#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
#include "flags.h"
#include "function.h"
#include "expr.h"
#include "optabs.h"
#include "libfuncs.h"
#include "recog.h"
#include "toplev.h"
#include "ggc.h"
#include "tm_p.h"
#include "debug.h"
#include "target.h"
#include "target-def.h"
#define SKIP_CALLERS_UNIMP_P \
(!TARGET_ARCH64 && current_function_returns_struct \
&& ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \
&& (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \
== INTEGER_CST))
static int apparent_fsize;
static int actual_fsize;
static int num_gfregs;
rtx sparc_compare_op0, sparc_compare_op1;
bool sparc_emitting_epilogue;
char leaf_reg_remap[] =
{ 0, 1, 2, 3, 4, 5, 6, 7,
-1, -1, -1, -1, -1, -1, 14, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
8, 9, 10, 11, 12, 13, -1, 15,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100};
char sparc_leaf_regs[] =
{ 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1};
static const char *frame_base_name;
static int frame_base_offset;
static void sparc_init_modes PARAMS ((void));
static int save_regs PARAMS ((FILE *, int, int, const char *,
int, int, int));
static int restore_regs PARAMS ((FILE *, int, int, const char *, int, int));
static void build_big_number PARAMS ((FILE *, int, const char *));
static int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *,
enum machine_mode, tree, int, int,
int *, int *));
static int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static void sparc_output_addr_vec PARAMS ((rtx));
static void sparc_output_addr_diff_vec PARAMS ((rtx));
static void sparc_output_deferred_case_vectors PARAMS ((void));
static int check_return_regs PARAMS ((rtx));
static int epilogue_renumber PARAMS ((rtx *, int));
static bool sparc_assemble_integer PARAMS ((rtx, unsigned int, int));
static int set_extends PARAMS ((rtx));
static void output_restore_regs PARAMS ((FILE *, int));
static void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void sparc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void sparc_flat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
static void sparc_flat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
static void sparc_nonflat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT,
int));
static void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT,
int));
#ifdef OBJECT_FORMAT_ELF
static void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int));
#endif
static void sparc_aout_select_section PARAMS ((tree, int,
unsigned HOST_WIDE_INT))
ATTRIBUTE_UNUSED;
static void sparc_aout_select_rtx_section PARAMS ((enum machine_mode, rtx,
unsigned HOST_WIDE_INT))
ATTRIBUTE_UNUSED;
static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int sparc_issue_rate PARAMS ((void));
static void sparc_sched_init PARAMS ((FILE *, int, int));
static int sparc_use_dfa_pipeline_interface PARAMS ((void));
static int sparc_use_sched_lookahead PARAMS ((void));
static void emit_soft_tfmode_libcall PARAMS ((const char *, int, rtx *));
static void emit_soft_tfmode_binop PARAMS ((enum rtx_code, rtx *));
static void emit_soft_tfmode_unop PARAMS ((enum rtx_code, rtx *));
static void emit_soft_tfmode_cvt PARAMS ((enum rtx_code, rtx *));
static void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *));
static void sparc_encode_section_info PARAMS ((tree, int));
static void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree));
const char *sparc_cmodel_string;
enum cmodel sparc_cmodel;
char sparc_hard_reg_printed[8];
struct sparc_cpu_select sparc_select[] =
{
{ (char *)0, "default", 1, 1 },
{ (char *)0, "-mcpu=", 1, 1 },
{ (char *)0, "-mtune=", 1, 0 },
{ 0, 0, 0, 0 }
};
enum processor_type sparc_cpu;
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
#ifndef OBJECT_FORMAT_ELF
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
#endif
#undef TARGET_ASM_UNALIGNED_HI_OP
#define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t"
#undef TARGET_ASM_UNALIGNED_SI_OP
#define TARGET_ASM_UNALIGNED_SI_OP "\t.uaword\t"
#undef TARGET_ASM_UNALIGNED_DI_OP
#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaxword\t"
#undef TARGET_ASM_INTEGER
#define TARGET_ASM_INTEGER sparc_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
#undef TARGET_SCHED_ISSUE_RATE
#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
#undef TARGET_SCHED_INIT
#define TARGET_SCHED_INIT sparc_sched_init
#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO sparc_encode_section_info
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
struct gcc_target targetm = TARGET_INITIALIZER;
void
sparc_override_options ()
{
static struct code_model {
const char *const name;
const int value;
} const cmodels[] = {
{ "32", CM_32 },
{ "medlow", CM_MEDLOW },
{ "medmid", CM_MEDMID },
{ "medany", CM_MEDANY },
{ "embmedany", CM_EMBMEDANY },
{ 0, 0 }
};
const struct code_model *cmodel;
static struct cpu_default {
const int cpu;
const char *const name;
} const cpu_default[] = {
{ TARGET_CPU_sparc, "cypress" },
{ TARGET_CPU_sparclet, "tsc701" },
{ TARGET_CPU_sparclite, "f930" },
{ TARGET_CPU_v8, "v8" },
{ TARGET_CPU_hypersparc, "hypersparc" },
{ TARGET_CPU_sparclite86x, "sparclite86x" },
{ TARGET_CPU_supersparc, "supersparc" },
{ TARGET_CPU_v9, "v9" },
{ TARGET_CPU_ultrasparc, "ultrasparc" },
{ TARGET_CPU_ultrasparc3, "ultrasparc3" },
{ 0, 0 }
};
const struct cpu_default *def;
static struct cpu_table {
const char *const name;
const enum processor_type processor;
const int disable;
const int enable;
} const cpu_table[] = {
{ "v7", PROCESSOR_V7, MASK_ISA, 0 },
{ "cypress", PROCESSOR_CYPRESS, MASK_ISA, 0 },
{ "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 },
{ "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 },
{ "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE },
{ "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE },
{ "f934", PROCESSOR_F934, MASK_ISA, MASK_SPARCLITE|MASK_FPU },
{ "hypersparc", PROCESSOR_HYPERSPARC, MASK_ISA, MASK_V8|MASK_FPU },
{ "sparclite86x", PROCESSOR_SPARCLITE86X, MASK_ISA|MASK_FPU,
MASK_SPARCLITE },
{ "sparclet", PROCESSOR_SPARCLET, MASK_ISA, MASK_SPARCLET },
{ "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET },
{ "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 },
{ "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9
|MASK_DEPRECATED_V8_INSNS},
{ "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
{ 0, 0, 0, 0 }
};
const struct cpu_table *cpu;
const struct sparc_cpu_select *sel;
int fpu;
#ifndef SPARC_BI_ARCH
if (! TARGET_64BIT != DEFAULT_ARCH32_P)
error ("%s is not supported by this configuration",
DEFAULT_ARCH32_P ? "-m64" : "-m32");
#endif
if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
{
error ("-mlong-double-64 not allowed with -m64");
target_flags |= MASK_LONG_DOUBLE_128;
}
sparc_cmodel = SPARC_DEFAULT_CMODEL;
#ifdef SPARC_BI_ARCH
if (TARGET_ARCH32)
sparc_cmodel = CM_32;
#endif
if (sparc_cmodel_string != NULL)
{
if (TARGET_ARCH64)
{
for (cmodel = &cmodels[0]; cmodel->name; cmodel++)
if (strcmp (sparc_cmodel_string, cmodel->name) == 0)
break;
if (cmodel->name == NULL)
error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string);
else
sparc_cmodel = cmodel->value;
}
else
error ("-mcmodel= is not supported on 32 bit systems");
}
fpu = TARGET_FPU;
for (def = &cpu_default[0]; def->name; ++def)
if (def->cpu == TARGET_CPU_DEFAULT)
break;
if (! def->name)
abort ();
sparc_select[0].string = def->name;
for (sel = &sparc_select[0]; sel->name; ++sel)
{
if (sel->string)
{
for (cpu = &cpu_table[0]; cpu->name; ++cpu)
if (! strcmp (sel->string, cpu->name))
{
if (sel->set_tune_p)
sparc_cpu = cpu->processor;
if (sel->set_arch_p)
{
target_flags &= ~cpu->disable;
target_flags |= cpu->enable;
}
break;
}
if (! cpu->name)
error ("bad value (%s) for %s switch", sel->string, sel->name);
}
}
if (TARGET_FPU_SET)
{
target_flags = (target_flags & ~MASK_FPU) | fpu;
target_flags &= ~MASK_FPU_SET;
}
if (! TARGET_FPU)
target_flags &= ~MASK_VIS;
if (TARGET_VIS || TARGET_ARCH64)
{
target_flags |= MASK_V9;
target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE);
}
if (TARGET_V9 && TARGET_ARCH32)
target_flags |= MASK_DEPRECATED_V8_INSNS;
if (! TARGET_V9 || TARGET_ARCH64)
target_flags &= ~MASK_V8PLUS;
if (TARGET_ARCH32)
target_flags &= ~MASK_STACK_BIAS;
if (align_functions == 0
&& (sparc_cpu == PROCESSOR_ULTRASPARC
|| sparc_cpu == PROCESSOR_ULTRASPARC3))
align_functions = 32;
if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN)
flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1);
if (!TARGET_ARCH64)
targetm.asm_out.unaligned_op.di = NULL;
sparc_init_modes ();
}
int
v9_regcmp_p (code)
enum rtx_code code;
{
return (code == EQ || code == NE || code == GE || code == LT
|| code == LE || code == GT);
}
int
reg_or_0_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
return 1;
if (op == const0_rtx)
return 1;
if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& CONST_DOUBLE_LOW (op) == 0)
return 1;
if (fp_zero_operand (op, mode))
return 1;
return 0;
}
int
const1_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return op == const1_rtx;
}
int
fp_zero_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
return 0;
return op == CONST0_RTX (mode);
}
int
fp_register_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (! register_operand (op, mode))
return 0;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op));
}
int
fp_sethi_p (op)
rtx op;
{
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (SPARC_SETHI_P (i))
return 1;
}
return 0;
}
int
fp_mov_p (op)
rtx op;
{
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (SPARC_SIMM13_P (i))
return 1;
}
return 0;
}
int
fp_high_losum_p (op)
rtx op;
{
if (GET_CODE (op) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r;
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
if (REAL_VALUES_EQUAL (r, dconst0) &&
! REAL_VALUE_MINUS_ZERO (r))
return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
if (! SPARC_SETHI_P (i)
&& ! SPARC_SIMM13_P (i))
return 1;
}
return 0;
}
int
intreg_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (register_operand (op, SImode)
|| (TARGET_ARCH64 && register_operand (op, DImode)));
}
int
fcc_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != REG)
return 0;
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return 0;
#if 0
if (reg_renumber == 0)
return REGNO (op) >= FIRST_PSEUDO_REGISTER;
return REGNO_OK_FOR_CCFP_P (REGNO (op));
#else
return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
#endif
}
int
fcc0_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != REG)
return 0;
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
return 0;
return REGNO (op) == SPARC_FCC_REG;
}
int
icc_or_fcc_reg_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
{
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (mode == VOIDmode
&& GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
return 0;
return 1;
}
return fcc_reg_operand (op, mode);
}
int
restore_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (GET_CODE (op) == REG && GET_MODE (op) == mode
&& (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
}
int
call_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != MEM)
abort ();
op = XEXP (op, 0);
return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
}
int
call_operand_address (op, mode)
rtx op;
enum machine_mode mode;
{
return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
}
int
symbolic_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
enum machine_mode omode = GET_MODE (op);
if (omode != mode && omode != VOIDmode && mode != VOIDmode)
return 0;
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
int
symbolic_memory_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) != MEM)
return 0;
op = XEXP (op, 0);
return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
|| GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
}
int
label_ref_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) != LABEL_REF)
return 0;
if (GET_MODE (op) != mode)
return 0;
return 1;
}
int
sp64_medium_pic_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST)
return 0;
op = XEXP (op, 0);
if (GET_CODE (op) != MINUS)
return 0;
if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
return 0;
if (GET_CODE (XEXP (op, 1)) != CONST)
return 0;
if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
return 0;
return 1;
}
int
data_segment_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case SYMBOL_REF :
return ! SYMBOL_REF_FLAG (op);
case PLUS :
case CONST :
return data_segment_operand (XEXP (op, 0), VOIDmode);
default :
return 0;
}
}
int
text_segment_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case LABEL_REF :
return 1;
case SYMBOL_REF :
return SYMBOL_REF_FLAG (op);
case PLUS :
case CONST :
return text_segment_operand (XEXP (op, 0), VOIDmode);
default :
return 0;
}
}
int
reg_or_nonsymb_mem_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
return 1;
if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
return 1;
return 0;
}
int
splittable_symbolic_memory_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != MEM)
return 0;
if (! symbolic_operand (XEXP (op, 0), Pmode))
return 0;
return 1;
}
int
splittable_immediate_memory_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != MEM)
return 0;
if (! immediate_operand (XEXP (op, 0), Pmode))
return 0;
return 1;
}
int
eq_or_neq (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
}
int
normal_comp_operator (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
if (GET_RTX_CLASS (code) != '<')
return 0;
if (GET_MODE (XEXP (op, 0)) == CCFPmode
|| GET_MODE (XEXP (op, 0)) == CCFPEmode)
return 1;
return (code != NE && code != EQ && code != GEU && code != LTU);
}
int
noov_compare_op (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
if (GET_RTX_CLASS (code) != '<')
return 0;
if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
|| GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
return (code == EQ || code == NE || code == GE || code == LT);
return 1;
}
int
noov_compare64_op (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
if (! TARGET_V9)
return 0;
if (GET_RTX_CLASS (code) != '<')
return 0;
if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
return (code == EQ || code == NE || code == GE || code == LT);
return (GET_MODE (XEXP (op, 0)) == CCXmode);
}
int
v9_regcmp_op (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
enum rtx_code code = GET_CODE (op);
if (GET_RTX_CLASS (code) != '<')
return 0;
return v9_regcmp_p (code);
}
int
extend_op (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
}
int
cc_arithop (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == AND
|| GET_CODE (op) == IOR
|| GET_CODE (op) == XOR)
return 1;
return 0;
}
int
cc_arithopn (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == AND
|| GET_CODE (op) == IOR);
}
int
arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (register_operand (op, mode))
return 1;
if (GET_CODE (op) != CONST_INT)
return 0;
return SMALL_INT32 (op);
}
int
arith_4096_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) != CONST_INT)
return 0;
else
return INTVAL (op) == 4096;
}
int
arith_add_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return arith_operand (op, mode) || arith_4096_operand (op, mode);
}
int
const64_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return ((GET_CODE (op) == CONST_INT
&& SPARC_SIMM13_P (INTVAL (op)))
#if HOST_BITS_PER_WIDE_INT != 64
|| (GET_CODE (op) == CONST_DOUBLE
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
&& (CONST_DOUBLE_HIGH (op) ==
((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ?
(HOST_WIDE_INT)-1 : 0)))
#endif
);
}
int
const64_high_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return ((GET_CODE (op) == CONST_INT
&& (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
&& SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
)
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0
&& SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));
}
int
arith11_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
}
int
arith10_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
}
int
arith_double_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_INT && SMALL_INT (op))
|| (! TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
|| (TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
}
int
arith_double_4096_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (TARGET_ARCH64 &&
((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
(GET_CODE (op) == CONST_DOUBLE &&
CONST_DOUBLE_LOW (op) == 4096 &&
CONST_DOUBLE_HIGH (op) == 0)));
}
int
arith_double_add_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
}
int
arith11_double_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
|| (GET_CODE (op) == CONST_INT
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
}
int
arith10_double_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return (register_operand (op, mode)
|| (GET_CODE (op) == CONST_DOUBLE
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
&& ((CONST_DOUBLE_HIGH (op) == -1
&& (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
|| (CONST_DOUBLE_HIGH (op) == 0
&& (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
|| (GET_CODE (op) == CONST_INT
&& (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
&& (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
}
int
small_int (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
}
int
small_int_or_double (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));
}
int
uns_small_int (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
#if HOST_BITS_PER_WIDE_INT > 32
return (GET_CODE (op) == CONST_INT
&& ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
|| (INTVAL (op) >= 0xFFFFF000
&& INTVAL (op) <= 0xFFFFFFFF)));
#else
return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
|| (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (op) == 0
&& (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
#endif
}
int
uns_arith_operand (op, mode)
rtx op;
enum machine_mode mode;
{
return register_operand (op, mode) || uns_small_int (op, mode);
}
int
clobbered_register (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
}
int
input_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_CODE (op) == CONST && GET_CODE (XEXP (op, 0)) == CONSTANT_P_RTX)
return 1;
if (GET_MODE_CLASS (mode) == MODE_INT
&& ((GET_CODE (op) == CONST_INT
&& (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
|| SPARC_SIMM13_P (INTVAL (op))
|| (mode == DImode
&& ! TARGET_ARCH64)))
|| (TARGET_ARCH64
&& GET_CODE (op) == CONST_DOUBLE
&& ((CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))
||
#if HOST_BITS_PER_WIDE_INT == 64
(CONST_DOUBLE_HIGH (op) == 0
&& SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))
#else
(SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
&& (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
&& CONST_DOUBLE_HIGH (op) == 0)
|| (CONST_DOUBLE_HIGH (op) == -1
&& CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
#endif
))))
return 1;
if (! TARGET_ARCH64
&& mode == DImode
&& GET_CODE (op) == CONST_DOUBLE)
return 1;
if (register_operand (op, mode))
return 1;
if (GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_CODE (op) == CONST_DOUBLE)
return 1;
if (GET_CODE (op) == SUBREG)
op = SUBREG_REG (op);
if (GET_CODE (op) == MEM)
{
rtx inside = XEXP (op, 0);
if (GET_CODE (inside) == LO_SUM)
{
if (! TARGET_V9
&& GET_MODE (op) == TFmode)
return 0;
return (register_operand (XEXP (inside, 0), Pmode)
&& CONSTANT_P (XEXP (inside, 1)));
}
return memory_address_p (mode, inside);
}
return 0;
}
void
sparc_emit_set_const32 (op0, op1)
rtx op0;
rtx op1;
{
enum machine_mode mode = GET_MODE (op0);
rtx temp;
if (GET_CODE (op1) == CONST_INT)
{
HOST_WIDE_INT value = INTVAL (op1);
if (SPARC_SETHI_P (value & GET_MODE_MASK (mode))
|| SPARC_SIMM13_P (value))
abort ();
}
if (reload_in_progress || reload_completed)
temp = op0;
else
temp = gen_reg_rtx (mode);
if (GET_CODE (op1) == CONST_INT)
{
if (TARGET_ARCH64
&& HOST_BITS_PER_WIDE_INT != 64
&& (INTVAL (op1) & 0x80000000) != 0)
emit_insn (gen_rtx_SET
(VOIDmode, temp,
immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff,
0, DImode)));
else
emit_insn (gen_rtx_SET (VOIDmode, temp,
GEN_INT (INTVAL (op1)
& ~(HOST_WIDE_INT)0x3ff)));
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_rtx_IOR (mode, temp,
GEN_INT (INTVAL (op1) & 0x3ff))));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, temp,
gen_rtx_HIGH (mode, op1)));
emit_insn (gen_rtx_SET (VOIDmode,
op0, gen_rtx_LO_SUM (mode, temp, op1)));
}
}
void
sparc_emit_set_symbolic_const64 (op0, op1, temp1)
rtx op0;
rtx op1;
rtx temp1;
{
rtx ti_temp1 = 0;
if (temp1 && GET_MODE (temp1) == TImode)
{
ti_temp1 = temp1;
temp1 = gen_rtx_REG (DImode, REGNO (temp1));
}
switch (sparc_cmodel)
{
case CM_MEDLOW:
emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1)));
emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1)));
break;
case CM_MEDMID:
emit_insn (gen_seth44 (op0, op1));
emit_insn (gen_setm44 (op0, op0, op1));
emit_insn (gen_rtx_SET (VOIDmode, temp1,
gen_rtx_ASHIFT (DImode, op0, GEN_INT (12))));
emit_insn (gen_setl44 (op0, temp1, op1));
break;
case CM_MEDANY:
if (rtx_equal_p (temp1, op0))
{
if (ti_temp1)
temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
else
abort();
}
emit_insn (gen_sethh (op0, op1));
emit_insn (gen_setlm (temp1, op1));
emit_insn (gen_sethm (op0, op0, op1));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_PLUS (DImode, op0, temp1)));
emit_insn (gen_setlo (op0, op0, op1));
break;
case CM_EMBMEDANY:
if (data_segment_operand (op1, GET_MODE (op1)))
{
emit_insn (gen_embmedany_sethi (temp1, op1));
emit_insn (gen_embmedany_brsum (op0, temp1));
emit_insn (gen_embmedany_losum (op0, op0, op1));
}
else
{
if (rtx_equal_p (temp1, op0))
{
if (ti_temp1)
temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
else
abort();
}
emit_insn (gen_embmedany_textuhi (op0, op1));
emit_insn (gen_embmedany_texthi (temp1, op1));
emit_insn (gen_embmedany_textulo (op0, op0, op1));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_PLUS (DImode, op0, temp1)));
emit_insn (gen_embmedany_textlo (op0, op0, op1));
}
break;
default:
abort();
}
}
static void sparc_emit_set_safe_HIGH64 PARAMS ((rtx, HOST_WIDE_INT));
static rtx gen_safe_SET64 PARAMS ((rtx, HOST_WIDE_INT));
static rtx gen_safe_OR64 PARAMS ((rtx, HOST_WIDE_INT));
static rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT));
#if HOST_BITS_PER_WIDE_INT == 64
#define GEN_HIGHINT64(__x) GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff)
#define GEN_INT64(__x) GEN_INT (__x)
#else
#define GEN_HIGHINT64(__x) \
immed_double_const ((__x) & ~(HOST_WIDE_INT)0x3ff, 0, DImode)
#define GEN_INT64(__x) \
immed_double_const ((__x) & 0xffffffff, \
((__x) & 0x80000000 ? -1 : 0), DImode)
#endif
static void
sparc_emit_set_safe_HIGH64 (dest, val)
rtx dest;
HOST_WIDE_INT val;
{
emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val)));
}
static rtx
gen_safe_SET64 (dest, val)
rtx dest;
HOST_WIDE_INT val;
{
return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
}
static rtx
gen_safe_OR64 (src, val)
rtx src;
HOST_WIDE_INT val;
{
return gen_rtx_IOR (DImode, src, GEN_INT64 (val));
}
static rtx
gen_safe_XOR64 (src, val)
rtx src;
HOST_WIDE_INT val;
{
return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
}
static void sparc_emit_set_const64_quick1
PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, int));
static void
sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg)
rtx op0;
rtx temp;
unsigned HOST_WIDE_INT low_bits;
int is_neg;
{
unsigned HOST_WIDE_INT high_bits;
if (is_neg)
high_bits = (~low_bits) & 0xffffffff;
else
high_bits = low_bits;
sparc_emit_set_safe_HIGH64 (temp, high_bits);
if (!is_neg)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
}
else
{
if ((low_bits & 0x3ff) == 0x3ff)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_NOT (DImode, temp)));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_safe_XOR64 (temp,
(-(HOST_WIDE_INT)0x400
| (low_bits & 0x3ff)))));
}
}
}
static void sparc_emit_set_const64_quick2
PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT, int));
static void
sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count)
rtx op0;
rtx temp;
unsigned HOST_WIDE_INT high_bits;
unsigned HOST_WIDE_INT low_immediate;
int shift_count;
{
rtx temp2 = op0;
if ((high_bits & 0xfffffc00) != 0)
{
sparc_emit_set_safe_HIGH64 (temp, high_bits);
if ((high_bits & ~0xfffffc00) != 0)
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
else
temp2 = temp;
}
else
{
emit_insn (gen_safe_SET64 (temp, high_bits));
temp2 = temp;
}
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, temp2,
GEN_INT (shift_count))));
if (low_immediate != 0)
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_safe_OR64 (op0, low_immediate)));
}
static void sparc_emit_set_const64_longway
PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
static void
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits)
rtx op0;
rtx temp;
unsigned HOST_WIDE_INT high_bits;
unsigned HOST_WIDE_INT low_bits;
{
rtx sub_temp;
if (reload_in_progress || reload_completed)
sub_temp = op0;
else
sub_temp = gen_reg_rtx (DImode);
if ((high_bits & 0xfffffc00) != 0)
{
sparc_emit_set_safe_HIGH64 (temp, high_bits);
if ((high_bits & ~0xfffffc00) != 0)
emit_insn (gen_rtx_SET (VOIDmode,
sub_temp,
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
else
sub_temp = temp;
}
else
{
emit_insn (gen_safe_SET64 (temp, high_bits));
sub_temp = temp;
}
if (!reload_in_progress && !reload_completed)
{
rtx temp2 = gen_reg_rtx (DImode);
rtx temp3 = gen_reg_rtx (DImode);
rtx temp4 = gen_reg_rtx (DImode);
emit_insn (gen_rtx_SET (VOIDmode, temp4,
gen_rtx_ASHIFT (DImode, sub_temp,
GEN_INT (32))));
sparc_emit_set_safe_HIGH64 (temp2, low_bits);
if ((low_bits & ~0xfffffc00) != 0)
{
emit_insn (gen_rtx_SET (VOIDmode, temp3,
gen_safe_OR64 (temp2, (low_bits & 0x3ff))));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_PLUS (DImode, temp4, temp3)));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_PLUS (DImode, temp4, temp2)));
}
}
else
{
rtx low1 = GEN_INT ((low_bits >> (32 - 12)) & 0xfff);
rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12)) & 0xfff);
rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff);
int to_shift = 12;
if (low1 != const0_rtx)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, sub_temp,
GEN_INT (to_shift))));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_IOR (DImode, op0, low1)));
sub_temp = op0;
to_shift = 12;
}
else
{
to_shift += 12;
}
if (low2 != const0_rtx)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, sub_temp,
GEN_INT (to_shift))));
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_IOR (DImode, op0, low2)));
sub_temp = op0;
to_shift = 8;
}
else
{
to_shift += 8;
}
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_ASHIFT (DImode, sub_temp,
GEN_INT (to_shift))));
if (low3 != const0_rtx)
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_IOR (DImode, op0, low3)));
}
}
static void analyze_64bit_constant
PARAMS ((unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
int *, int *, int *));
static void
analyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp)
unsigned HOST_WIDE_INT high_bits, low_bits;
int *hbsp, *lbsp, *abbasp;
{
int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
int i;
lowest_bit_set = highest_bit_set = -1;
i = 0;
do
{
if ((lowest_bit_set == -1)
&& ((low_bits >> i) & 1))
lowest_bit_set = i;
if ((highest_bit_set == -1)
&& ((high_bits >> (32 - i - 1)) & 1))
highest_bit_set = (64 - i - 1);
}
while (++i < 32
&& ((highest_bit_set == -1)
|| (lowest_bit_set == -1)));
if (i == 32)
{
i = 0;
do
{
if ((lowest_bit_set == -1)
&& ((high_bits >> i) & 1))
lowest_bit_set = i + 32;
if ((highest_bit_set == -1)
&& ((low_bits >> (32 - i - 1)) & 1))
highest_bit_set = 32 - i - 1;
}
while (++i < 32
&& ((highest_bit_set == -1)
|| (lowest_bit_set == -1)));
}
if (lowest_bit_set == -1
|| highest_bit_set == -1)
abort ();
all_bits_between_are_set = 1;
for (i = lowest_bit_set; i <= highest_bit_set; i++)
{
if (i < 32)
{
if ((low_bits & (1 << i)) != 0)
continue;
}
else
{
if ((high_bits & (1 << (i - 32))) != 0)
continue;
}
all_bits_between_are_set = 0;
break;
}
*hbsp = highest_bit_set;
*lbsp = lowest_bit_set;
*abbasp = all_bits_between_are_set;
}
static int const64_is_2insns
PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
static int
const64_is_2insns (high_bits, low_bits)
unsigned HOST_WIDE_INT high_bits, low_bits;
{
int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
if (high_bits == 0
|| high_bits == 0xffffffff)
return 1;
analyze_64bit_constant (high_bits, low_bits,
&highest_bit_set, &lowest_bit_set,
&all_bits_between_are_set);
if ((highest_bit_set == 63
|| lowest_bit_set == 0)
&& all_bits_between_are_set != 0)
return 1;
if ((highest_bit_set - lowest_bit_set) < 21)
return 1;
return 0;
}
static unsigned HOST_WIDE_INT create_simple_focus_bits
PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
int, int));
static unsigned HOST_WIDE_INT
create_simple_focus_bits (high_bits, low_bits, lowest_bit_set, shift)
unsigned HOST_WIDE_INT high_bits, low_bits;
int lowest_bit_set, shift;
{
HOST_WIDE_INT hi, lo;
if (lowest_bit_set < 32)
{
lo = (low_bits >> lowest_bit_set) << shift;
hi = ((high_bits << (32 - lowest_bit_set)) << shift);
}
else
{
lo = 0;
hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
}
if (hi & lo)
abort ();
return (hi | lo);
}
void
sparc_emit_set_const64 (op0, op1)
rtx op0;
rtx op1;
{
unsigned HOST_WIDE_INT high_bits, low_bits;
int lowest_bit_set, highest_bit_set;
int all_bits_between_are_set;
rtx temp;
if (! TARGET_ARCH64)
abort ();
if (GET_CODE (op0) != SUBREG)
{
if (GET_CODE (op0) != REG
|| (REGNO (op0) >= SPARC_FIRST_FP_REG
&& REGNO (op0) <= SPARC_LAST_V9_FP_REG))
abort ();
}
if (reload_in_progress || reload_completed)
temp = op0;
else
temp = gen_reg_rtx (DImode);
if (GET_CODE (op1) != CONST_DOUBLE
&& GET_CODE (op1) != CONST_INT)
{
sparc_emit_set_symbolic_const64 (op0, op1, temp);
return;
}
if (GET_CODE (op1) == CONST_DOUBLE)
{
#if HOST_BITS_PER_WIDE_INT == 64
high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff;
low_bits = CONST_DOUBLE_LOW (op1) & 0xffffffff;
#else
high_bits = CONST_DOUBLE_HIGH (op1);
low_bits = CONST_DOUBLE_LOW (op1);
#endif
}
else
{
#if HOST_BITS_PER_WIDE_INT == 64
high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
low_bits = (INTVAL (op1) & 0xffffffff);
#else
high_bits = ((INTVAL (op1) < 0) ?
0xffffffff :
0x00000000);
low_bits = INTVAL (op1);
#endif
}
analyze_64bit_constant (high_bits, low_bits,
&highest_bit_set, &lowest_bit_set,
&all_bits_between_are_set);
if (((highest_bit_set == 63
|| lowest_bit_set == 0)
&& all_bits_between_are_set != 0)
|| ((highest_bit_set - lowest_bit_set) < 12))
{
HOST_WIDE_INT the_const = -1;
int shift = lowest_bit_set;
if ((highest_bit_set != 63
&& lowest_bit_set != 0)
|| all_bits_between_are_set == 0)
{
the_const =
create_simple_focus_bits (high_bits, low_bits,
lowest_bit_set, 0);
}
else if (lowest_bit_set == 0)
shift = -(63 - highest_bit_set);
if (! SPARC_SIMM13_P (the_const))
abort ();
emit_insn (gen_safe_SET64 (temp, the_const));
if (shift > 0)
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_rtx_ASHIFT (DImode,
temp,
GEN_INT (shift))));
else if (shift < 0)
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_rtx_LSHIFTRT (DImode,
temp,
GEN_INT (-shift))));
else
abort ();
return;
}
if ((highest_bit_set - lowest_bit_set) < 21)
{
unsigned HOST_WIDE_INT focus_bits =
create_simple_focus_bits (high_bits, low_bits,
lowest_bit_set, 10);
if (! SPARC_SETHI_P (focus_bits))
abort ();
sparc_emit_set_safe_HIGH64 (temp, focus_bits);
if (lowest_bit_set < 10)
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_rtx_LSHIFTRT (DImode, temp,
GEN_INT (10 - lowest_bit_set))));
else if (lowest_bit_set > 10)
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_rtx_ASHIFT (DImode, temp,
GEN_INT (lowest_bit_set - 10))));
else
abort ();
return;
}
if (high_bits == 0
|| high_bits == 0xffffffff)
{
sparc_emit_set_const64_quick1 (op0, temp, low_bits,
(high_bits == 0xffffffff));
return;
}
if (low_bits == 0)
{
sparc_emit_set_const64_quick2 (op0, temp, high_bits, 0, 32);
return;
}
if (const64_is_2insns ((~high_bits) & 0xffffffff,
(~low_bits) & 0xfffffc00))
{
unsigned HOST_WIDE_INT trailing_bits = low_bits & 0x3ff;
if ((((~high_bits) & 0xffffffff) == 0
&& ((~low_bits) & 0x80000000) == 0)
|| (((~high_bits) & 0xffffffff) == 0xffffffff
&& ((~low_bits) & 0x80000000) != 0))
{
int fast_int = (~low_bits & 0xffffffff);
if ((SPARC_SETHI_P (fast_int)
&& (~high_bits & 0xffffffff) == 0)
|| SPARC_SIMM13_P (fast_int))
emit_insn (gen_safe_SET64 (temp, fast_int));
else
sparc_emit_set_const64 (temp, GEN_INT64 (fast_int));
}
else
{
rtx negated_const;
#if HOST_BITS_PER_WIDE_INT == 64
negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
(((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
#else
negated_const = immed_double_const ((~low_bits) & 0xfffffc00,
(~high_bits) & 0xffffffff,
DImode);
#endif
sparc_emit_set_const64 (temp, negated_const);
}
if (trailing_bits == 0x3ff)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_rtx_NOT (DImode, temp)));
}
else
{
emit_insn (gen_rtx_SET (VOIDmode,
op0,
gen_safe_XOR64 (temp,
(-0x400 | trailing_bits))));
}
return;
}
if ((highest_bit_set - lowest_bit_set) < 32)
{
unsigned HOST_WIDE_INT focus_bits =
create_simple_focus_bits (high_bits, low_bits,
lowest_bit_set, 0);
if (highest_bit_set < 32
|| lowest_bit_set >= 32)
abort ();
sparc_emit_set_const64_quick2 (op0, temp,
focus_bits, 0,
lowest_bit_set);
return;
}
if (SPARC_SIMM13_P(low_bits)
&& ((int)low_bits > 0))
{
sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32);
return;
}
#if 0
printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n",
high_bits, low_bits, ~high_bits, ~low_bits);
#endif
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
}
enum machine_mode
select_cc_mode (op, x, y)
enum rtx_code op;
rtx x;
rtx y ATTRIBUTE_UNUSED;
{
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
{
switch (op)
{
case EQ:
case NE:
case UNORDERED:
case ORDERED:
case UNLT:
case UNLE:
case UNGT:
case UNGE:
case UNEQ:
case LTGT:
return CCFPmode;
case LT:
case LE:
case GT:
case GE:
return CCFPEmode;
default:
abort ();
}
}
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
|| GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
{
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCX_NOOVmode;
else
return CC_NOOVmode;
}
else
{
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
return CCXmode;
else
return CCmode;
}
}
rtx
gen_compare_reg (code, x, y)
enum rtx_code code;
rtx x, y;
{
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
rtx cc_reg;
if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
#if 1
{
int reg;
static int next_fcc_reg = 0;
static rtx prev_args[4][2];
for (reg = 0; reg < 4; reg++)
if (prev_args[reg][0] == x && prev_args[reg][1] == y)
break;
if (reg == 4)
{
reg = next_fcc_reg;
prev_args[reg][0] = x;
prev_args[reg][1] = y;
next_fcc_reg = (next_fcc_reg + 1) & 3;
}
cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG);
}
#else
cc_reg = gen_reg_rtx (mode);
#endif
else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG);
else
cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
gen_rtx_COMPARE (mode, x, y)));
return cc_reg;
}
int
gen_v9_scc (compare_code, operands)
enum rtx_code compare_code;
register rtx *operands;
{
rtx temp, op0, op1;
if (! TARGET_ARCH64
&& (GET_MODE (sparc_compare_op0) == DImode
|| GET_MODE (operands[0]) == DImode))
return 0;
op0 = sparc_compare_op0;
op1 = sparc_compare_op1;
if (TARGET_ARCH64
&& GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
&& op1 == const0_rtx
&& v9_regcmp_p (compare_code))
{
if (compare_code == NE
&& GET_MODE (operands[0]) == DImode
&& rtx_equal_p (op0, operands[0]))
{
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (DImode,
gen_rtx_fmt_ee (compare_code, DImode,
op0, const0_rtx),
const1_rtx,
operands[0])));
return 1;
}
if (reg_overlap_mentioned_p (operands[0], op0))
{
op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0));
emit_move_insn (op0, sparc_compare_op0);
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
if (GET_MODE (op0) != DImode)
{
temp = gen_reg_rtx (DImode);
convert_move (temp, op0, 0);
}
else
temp = op0;
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
gen_rtx_fmt_ee (compare_code, DImode,
temp, const0_rtx),
const1_rtx,
operands[0])));
return 1;
}
else
{
operands[1] = gen_compare_reg (compare_code, op0, op1);
switch (GET_MODE (operands[1]))
{
case CCmode :
case CCXmode :
case CCFPEmode :
case CCFPmode :
break;
default :
abort ();
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
gen_rtx_fmt_ee (compare_code,
GET_MODE (operands[1]),
operands[1], const0_rtx),
const1_rtx, operands[0])));
return 1;
}
}
void
emit_v9_brxx_insn (code, op0, label)
enum rtx_code code;
rtx op0, label;
{
emit_jump_insn (gen_rtx_SET (VOIDmode,
pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode,
gen_rtx_fmt_ee (code, GET_MODE (op0),
op0, const0_rtx),
gen_rtx_LABEL_REF (VOIDmode, label),
pc_rtx)));
}
rtx
gen_df_reg (reg, low)
rtx reg;
int low;
{
int regno = REGNO (reg);
if ((WORDS_BIG_ENDIAN == 0) ^ (low != 0))
regno += (TARGET_ARCH64 && regno < 32) ? 1 : 2;
return gen_rtx_REG (DFmode, regno);
}
static void
emit_soft_tfmode_libcall (func_name, nargs, operands)
const char *func_name;
int nargs;
rtx *operands;
{
rtx ret_slot = NULL, arg[3], func_sym;
int i;
if (nargs < 2 || nargs > 3)
abort ();
for (i = 0; i < nargs; ++i)
{
rtx this_arg = operands[i];
rtx this_slot;
if (GET_MODE (this_arg) == TFmode)
{
int force_stack_temp;
force_stack_temp = 0;
if (TARGET_BUGGY_QP_LIB && i == 0)
force_stack_temp = 1;
if (GET_CODE (this_arg) == MEM
&& ! force_stack_temp)
this_arg = XEXP (this_arg, 0);
else if (CONSTANT_P (this_arg)
&& ! force_stack_temp)
{
this_slot = force_const_mem (TFmode, this_arg);
this_arg = XEXP (this_slot, 0);
}
else
{
this_slot = assign_stack_temp (TFmode, GET_MODE_SIZE (TFmode), 0);
if (i > 0)
emit_move_insn (this_slot, this_arg);
else
ret_slot = this_slot;
this_arg = XEXP (this_slot, 0);
}
}
arg[i] = this_arg;
}
func_sym = gen_rtx_SYMBOL_REF (Pmode, func_name);
if (GET_MODE (operands[0]) == TFmode)
{
if (nargs == 2)
emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2,
arg[0], GET_MODE (arg[0]),
arg[1], GET_MODE (arg[1]));
else
emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3,
arg[0], GET_MODE (arg[0]),
arg[1], GET_MODE (arg[1]),
arg[2], GET_MODE (arg[2]));
if (ret_slot)
emit_move_insn (operands[0], ret_slot);
}
else
{
rtx ret;
if (nargs != 2)
abort ();
ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
GET_MODE (operands[0]), 1,
arg[1], GET_MODE (arg[1]));
if (ret != operands[0])
emit_move_insn (operands[0], ret);
}
}
static void
emit_soft_tfmode_binop (code, operands)
enum rtx_code code;
rtx *operands;
{
const char *func;
switch (code)
{
case PLUS:
func = "_Qp_add";
break;
case MINUS:
func = "_Qp_sub";
break;
case MULT:
func = "_Qp_mul";
break;
case DIV:
func = "_Qp_div";
break;
default:
abort ();
}
emit_soft_tfmode_libcall (func, 3, operands);
}
static void
emit_soft_tfmode_unop (code, operands)
enum rtx_code code;
rtx *operands;
{
const char *func;
switch (code)
{
case SQRT:
func = "_Qp_sqrt";
break;
default:
abort ();
}
emit_soft_tfmode_libcall (func, 2, operands);
}
static void
emit_soft_tfmode_cvt (code, operands)
enum rtx_code code;
rtx *operands;
{
const char *func;
switch (code)
{
case FLOAT_EXTEND:
switch (GET_MODE (operands[1]))
{
case SFmode:
func = "_Qp_stoq";
break;
case DFmode:
func = "_Qp_dtoq";
break;
default:
abort ();
}
break;
case FLOAT_TRUNCATE:
switch (GET_MODE (operands[0]))
{
case SFmode:
func = "_Qp_qtos";
break;
case DFmode:
func = "_Qp_qtod";
break;
default:
abort ();
}
break;
case FLOAT:
switch (GET_MODE (operands[1]))
{
case SImode:
func = "_Qp_itoq";
break;
case DImode:
func = "_Qp_xtoq";
break;
default:
abort ();
}
break;
case UNSIGNED_FLOAT:
switch (GET_MODE (operands[1]))
{
case SImode:
func = "_Qp_uitoq";
break;
case DImode:
func = "_Qp_uxtoq";
break;
default:
abort ();
}
break;
case FIX:
switch (GET_MODE (operands[0]))
{
case SImode:
func = "_Qp_qtoi";
break;
case DImode:
func = "_Qp_qtox";
break;
default:
abort ();
}
break;
case UNSIGNED_FIX:
switch (GET_MODE (operands[0]))
{
case SImode:
func = "_Qp_qtoui";
break;
case DImode:
func = "_Qp_qtoux";
break;
default:
abort ();
}
break;
default:
abort ();
}
emit_soft_tfmode_libcall (func, 2, operands);
}
static void
emit_hard_tfmode_operation (code, operands)
enum rtx_code code;
rtx *operands;
{
rtx op, dest;
if (GET_RTX_CLASS (code) == '1')
{
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]);
}
else
{
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
op = gen_rtx_fmt_ee (code, GET_MODE (operands[0]),
operands[1], operands[2]);
}
if (register_operand (operands[0], VOIDmode))
dest = operands[0];
else
dest = gen_reg_rtx (GET_MODE (operands[0]));
emit_insn (gen_rtx_SET (VOIDmode, dest, op));
if (dest != operands[0])
emit_move_insn (operands[0], dest);
}
void
emit_tfmode_binop (code, operands)
enum rtx_code code;
rtx *operands;
{
if (TARGET_HARD_QUAD)
emit_hard_tfmode_operation (code, operands);
else
emit_soft_tfmode_binop (code, operands);
}
void
emit_tfmode_unop (code, operands)
enum rtx_code code;
rtx *operands;
{
if (TARGET_HARD_QUAD)
emit_hard_tfmode_operation (code, operands);
else
emit_soft_tfmode_unop (code, operands);
}
void
emit_tfmode_cvt (code, operands)
enum rtx_code code;
rtx *operands;
{
if (TARGET_HARD_QUAD)
emit_hard_tfmode_operation (code, operands);
else
emit_soft_tfmode_cvt (code, operands);
}
int
leaf_return_peephole_ok ()
{
return (actual_fsize == 0);
}
int
empty_delay_slot (insn)
rtx insn;
{
rtx seq;
if (PREV_INSN (insn) == NULL)
return 1;
seq = NEXT_INSN (PREV_INSN (insn));
if (GET_CODE (PATTERN (seq)) == SEQUENCE)
return 0;
return 1;
}
int
eligible_for_epilogue_delay (trial, slot)
rtx trial;
int slot;
{
rtx pat, src;
if (slot >= 1)
return 0;
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
return 0;
if (get_attr_length (trial) != 1)
return 0;
if (num_gfregs)
return 0;
if (current_function_calls_eh_return)
return 0;
if (current_function_uses_only_leaf_regs)
{
if (leaf_return_peephole_ok ())
return ((get_attr_in_uncond_branch_delay (trial)
== IN_BRANCH_DELAY_TRUE));
return 0;
}
pat = PATTERN (trial);
if (GET_CODE (SET_DEST (pat)) != REG
|| REGNO (SET_DEST (pat)) < 24)
return 0;
if (REGNO (SET_DEST (pat)) >= 32)
{
if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
return 1;
return 0;
}
src = SET_SRC (pat);
if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_operand (src, GET_MODE (src)))
{
if (TARGET_ARCH64)
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
else
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
}
else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_double_operand (src, GET_MODE (src)))
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
&& register_operand (src, SFmode))
return 1;
else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
&& (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
return 1;
else if (GET_CODE (src) == PLUS
&& arith_operand (XEXP (src, 0), SImode)
&& arith_operand (XEXP (src, 1), SImode)
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 1), SImode)))
return 1;
else if (GET_CODE (src) == PLUS
&& arith_double_operand (XEXP (src, 0), DImode)
&& arith_double_operand (XEXP (src, 1), DImode)
&& (register_operand (XEXP (src, 0), DImode)
|| register_operand (XEXP (src, 1), DImode)))
return 1;
else if (GET_CODE (src) == LO_SUM
&& ! TARGET_CM_MEDMID
&& ((register_operand (XEXP (src, 0), SImode)
&& immediate_operand (XEXP (src, 1), SImode))
|| (TARGET_ARCH64
&& register_operand (XEXP (src, 0), DImode)
&& immediate_operand (XEXP (src, 1), DImode))))
return 1;
else if (GET_CODE (src) == ASHIFT
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 0), DImode))
&& XEXP (src, 1) == const1_rtx)
return 1;
return 0;
}
int
eligible_for_sibcall_delay (trial)
rtx trial;
{
rtx pat, src;
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
return 0;
if (get_attr_length (trial) != 1)
return 0;
pat = PATTERN (trial);
if (current_function_uses_only_leaf_regs)
{
if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
return 0;
if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat))
return 0;
return 1;
}
if (GET_CODE (SET_DEST (pat)) != REG
|| REGNO (SET_DEST (pat)) < 24
|| REGNO (SET_DEST (pat)) >= 32)
return 0;
if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
return 0;
src = SET_SRC (pat);
if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_operand (src, GET_MODE (src)))
{
if (TARGET_ARCH64)
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
else
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
}
else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_double_operand (src, GET_MODE (src)))
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
&& register_operand (src, SFmode))
return 1;
else if (GET_CODE (src) == PLUS
&& arith_operand (XEXP (src, 0), SImode)
&& arith_operand (XEXP (src, 1), SImode)
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 1), SImode)))
return 1;
else if (GET_CODE (src) == PLUS
&& arith_double_operand (XEXP (src, 0), DImode)
&& arith_double_operand (XEXP (src, 1), DImode)
&& (register_operand (XEXP (src, 0), DImode)
|| register_operand (XEXP (src, 1), DImode)))
return 1;
else if (GET_CODE (src) == LO_SUM
&& ! TARGET_CM_MEDMID
&& ((register_operand (XEXP (src, 0), SImode)
&& immediate_operand (XEXP (src, 1), SImode))
|| (TARGET_ARCH64
&& register_operand (XEXP (src, 0), DImode)
&& immediate_operand (XEXP (src, 1), DImode))))
return 1;
else if (GET_CODE (src) == ASHIFT
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 0), DImode))
&& XEXP (src, 1) == const1_rtx)
return 1;
return 0;
}
static int
check_return_regs (x)
rtx x;
{
switch (GET_CODE (x))
{
case REG:
return IN_OR_GLOBAL_P (x);
case CONST_INT:
case CONST_DOUBLE:
case CONST:
case SYMBOL_REF:
case LABEL_REF:
return 1;
case SET:
case IOR:
case AND:
case XOR:
case PLUS:
case MINUS:
if (check_return_regs (XEXP (x, 1)) == 0)
return 0;
case NOT:
case NEG:
case MEM:
return check_return_regs (XEXP (x, 0));
default:
return 0;
}
}
int
short_branch (uid1, uid2)
int uid1, uid2;
{
int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
if (delta >= -1023 && delta <= 1022)
return 1;
return 0;
}
int
reg_unused_after (reg, insn)
rtx reg;
rtx insn;
{
enum rtx_code code, prev_code = UNKNOWN;
while ((insn = NEXT_INSN (insn)))
{
if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
return 1;
code = GET_CODE (insn);
if (GET_CODE (insn) == CODE_LABEL)
return 1;
if (GET_RTX_CLASS (code) == 'i')
{
rtx set = single_set (insn);
int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
if (set && in_src)
return 0;
if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
return 1;
if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
return 0;
}
prev_code = code;
}
return 1;
}
static GTY(()) rtx global_offset_table;
static GTY(()) rtx get_pc_symbol;
static char get_pc_symbol_name[256];
int
check_pic (i)
int i;
{
switch (flag_pic)
{
case 1:
if (GET_CODE (recog_data.operand[i]) == SYMBOL_REF
|| (GET_CODE (recog_data.operand[i]) == CONST
&& ! (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
&& (XEXP (XEXP (recog_data.operand[i], 0), 0)
== global_offset_table)
&& (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
== CONST))))
abort ();
case 2:
default:
return 1;
}
}
int
pic_address_needs_scratch (x)
rtx x;
{
if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
return 1;
return 0;
}
rtx
legitimize_pic_address (orig, mode, reg)
rtx orig;
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx reg;
{
if (GET_CODE (orig) == SYMBOL_REF)
{
rtx pic_ref, address;
rtx insn;
if (reg == 0)
{
if (reload_in_progress || reload_completed)
abort ();
else
reg = gen_reg_rtx (Pmode);
}
if (flag_pic == 2)
{
rtx temp_reg = ((reload_in_progress || reload_completed)
? reg : gen_reg_rtx (Pmode));
if (Pmode == SImode)
{
emit_insn (gen_movsi_high_pic (temp_reg, orig));
emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
}
else
{
emit_insn (gen_movdi_high_pic (temp_reg, orig));
emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
}
address = temp_reg;
}
else
address = orig;
pic_ref = gen_rtx_MEM (Pmode,
gen_rtx_PLUS (Pmode,
pic_offset_table_rtx, address));
current_function_uses_pic_offset_table = 1;
RTX_UNCHANGING_P (pic_ref) = 1;
insn = emit_move_insn (reg, pic_ref);
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
REG_NOTES (insn));
return reg;
}
else if (GET_CODE (orig) == CONST)
{
rtx base, offset;
if (GET_CODE (XEXP (orig, 0)) == PLUS
&& XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
return orig;
if (reg == 0)
{
if (reload_in_progress || reload_completed)
abort ();
else
reg = gen_reg_rtx (Pmode);
}
if (GET_CODE (XEXP (orig, 0)) == PLUS)
{
base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
base == reg ? 0 : reg);
}
else
abort ();
if (GET_CODE (offset) == CONST_INT)
{
if (SMALL_INT (offset))
return plus_constant (base, INTVAL (offset));
else if (! reload_in_progress && ! reload_completed)
offset = force_reg (Pmode, offset);
else
abort ();
}
return gen_rtx_PLUS (Pmode, base, offset);
}
else if (GET_CODE (orig) == LABEL_REF)
current_function_uses_pic_offset_table = 1;
return orig;
}
void
load_pic_register ()
{
int orig_flag_pic = flag_pic;
if (! flag_pic)
abort ();
if (get_pc_symbol_name[0] == 0)
{
int align;
ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
text_section ();
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
}
global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
flag_pic = 0;
emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
get_pc_symbol));
flag_pic = orig_flag_pic;
emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
}
int
mem_min_alignment (mem, desired)
rtx mem;
int desired;
{
rtx addr, base, offset;
if (GET_CODE (mem) != MEM)
return 0;
addr = XEXP (mem, 0);
base = offset = NULL_RTX;
if (GET_CODE (addr) == PLUS)
{
if (GET_CODE (XEXP (addr, 0)) == REG)
{
base = XEXP (addr, 0);
if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
offset = XEXP (addr, 1);
else
offset = const0_rtx;
}
}
else if (GET_CODE (addr) == REG)
{
base = addr;
offset = const0_rtx;
}
if (base != NULL_RTX)
{
int regno = REGNO (base);
if (regno != HARD_FRAME_POINTER_REGNUM && regno != STACK_POINTER_REGNUM)
{
if (((cfun != 0
&& REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT)
|| (optimize && reload_completed))
&& (INTVAL (offset) & (desired - 1)) == 0)
return 1;
}
else
{
if (((INTVAL (offset) - SPARC_STACK_BIAS) & (desired - 1)) == 0)
return 1;
}
}
else if (! TARGET_UNALIGNED_DOUBLES
|| CONSTANT_P (addr)
|| GET_CODE (addr) == LO_SUM)
{
return 1;
}
return 0;
}
enum sparc_mode_class {
S_MODE, D_MODE, T_MODE, O_MODE,
SF_MODE, DF_MODE, TF_MODE, OF_MODE,
CC_MODE, CCFP_MODE
};
#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
#define O_MODES (T_MODES | (1 << (int) O_MODE) | (1 << (int) OF_MODE))
#define SF_MODES (S_MODES)
#define DF_MODES (S_MODES | D_MODES)
#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
#define TF_ONLY_MODES (1 << (int) TF_MODE)
#define TF_MODES (DF_MODES | TF_ONLY_MODES)
#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES)
#define OF_ONLY_MODES (1 << (int) OF_MODE)
#define OF_MODES (TF_MODES | OF_ONLY_MODES)
#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES)
#define CC_MODES (1 << (int) CC_MODE)
#define CCFP_MODES (1 << (int) CCFP_MODE)
const int *hard_regno_mode_classes;
static const int hard_32bit_mode_classes[] = {
S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
CC_MODES
};
static const int hard_64bit_mode_classes[] = {
D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
CC_MODES
};
int sparc_mode_class [NUM_MACHINE_MODES];
enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
static void
sparc_init_modes ()
{
int i;
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
switch (GET_MODE_CLASS (i))
{
case MODE_INT:
case MODE_PARTIAL_INT:
case MODE_COMPLEX_INT:
if (GET_MODE_SIZE (i) <= 4)
sparc_mode_class[i] = 1 << (int) S_MODE;
else if (GET_MODE_SIZE (i) == 8)
sparc_mode_class[i] = 1 << (int) D_MODE;
else if (GET_MODE_SIZE (i) == 16)
sparc_mode_class[i] = 1 << (int) T_MODE;
else if (GET_MODE_SIZE (i) == 32)
sparc_mode_class[i] = 1 << (int) O_MODE;
else
sparc_mode_class[i] = 0;
break;
case MODE_FLOAT:
case MODE_COMPLEX_FLOAT:
if (GET_MODE_SIZE (i) <= 4)
sparc_mode_class[i] = 1 << (int) SF_MODE;
else if (GET_MODE_SIZE (i) == 8)
sparc_mode_class[i] = 1 << (int) DF_MODE;
else if (GET_MODE_SIZE (i) == 16)
sparc_mode_class[i] = 1 << (int) TF_MODE;
else if (GET_MODE_SIZE (i) == 32)
sparc_mode_class[i] = 1 << (int) OF_MODE;
else
sparc_mode_class[i] = 0;
break;
case MODE_CC:
default:
if (i == (int) CCFPmode || i == (int) CCFPEmode)
sparc_mode_class[i] = 1 << (int) CCFP_MODE;
else if (i == (int) CCmode || i == (int) CC_NOOVmode
|| i == (int) CCXmode || i == (int) CCX_NOOVmode)
sparc_mode_class[i] = 1 << (int) CC_MODE;
else
sparc_mode_class[i] = 0;
break;
}
}
if (TARGET_ARCH64)
hard_regno_mode_classes = hard_64bit_mode_classes;
else
hard_regno_mode_classes = hard_32bit_mode_classes;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (i < 16 && TARGET_V8PLUS)
sparc_regno_reg_class[i] = I64_REGS;
else if (i < 32 || i == FRAME_POINTER_REGNUM)
sparc_regno_reg_class[i] = GENERAL_REGS;
else if (i < 64)
sparc_regno_reg_class[i] = FP_REGS;
else if (i < 96)
sparc_regno_reg_class[i] = EXTRA_FP_REGS;
else if (i < 100)
sparc_regno_reg_class[i] = FPCC_REGS;
else
sparc_regno_reg_class[i] = NO_REGS;
}
}
static int
save_regs (file, low, high, base, offset, n_regs, real_offset)
FILE *file;
int low, high;
const char *base;
int offset;
int n_regs;
int real_offset;
{
int i;
if (TARGET_ARCH64 && high <= 32)
{
for (i = low; i < high; i++)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
fprintf (file, "\tstx\t%s, [%s+%d]\n",
reg_names[i], base, offset + 4 * n_regs);
if (dwarf2out_do_frame ())
dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
n_regs += 2;
}
}
}
else
{
for (i = low; i < high; i += 2)
{
if (regs_ever_live[i] && ! call_used_regs[i])
{
if (regs_ever_live[i+1] && ! call_used_regs[i+1])
{
fprintf (file, "\tstd\t%s, [%s+%d]\n",
reg_names[i], base, offset + 4 * n_regs);
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
}
n_regs += 2;
}
else
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
reg_names[i], base, offset + 4 * n_regs);
if (dwarf2out_do_frame ())
dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
n_regs += 2;
}
}
else
{
if (regs_ever_live[i+1] && ! call_used_regs[i+1])
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
reg_names[i+1], base, offset + 4 * n_regs + 4);
if (dwarf2out_do_frame ())
dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
n_regs += 2;
}
}
}
}
return n_regs;
}
static int
restore_regs (file, low, high, base, offset, n_regs)
FILE *file;
int low, high;
const char *base;
int offset;
int n_regs;
{
int i;
if (TARGET_ARCH64 && high <= 32)
{
for (i = low; i < high; i++)
{
if (regs_ever_live[i] && ! call_used_regs[i])
fprintf (file, "\tldx\t[%s+%d], %s\n",
base, offset + 4 * n_regs, reg_names[i]),
n_regs += 2;
}
}
else
{
for (i = low; i < high; i += 2)
{
if (regs_ever_live[i] && ! call_used_regs[i])
if (regs_ever_live[i+1] && ! call_used_regs[i+1])
fprintf (file, "\tldd\t[%s+%d], %s\n",
base, offset + 4 * n_regs, reg_names[i]),
n_regs += 2;
else
fprintf (file, "\tld\t[%s+%d], %s\n",
base, offset + 4 * n_regs, reg_names[i]),
n_regs += 2;
else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
fprintf (file, "\tld\t[%s+%d], %s\n",
base, offset + 4 * n_regs + 4, reg_names[i+1]),
n_regs += 2;
}
}
return n_regs;
}
int
compute_frame_size (size, leaf_function)
int size;
int leaf_function;
{
int n_regs = 0, i;
int outgoing_args_size = (current_function_outgoing_args_size
+ REG_PARM_STACK_SPACE (current_function_decl));
if (TARGET_ARCH64)
{
for (i = 0; i < 8; i++)
if (regs_ever_live[i] && ! call_used_regs[i])
n_regs += 2;
}
else
{
for (i = 0; i < 8; i += 2)
if ((regs_ever_live[i] && ! call_used_regs[i])
|| (regs_ever_live[i+1] && ! call_used_regs[i+1]))
n_regs += 2;
}
for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
if ((regs_ever_live[i] && ! call_used_regs[i])
|| (regs_ever_live[i+1] && ! call_used_regs[i+1]))
n_regs += 2;
num_gfregs = n_regs;
if (leaf_function && n_regs == 0
&& size == 0 && current_function_outgoing_args_size == 0)
{
actual_fsize = apparent_fsize = 0;
}
else
{
apparent_fsize = (size - STARTING_FRAME_OFFSET + 7) & -8;
apparent_fsize += n_regs * 4;
actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8);
}
if (leaf_function == 0 || size > 0)
actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
return SPARC_STACK_ALIGN (actual_fsize);
}
static void
build_big_number (file, num, reg)
FILE *file;
int num;
const char *reg;
{
if (num >= 0 || ! TARGET_ARCH64)
{
fprintf (file, "\tsethi\t%%hi(%d), %s\n", num, reg);
if ((num & 0x3ff) != 0)
fprintf (file, "\tor\t%s, %%lo(%d), %s\n", reg, num, reg);
}
else
{
int asize = num;
int inv = ~asize;
int low = -0x400 + (asize & 0x3FF);
fprintf (file, "\tsethi\t%%hi(%d), %s\n\txor\t%s, %d, %s\n",
inv, reg, reg, low, reg);
}
}
void
sparc_output_scratch_registers (file)
FILE *file ATTRIBUTE_UNUSED;
{
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
int i;
if (TARGET_ARCH32)
return;
for (i = 2; i < 8; i++)
{
if (regs_ever_live [i]
&& ! sparc_hard_reg_printed [i])
{
sparc_hard_reg_printed [i] = 1;
fprintf (file, "\t.register\t%%g%d, #scratch\n", i);
}
if (i == 3) i = 5;
}
#endif
}
static void
sparc_output_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
if (TARGET_FLAT)
sparc_flat_function_prologue (file, size);
else
sparc_nonflat_function_prologue (file, size,
current_function_uses_only_leaf_regs);
}
static void
sparc_nonflat_function_prologue (file, size, leaf_function)
FILE *file;
HOST_WIDE_INT size;
int leaf_function;
{
sparc_output_scratch_registers (file);
actual_fsize = compute_frame_size (size, leaf_function);
if (leaf_function)
{
frame_base_name = "%sp";
frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
}
else
{
frame_base_name = "%fp";
frame_base_offset = SPARC_STACK_BIAS;
}
fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
if (actual_fsize == 0)
;
else if (! leaf_function)
{
if (actual_fsize <= 4096)
fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize);
else if (actual_fsize <= 8192)
{
fprintf (file, "\tsave\t%%sp, -4096, %%sp\n");
fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096);
}
else
{
build_big_number (file, -actual_fsize, "%g1");
fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n");
}
}
else
{
if (actual_fsize <= 4096)
fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize);
else if (actual_fsize <= 8192)
{
fprintf (file, "\tadd\t%%sp, -4096, %%sp\n");
fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096);
}
else
{
build_big_number (file, -actual_fsize, "%g1");
fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n");
}
}
if (dwarf2out_do_frame () && actual_fsize)
{
char *label = dwarf2out_cfi_label ();
dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM
: HARD_FRAME_POINTER_REGNUM),
frame_base_offset);
if (! leaf_function)
{
dwarf2out_window_save (label);
dwarf2out_return_reg (label, 31);
}
}
if (! flag_pic)
fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
if (num_gfregs)
{
int offset, real_offset, n_regs;
const char *base;
real_offset = -apparent_fsize;
offset = -apparent_fsize + frame_base_offset;
if (offset < -4096 || offset + num_gfregs * 4 > 4096)
{
build_big_number (file, offset, "%g1");
fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
base = "%g1";
offset = 0;
}
else
{
base = frame_base_name;
}
n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs,
real_offset);
}
}
static void
output_restore_regs (file, leaf_function)
FILE *file;
int leaf_function ATTRIBUTE_UNUSED;
{
int offset, n_regs;
const char *base;
offset = -apparent_fsize + frame_base_offset;
if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 )
{
build_big_number (file, offset, "%g1");
fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
base = "%g1";
offset = 0;
}
else
{
base = frame_base_name;
}
n_regs = restore_regs (file, 0, 8, base, offset, 0);
restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
}
static void
sparc_output_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
if (TARGET_FLAT)
sparc_flat_function_epilogue (file, size);
else
sparc_nonflat_function_epilogue (file, size,
current_function_uses_only_leaf_regs);
}
static void
sparc_nonflat_function_epilogue (file, size, leaf_function)
FILE *file;
HOST_WIDE_INT size ATTRIBUTE_UNUSED;
int leaf_function;
{
const char *ret;
if (current_function_epilogue_delay_list == 0)
{
rtx insn;
fputs("\tnop\n", file);
insn = get_last_insn ();
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
goto output_vectors;
}
if (num_gfregs)
output_restore_regs (file, leaf_function);
if (leaf_function)
ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl");
else
ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret");
if (! leaf_function)
{
if (current_function_calls_eh_return)
{
if (current_function_epilogue_delay_list)
abort ();
if (SKIP_CALLERS_UNIMP_P)
abort ();
fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
}
else if (current_function_epilogue_delay_list)
{
rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
{
epilogue_renumber (&delay, 0);
fputs (SKIP_CALLERS_UNIMP_P
? "\treturn\t%i7+12\n"
: "\treturn\t%i7+8\n", file);
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
file, 1, 0, 0);
}
else
{
rtx insn, src;
if (GET_CODE (delay) != SET)
abort();
src = SET_SRC (delay);
if (GET_CODE (src) == ASHIFT)
{
if (XEXP (src, 1) != const1_rtx)
abort();
SET_SRC (delay)
= gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
XEXP (src, 0));
}
insn = gen_rtx_PARALLEL (VOIDmode,
gen_rtvec (2, delay,
gen_rtx_RETURN (VOIDmode)));
insn = emit_jump_insn (insn);
sparc_emitting_epilogue = true;
final_scan_insn (insn, file, 1, 0, 1);
sparc_emitting_epilogue = false;
}
}
else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
fputs ("\treturn\t%i7+8\n\tnop\n", file);
else
fprintf (file, "\t%s\n\trestore\n", ret);
}
else if (current_function_calls_eh_return)
abort ();
else if (current_function_epilogue_delay_list)
{
if (actual_fsize != 0)
abort ();
fprintf (file, "\t%s\n", ret);
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
file, 1, 0, 1);
}
else if (actual_fsize == 0)
fprintf (file, "\t%s\n\tnop\n", ret);
else if (actual_fsize <= 4096)
fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize);
else if (actual_fsize <= 8192)
fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n",
ret, actual_fsize - 4096);
else if ((actual_fsize & 0x3ff) == 0)
fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n",
actual_fsize, ret);
else
fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n",
actual_fsize, actual_fsize, ret);
output_vectors:
sparc_output_deferred_case_vectors ();
}
const char *
output_sibcall (insn, call_operand)
rtx insn, call_operand;
{
int leaf_regs = current_function_uses_only_leaf_regs;
rtx operands[3];
int delay_slot = dbr_sequence_length () > 0;
if (num_gfregs)
{
if (delay_slot)
{
rtx delay = NEXT_INSN (insn);
if (! delay)
abort ();
final_scan_insn (delay, asm_out_file, 1, 0, 1);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
delay_slot = 0;
}
output_restore_regs (asm_out_file, leaf_regs);
}
operands[0] = call_operand;
if (leaf_regs)
{
#ifdef HAVE_AS_RELAX_OPTION
int spare_slot = 0;
#else
int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic);
#endif
int size = 0;
if ((actual_fsize || ! spare_slot) && delay_slot)
{
rtx delay = NEXT_INSN (insn);
if (! delay)
abort ();
final_scan_insn (delay, asm_out_file, 1, 0, 1);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
delay_slot = 0;
}
if (actual_fsize)
{
if (actual_fsize <= 4096)
size = actual_fsize;
else if (actual_fsize <= 8192)
{
fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file);
size = actual_fsize - 4096;
}
else if ((actual_fsize & 0x3ff) == 0)
fprintf (asm_out_file,
"\tsethi\t%%hi(%d), %%g1\n\tadd\t%%sp, %%g1, %%sp\n",
actual_fsize);
else
{
fprintf (asm_out_file,
"\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n",
actual_fsize, actual_fsize);
fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file);
}
}
if (spare_slot)
{
output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands);
if (size)
fprintf (asm_out_file, "\t sub\t%%sp, -%d, %%sp\n", size);
else if (! delay_slot)
fputs ("\t nop\n", asm_out_file);
}
else
{
if (size)
fprintf (asm_out_file, "\tsub\t%%sp, -%d, %%sp\n", size);
output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
output_asm_insn ("call\t%a0, 0", operands);
output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
}
return "";
}
output_asm_insn ("call\t%a0, 0", operands);
if (delay_slot)
{
rtx delay = NEXT_INSN (insn), pat;
if (! delay)
abort ();
pat = PATTERN (delay);
if (GET_CODE (pat) != SET)
abort ();
operands[0] = SET_DEST (pat);
pat = SET_SRC (pat);
switch (GET_CODE (pat))
{
case PLUS:
operands[1] = XEXP (pat, 0);
operands[2] = XEXP (pat, 1);
output_asm_insn (" restore %r1, %2, %Y0", operands);
break;
case LO_SUM:
operands[1] = XEXP (pat, 0);
operands[2] = XEXP (pat, 1);
output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
break;
case ASHIFT:
operands[1] = XEXP (pat, 0);
output_asm_insn (" restore %r1, %r1, %Y0", operands);
break;
default:
operands[1] = pat;
output_asm_insn (" restore %%g0, %1, %Y0", operands);
break;
}
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
}
else
fputs ("\t restore\n", asm_out_file);
return "";
}
#define SPARC_INT_ARG_MAX 6
#define SPARC_FP_ARG_MAX 16
#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
void
init_cumulative_args (cum, fntype, libname, indirect)
CUMULATIVE_ARGS *cum;
tree fntype;
rtx libname ATTRIBUTE_UNUSED;
int indirect ATTRIBUTE_UNUSED;
{
cum->words = 0;
cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype);
cum->libcall_p = fntype == 0;
}
static int
function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
int incoming_p;
int *pregno;
int *ppadding;
{
int regbase = (incoming_p
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno = cum->words;
int regno;
*ppadding = 0;
if (type != 0 && TREE_ADDRESSABLE (type))
return -1;
if (TARGET_ARCH32
&& type != 0 && mode == BLKmode
&& TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
return -1;
switch (mode)
{
case VOIDmode :
return -1;
case QImode : case CQImode :
case HImode : case CHImode :
case SImode : case CSImode :
case DImode : case CDImode :
case TImode : case CTImode :
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
break;
case SFmode : case SCmode :
case DFmode : case DCmode :
case TFmode : case TCmode :
if (TARGET_ARCH32)
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else
{
if ((mode == TFmode || mode == TCmode)
&& (slotno & 1) != 0)
slotno++, *ppadding = 1;
if (TARGET_FPU && named)
{
if (slotno >= SPARC_FP_ARG_MAX)
return -1;
regno = SPARC_FP_ARG_FIRST + slotno * 2;
if (mode == SFmode)
regno++;
}
else
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
}
break;
case BLKmode :
if (TARGET_ARCH64)
{
if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
slotno++, *ppadding = 1;
}
if (TARGET_ARCH32
|| (type && TREE_CODE (type) == UNION_TYPE))
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
else
{
tree field;
int intregs_p = 0, fpregs_p = 0;
int packed_p = 0;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
&& TARGET_FPU)
fpregs_p = 1;
else
intregs_p = 1;
if (DECL_PACKED (field))
packed_p = 1;
}
}
if (packed_p || !named)
fpregs_p = 0, intregs_p = 1;
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
return -1;
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
return -1;
return slotno;
}
break;
default :
abort ();
}
*pregno = regno;
return slotno;
}
struct function_arg_record_value_parms
{
rtx ret;
int slotno, named, regbase;
unsigned int nregs;
int intoffset;
};
static void function_arg_record_value_3
PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
static void function_arg_record_value_2
PARAMS ((tree, HOST_WIDE_INT,
struct function_arg_record_value_parms *));
static void function_arg_record_value_1
PARAMS ((tree, HOST_WIDE_INT,
struct function_arg_record_value_parms *));
static rtx function_arg_record_value
PARAMS ((tree, enum machine_mode, int, int, int));
static void
function_arg_record_value_1 (type, startbitpos, parms)
tree type;
HOST_WIDE_INT startbitpos;
struct function_arg_record_value_parms *parms;
{
tree field;
int packed_p = 0;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
{
packed_p = 1;
break;
}
}
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
HOST_WIDE_INT bitpos = startbitpos;
if (DECL_SIZE (field) != 0
&& host_integerp (bit_position (field), 1))
bitpos += int_bit_position (field);
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
|| (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
== REAL_TYPE)))
&& TARGET_FPU
&& ! packed_p
&& parms->named)
{
if (parms->intoffset != -1)
{
int intslots, this_slotno;
intslots = (bitpos - parms->intoffset + BITS_PER_WORD - 1)
/ BITS_PER_WORD;
this_slotno = parms->slotno + parms->intoffset
/ BITS_PER_WORD;
intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
intslots = MAX (intslots, 0);
parms->nregs += intslots;
parms->intoffset = -1;
}
parms->nregs += 1;
if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
parms->nregs += 1;
}
else
{
if (parms->intoffset == -1)
parms->intoffset = bitpos;
}
}
}
}
static void
function_arg_record_value_3 (bitpos, parms)
HOST_WIDE_INT bitpos;
struct function_arg_record_value_parms *parms;
{
enum machine_mode mode;
unsigned int regno;
unsigned int startbit, endbit;
int this_slotno, intslots, intoffset;
rtx reg;
if (parms->intoffset == -1)
return;
intoffset = parms->intoffset;
parms->intoffset = -1;
startbit = intoffset & -BITS_PER_WORD;
endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
intslots = (endbit - startbit) / BITS_PER_WORD;
this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
if (intslots <= 0)
return;
if (intoffset % BITS_PER_WORD != 0)
mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
MODE_INT, 0);
else
mode = word_mode;
intoffset /= BITS_PER_UNIT;
do
{
regno = parms->regbase + this_slotno;
reg = gen_rtx_REG (mode, regno);
XVECEXP (parms->ret, 0, parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
this_slotno += 1;
intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
parms->nregs += 1;
intslots -= 1;
}
while (intslots > 0);
}
static void
function_arg_record_value_2 (type, startbitpos, parms)
tree type;
HOST_WIDE_INT startbitpos;
struct function_arg_record_value_parms *parms;
{
tree field;
int packed_p = 0;
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
{
packed_p = 1;
break;
}
}
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
HOST_WIDE_INT bitpos = startbitpos;
if (DECL_SIZE (field) != 0
&& host_integerp (bit_position (field), 1))
bitpos += int_bit_position (field);
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
|| (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE
&& (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
== REAL_TYPE)))
&& TARGET_FPU
&& ! packed_p
&& parms->named)
{
int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
int regno;
enum machine_mode mode = DECL_MODE (field);
rtx reg;
function_arg_record_value_3 (bitpos, parms);
regno = SPARC_FP_ARG_FIRST + this_slotno * 2
+ ((mode == SFmode || mode == SCmode)
&& (bitpos & 32) != 0);
switch (mode)
{
case SCmode: mode = SFmode; break;
case DCmode: mode = DFmode; break;
case TCmode: mode = TFmode; break;
default: break;
}
reg = gen_rtx_REG (mode, regno);
XVECEXP (parms->ret, 0, parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT (bitpos / BITS_PER_UNIT));
parms->nregs += 1;
if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
{
regno += GET_MODE_SIZE (mode) / 4;
reg = gen_rtx_REG (mode, regno);
XVECEXP (parms->ret, 0, parms->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg,
GEN_INT ((bitpos + GET_MODE_BITSIZE (mode))
/ BITS_PER_UNIT));
parms->nregs += 1;
}
}
else
{
if (parms->intoffset == -1)
parms->intoffset = bitpos;
}
}
}
}
static rtx
function_arg_record_value (type, mode, slotno, named, regbase)
tree type;
enum machine_mode mode;
int slotno, named, regbase;
{
HOST_WIDE_INT typesize = int_size_in_bytes (type);
struct function_arg_record_value_parms parms;
unsigned int nregs;
parms.ret = NULL_RTX;
parms.slotno = slotno;
parms.named = named;
parms.regbase = regbase;
parms.nregs = 0;
parms.intoffset = 0;
function_arg_record_value_1 (type, 0, &parms);
if (parms.intoffset != -1)
{
unsigned int startbit, endbit;
int intslots, this_slotno;
startbit = parms.intoffset & -BITS_PER_WORD;
endbit = (typesize*BITS_PER_UNIT + BITS_PER_WORD - 1) & -BITS_PER_WORD;
intslots = (endbit - startbit) / BITS_PER_WORD;
this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
intslots = MAX (intslots, 0);
parms.nregs += intslots;
}
nregs = parms.nregs;
if (nregs == 0)
{
if (typesize <= 0)
{
return gen_rtx_REG (mode, regbase);
}
else
{
nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
}
if (nregs + slotno > SPARC_INT_ARG_MAX)
nregs = SPARC_INT_ARG_MAX - slotno;
}
if (nregs == 0)
abort ();
parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nregs));
parms.nregs = 0;
parms.intoffset = 0;
function_arg_record_value_2 (type, 0, &parms);
function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
if (parms.nregs != nregs)
abort ();
return parms.ret;
}
rtx
function_arg (cum, mode, type, named, incoming_p)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
int incoming_p;
{
int regbase = (incoming_p
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno, regno, padding;
rtx reg;
slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
®no, &padding);
if (slotno == -1)
return 0;
if (TARGET_ARCH32)
{
reg = gen_rtx_REG (mode, regno);
return reg;
}
if ((GET_MODE_CLASS (mode) == MODE_FLOAT
|| GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
&& SPARC_FP_REG_P (regno))
{
reg = gen_rtx_REG (mode, regno);
if (cum->prototype_p || cum->libcall_p)
{
#if 0
if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
return gen_rtx_PARALLEL (mode,
gen_rtvec (2,
gen_rtx_EXPR_LIST (VOIDmode,
NULL_RTX, const0_rtx),
gen_rtx_EXPR_LIST (VOIDmode,
reg, const0_rtx)));
else
#else
#endif
return reg;
}
else
{
rtx v0, v1;
if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2)
{
int intreg;
if (incoming_p)
return reg;
intreg = (SPARC_OUTGOING_INT_ARG_FIRST
+ (regno - SPARC_FP_ARG_FIRST) / 2);
v0 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
v1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, intreg),
const0_rtx);
return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
}
else
{
v0 = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
v1 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
}
}
}
else if (type && TREE_CODE (type) == RECORD_TYPE)
{
if (int_size_in_bytes (type) > 16)
abort ();
return function_arg_record_value (type, mode, slotno, named, regbase);
}
else if (type && TREE_CODE (type) == UNION_TYPE)
{
enum machine_mode mode;
int bytes = int_size_in_bytes (type);
if (bytes > 16)
abort ();
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
reg = gen_rtx_REG (mode, regno);
}
else
{
reg = gen_rtx_REG (mode, regno);
}
return reg;
}
int
function_arg_partial_nregs (cum, mode, type, named)
const CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int slotno, regno, padding;
slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding);
if (slotno == -1)
return 0;
if (TARGET_ARCH32)
{
if ((slotno + (mode == BLKmode
? ROUND_ADVANCE (int_size_in_bytes (type))
: ROUND_ADVANCE (GET_MODE_SIZE (mode))))
> NPARM_REGS (SImode))
return NPARM_REGS (SImode) - slotno;
return 0;
}
else
{
if (type && AGGREGATE_TYPE_P (type))
{
int size = int_size_in_bytes (type);
int align = TYPE_ALIGN (type);
if (align == 16)
slotno += slotno & 1;
if (size > 8 && size <= 16
&& slotno == SPARC_INT_ARG_MAX - 1)
return 1;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
|| (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
&& ! TARGET_FPU))
{
if (GET_MODE_ALIGNMENT (mode) == 128)
{
slotno += slotno & 1;
if (slotno == SPARC_INT_ARG_MAX - 2)
return 1;
}
else
{
if (slotno == SPARC_INT_ARG_MAX - 1)
return 1;
}
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{
if (GET_MODE_ALIGNMENT (mode) == 128)
slotno += slotno & 1;
if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
> SPARC_FP_ARG_MAX)
return 1;
}
return 0;
}
}
int
function_arg_pass_by_reference (cum, mode, type, named)
const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
enum machine_mode mode;
tree type;
int named ATTRIBUTE_UNUSED;
{
if (TARGET_ARCH32)
{
return ((type && AGGREGATE_TYPE_P (type))
|| mode == TFmode || mode == TCmode);
}
else
{
return ((type && TREE_CODE (type) == ARRAY_TYPE)
|| GET_MODE_SIZE (mode) > 16
|| (type
&& AGGREGATE_TYPE_P (type)
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16));
}
}
void
function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int slotno, regno, padding;
slotno = function_arg_slotno (cum, mode, type, named, 0, ®no, &padding);
if (slotno != -1)
cum->words += padding;
if (TARGET_ARCH32)
{
cum->words += (mode != BLKmode
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
: ROUND_ADVANCE (int_size_in_bytes (type)));
}
else
{
if (type && AGGREGATE_TYPE_P (type))
{
int size = int_size_in_bytes (type);
if (size <= 8)
++cum->words;
else if (size <= 16)
cum->words += 2;
else
++cum->words;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
{
cum->words += 2;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{
cum->words += GET_MODE_SIZE (mode) / UNITS_PER_WORD;
}
else
{
cum->words += (mode != BLKmode
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
: ROUND_ADVANCE (int_size_in_bytes (type)));
}
}
}
enum direction
function_arg_padding (mode, type)
enum machine_mode mode;
tree type;
{
if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
return upward;
return (! BYTES_BIG_ENDIAN
? upward
: ((mode == BLKmode
? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
: GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
? downward : upward));
}
rtx
function_value (type, mode, incoming_p)
tree type;
enum machine_mode mode;
int incoming_p;
{
int regno;
int regbase = (incoming_p
? SPARC_OUTGOING_INT_ARG_FIRST
: SPARC_INCOMING_INT_ARG_FIRST);
if (TARGET_ARCH64 && type)
{
if (TREE_CODE (type) == RECORD_TYPE)
{
if (int_size_in_bytes (type) > 32)
abort ();
return function_arg_record_value (type, mode, 0, 1, regbase);
}
else if (AGGREGATE_TYPE_P (type))
{
HOST_WIDE_INT bytes = int_size_in_bytes (type);
if (bytes > 32)
abort ();
mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
}
}
if (TARGET_ARCH64
&& GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD
&& type && ! AGGREGATE_TYPE_P (type))
mode = DImode;
if (incoming_p)
regno = BASE_RETURN_VALUE_REG (mode);
else
regno = BASE_OUTGOING_VALUE_REG (mode);
return gen_rtx_REG (mode, regno);
}
rtx
sparc_builtin_saveregs ()
{
int first_reg = current_function_args_info.words;
rtx address;
int regno;
for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
emit_move_insn (gen_rtx_MEM (word_mode,
gen_rtx_PLUS (Pmode,
frame_pointer_rtx,
GEN_INT (FIRST_PARM_OFFSET (0)
+ (UNITS_PER_WORD
* regno)))),
gen_rtx_REG (word_mode,
BASE_INCOMING_ARG_REG (word_mode) + regno));
address = gen_rtx_PLUS (Pmode,
frame_pointer_rtx,
GEN_INT (FIRST_PARM_OFFSET (0)
+ UNITS_PER_WORD * first_reg));
return address;
}
void
sparc_va_start (valist, nextarg)
tree valist;
rtx nextarg;
{
nextarg = expand_builtin_saveregs ();
std_expand_builtin_va_start (valist, nextarg);
}
rtx
sparc_va_arg (valist, type)
tree valist, type;
{
HOST_WIDE_INT size, rsize, align;
tree addr, incr;
rtx addr_rtx;
int indirect = 0;
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
align = 0;
if (TARGET_ARCH64)
{
if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
align = 2 * UNITS_PER_WORD;
if (AGGREGATE_TYPE_P (type))
{
if ((unsigned HOST_WIDE_INT) size > 16)
{
indirect = 1;
size = rsize = UNITS_PER_WORD;
}
else if (size == 0)
size = rsize = UNITS_PER_WORD;
else
size = rsize;
}
}
else
{
if (AGGREGATE_TYPE_P (type)
|| TYPE_MODE (type) == TFmode
|| TYPE_MODE (type) == TCmode)
{
indirect = 1;
size = rsize = UNITS_PER_WORD;
}
}
incr = valist;
if (align)
{
incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
build_int_2 (align - 1, 0)));
incr = fold (build (BIT_AND_EXPR, ptr_type_node, incr,
build_int_2 (-align, -1)));
}
addr = incr = save_expr (incr);
if (BYTES_BIG_ENDIAN && size < rsize)
{
addr = fold (build (PLUS_EXPR, ptr_type_node, incr,
build_int_2 (rsize - size, 0)));
}
incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
build_int_2 (rsize, 0)));
incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
TREE_SIDE_EFFECTS (incr) = 1;
expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
if (align == 0
&& TYPE_ALIGN (type) > BITS_PER_WORD
&& !indirect)
{
rtx tmp = assign_temp (type, 0, 1, 0);
rtx dest_addr;
addr_rtx = force_reg (Pmode, addr_rtx);
addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
set_mem_align (addr_rtx, BITS_PER_WORD);
tmp = shallow_copy_rtx (tmp);
PUT_MODE (tmp, BLKmode);
set_mem_alias_set (tmp, 0);
dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
BLOCK_OP_NORMAL);
if (dest_addr != NULL_RTX)
addr_rtx = dest_addr;
else
addr_rtx = XCEXP (tmp, 0, MEM);
}
if (indirect)
{
addr_rtx = force_reg (Pmode, addr_rtx);
addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
}
return addr_rtx;
}
char *
output_cbranch (op, dest, label, reversed, annul, noop, insn)
rtx op, dest;
int label;
int reversed, annul, noop;
rtx insn;
{
static char string[50];
enum rtx_code code = GET_CODE (op);
rtx cc_reg = XEXP (op, 0);
enum machine_mode mode = GET_MODE (cc_reg);
const char *labelno, *branch;
int spaces = 8, far;
char *p;
far = get_attr_length (insn) >= 3;
if (reversed ^ far)
{
if (mode == CCFPmode || mode == CCFPEmode)
code = reverse_condition_maybe_unordered (code);
else
code = reverse_condition (code);
}
if (mode == CCFPmode || mode == CCFPEmode)
{
switch (code)
{
case NE:
branch = "fbne";
break;
case EQ:
branch = "fbe";
break;
case GE:
branch = "fbge";
break;
case GT:
branch = "fbg";
break;
case LE:
branch = "fble";
break;
case LT:
branch = "fbl";
break;
case UNORDERED:
branch = "fbu";
break;
case ORDERED:
branch = "fbo";
break;
case UNGT:
branch = "fbug";
break;
case UNLT:
branch = "fbul";
break;
case UNEQ:
branch = "fbue";
break;
case UNGE:
branch = "fbuge";
break;
case UNLE:
branch = "fbule";
break;
case LTGT:
branch = "fblg";
break;
default:
abort ();
}
string[0] = '\0';
if (! TARGET_V9)
strcpy (string, "nop\n\t");
strcat (string, branch);
}
else
{
switch (code)
{
case NE:
branch = "bne";
break;
case EQ:
branch = "be";
break;
case GE:
if (mode == CC_NOOVmode || mode == CCX_NOOVmode)
branch = "bpos";
else
branch = "bge";
break;
case GT:
branch = "bg";
break;
case LE:
branch = "ble";
break;
case LT:
if (mode == CC_NOOVmode || mode == CCX_NOOVmode)
branch = "bneg";
else
branch = "bl";
break;
case GEU:
branch = "bgeu";
break;
case GTU:
branch = "bgu";
break;
case LEU:
branch = "bleu";
break;
case LTU:
branch = "blu";
break;
default:
abort ();
}
strcpy (string, branch);
}
spaces -= strlen (branch);
p = strchr (string, '\0');
if (annul && ! far)
{
strcpy (p, ",a");
p += 2;
spaces -= 2;
}
if (! TARGET_V9)
labelno = "";
else
{
rtx note;
int v8 = 0;
if (! far && insn && INSN_ADDRESSES_SET_P ())
{
int delta = (INSN_ADDRESSES (INSN_UID (dest))
- INSN_ADDRESSES (INSN_UID (insn)));
if (delta < -260000 || delta >= 260000)
v8 = 1;
}
if (mode == CCFPmode || mode == CCFPEmode)
{
static char v9_fcc_labelno[] = "%%fccX, ";
v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0';
labelno = v9_fcc_labelno;
if (v8)
{
if (REGNO (cc_reg) == SPARC_FCC_REG)
labelno = "";
else
abort ();
}
}
else if (mode == CCXmode || mode == CCX_NOOVmode)
{
labelno = "%%xcc, ";
if (v8)
abort ();
}
else
{
labelno = "%%icc, ";
if (v8)
labelno = "";
}
if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
{
strcpy (p,
((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far)
? ",pt" : ",pn");
p += 3;
spaces -= 3;
}
}
if (spaces > 0)
*p++ = '\t';
else
*p++ = ' ';
strcpy (p, labelno);
p = strchr (p, '\0');
if (far)
{
strcpy (p, ".+12\n\tnop\n\tb\t");
if (annul || noop)
p[3] = '6';
p += 13;
}
*p++ = '%';
*p++ = 'l';
*p++ = label + '0';
*p = '\0';
if (noop)
strcpy (p, "\n\tnop");
return string;
}
void
sparc_emit_float_lib_cmp (x, y, comparison)
rtx x, y;
enum rtx_code comparison;
{
const char *qpfunc;
rtx slot0, slot1, result, tem, tem2;
enum machine_mode mode;
switch (comparison)
{
case EQ:
qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq";
break;
case NE:
qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne";
break;
case GT:
qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt";
break;
case GE:
qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge";
break;
case LT:
qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt";
break;
case LE:
qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle";
break;
case ORDERED:
case UNORDERED:
case UNGT:
case UNLT:
case UNEQ:
case UNGE:
case UNLE:
case LTGT:
qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp";
break;
default:
abort();
break;
}
if (TARGET_ARCH64)
{
if (GET_CODE (x) != MEM)
{
slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
}
else
slot0 = x;
if (GET_CODE (y) != MEM)
{
slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
}
else
slot1 = y;
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
DImode, 2,
XEXP (slot0, 0), Pmode,
XEXP (slot1, 0), Pmode);
mode = DImode;
}
else
{
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
SImode, 2,
x, TFmode, y, TFmode);
mode = SImode;
}
result = gen_reg_rtx (mode);
emit_move_insn (result, hard_libcall_value (mode));
switch (comparison)
{
default:
emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0);
break;
case ORDERED:
case UNORDERED:
emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE,
NULL_RTX, mode, 0);
break;
case UNGT:
case UNGE:
emit_cmp_insn (result, const1_rtx,
comparison == UNGT ? GT : NE, NULL_RTX, mode, 0);
break;
case UNLE:
emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0);
break;
case UNLT:
tem = gen_reg_rtx (mode);
if (TARGET_ARCH32)
emit_insn (gen_andsi3 (tem, result, const1_rtx));
else
emit_insn (gen_anddi3 (tem, result, const1_rtx));
emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0);
break;
case UNEQ:
case LTGT:
tem = gen_reg_rtx (mode);
if (TARGET_ARCH32)
emit_insn (gen_addsi3 (tem, result, const1_rtx));
else
emit_insn (gen_adddi3 (tem, result, const1_rtx));
tem2 = gen_reg_rtx (mode);
if (TARGET_ARCH32)
emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
else
emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE,
NULL_RTX, mode, 0);
break;
}
}
void
sparc_emit_floatunsdi (operands)
rtx operands[2];
{
rtx neglab, donelab, i0, i1, f0, in, out;
enum machine_mode mode;
out = operands[0];
in = force_reg (DImode, operands[1]);
mode = GET_MODE (out);
neglab = gen_label_rtx ();
donelab = gen_label_rtx ();
i0 = gen_reg_rtx (DImode);
i1 = gen_reg_rtx (DImode);
f0 = gen_reg_rtx (mode);
emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
emit_jump_insn (gen_jump (donelab));
emit_barrier ();
emit_label (neglab);
emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
emit_insn (gen_anddi3 (i1, in, const1_rtx));
emit_insn (gen_iordi3 (i0, i0, i1));
emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
emit_label (donelab);
}
char *
output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
rtx op, dest;
int reg, label;
int reversed, annul, noop;
rtx insn;
{
static char string[50];
enum rtx_code code = GET_CODE (op);
enum machine_mode mode = GET_MODE (XEXP (op, 0));
rtx note;
int far;
char *p;
far = get_attr_length (insn) >= 3;
if (reversed ^ far)
code = reverse_condition (code);
if (mode != DImode)
abort ();
switch (code)
{
case NE:
strcpy (string, "brnz");
break;
case EQ:
strcpy (string, "brz");
break;
case GE:
strcpy (string, "brgez");
break;
case LT:
strcpy (string, "brlz");
break;
case LE:
strcpy (string, "brlez");
break;
case GT:
strcpy (string, "brgz");
break;
default:
abort ();
}
p = strchr (string, '\0');
if (annul && ! far)
{
strcpy (p, ",a");
p += 2;
}
if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
{
strcpy (p,
((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far)
? ",pt" : ",pn");
p += 3;
}
*p = p < string + 8 ? '\t' : ' ';
p++;
*p++ = '%';
*p++ = '0' + reg;
*p++ = ',';
*p++ = ' ';
if (far)
{
int veryfar = 1, delta;
if (INSN_ADDRESSES_SET_P ())
{
delta = (INSN_ADDRESSES (INSN_UID (dest))
- INSN_ADDRESSES (INSN_UID (insn)));
if (delta >= -260000 && delta < 260000)
veryfar = 0;
}
strcpy (p, ".+12\n\tnop\n\t");
if (annul || noop)
p[3] = '6';
p += 11;
if (veryfar)
{
strcpy (p, "b\t");
p += 2;
}
else
{
strcpy (p, "ba,pt\t%%xcc, ");
p += 13;
}
}
*p++ = '%';
*p++ = 'l';
*p++ = '0' + label;
*p = '\0';
if (noop)
strcpy (p, "\n\tnop");
return string;
}
static int
epilogue_renumber (where, test)
register rtx *where;
int test;
{
register const char *fmt;
register int i;
register enum rtx_code code;
if (*where == 0)
return 0;
code = GET_CODE (*where);
switch (code)
{
case REG:
if (REGNO (*where) >= 8 && REGNO (*where) < 24)
return 1;
if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
*where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
case SCRATCH:
case CC0:
case PC:
case CONST_INT:
case CONST_DOUBLE:
return 0;
case PLUS:
if (GET_CODE (XEXP (*where, 0)) == REG
&& REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM
&& (GET_CODE (XEXP (*where, 1)) != CONST_INT
|| INTVAL (XEXP (*where, 1)) < SPARC_STACK_BIAS))
return 1;
break;
case MEM:
if (SPARC_STACK_BIAS
&& GET_CODE (XEXP (*where, 0)) == REG
&& REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM)
return 1;
break;
default:
break;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
return 1;
}
else if (fmt[i] == 'e'
&& epilogue_renumber (&(XEXP (*where, i)), test))
return 1;
}
return 0;
}
static const int
reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
static const int
reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
static const int *const reg_alloc_orders[] = {
reg_leaf_alloc_order,
reg_nonleaf_alloc_order};
void
order_regs_for_local_alloc ()
{
static int last_order_nonleaf = 1;
if (regs_ever_live[15] != last_order_nonleaf)
{
last_order_nonleaf = !last_order_nonleaf;
memcpy ((char *) reg_alloc_order,
(const char *) reg_alloc_orders[last_order_nonleaf],
FIRST_PSEUDO_REGISTER * sizeof (int));
}
}
int
sparc_splitdi_legitimate (reg, mem)
rtx reg;
rtx mem;
{
if (! reload_completed)
abort ();
if (! offsettable_memref_p (mem))
return 0;
if ((REGNO (reg) % 2) == 0
&& mem_min_alignment (mem, 8))
return 0;
return 1;
}
int
sparc_absnegfloat_split_legitimate (x, y)
rtx x, y;
{
if (GET_CODE (x) != REG)
return 0;
if (GET_CODE (y) != REG)
return 0;
if (REGNO (x) == REGNO (y))
return 0;
return 1;
}
int
registers_ok_for_ldd_peep (reg1, reg2)
rtx reg1, reg2;
{
if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
return 0;
if (REGNO (reg1) % 2 != 0)
return 0;
if (TARGET_V9 && REGNO (reg1) < 32)
return 0;
return (REGNO (reg1) == REGNO (reg2) - 1);
}
int
mems_ok_for_ldd_peep (mem1, mem2, dependent_reg_rtx)
rtx mem1, mem2, dependent_reg_rtx;
{
rtx addr1, addr2;
unsigned int reg1;
int offset1;
if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
return 0;
if (MEM_ALIGN (mem1) < 64)
return 0;
addr1 = XEXP (mem1, 0);
addr2 = XEXP (mem2, 0);
if (GET_CODE (addr1) == PLUS)
{
if (GET_CODE (XEXP (addr1, 0)) != REG)
return 0;
else
{
reg1 = REGNO (XEXP (addr1, 0));
if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
return 0;
offset1 = INTVAL (XEXP (addr1, 1));
}
}
else if (GET_CODE (addr1) != REG)
return 0;
else
{
reg1 = REGNO (addr1);
offset1 = 0;
}
if (GET_CODE (addr2) != PLUS)
return 0;
if (GET_CODE (XEXP (addr2, 0)) != REG
|| GET_CODE (XEXP (addr2, 1)) != CONST_INT)
return 0;
if (reg1 != REGNO (XEXP (addr2, 0)))
return 0;
if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx))
return 0;
if (offset1 % 8 != 0)
return 0;
if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
return 0;
return 1;
}
int
register_ok_for_ldd (reg)
rtx reg;
{
if (GET_CODE (reg) != REG)
return 0;
if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
return (REGNO (reg) % 2 == 0);
else
return 1;
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
switch (code)
{
case '#':
if (dbr_sequence_length () == 0)
fputs ("\n\t nop", file);
return;
case '*':
if (dbr_sequence_length () == 0
&& (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs (",a", file);
return;
case '(':
if (dbr_sequence_length () == 0
&& ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs ("\n\t nop", file);
return;
case '_':
fputs (EMBMEDANY_BASE_REG, file);
return;
case '@':
fprintf (file, "%s+%d", frame_base_name, frame_base_offset);
return;
case 'Y':
if (GET_CODE (x) == CONST_INT)
break;
else if (GET_CODE (x) != REG)
output_operand_lossage ("invalid %%Y operand");
else if (REGNO (x) < 8)
fputs (reg_names[REGNO (x)], file);
else if (REGNO (x) >= 24 && REGNO (x) < 32)
fputs (reg_names[REGNO (x)-16], file);
else
output_operand_lossage ("invalid %%Y operand");
return;
case 'L':
if (WORDS_BIG_ENDIAN)
fputs (reg_names[REGNO (x)+1], file);
else
fputs (reg_names[REGNO (x)], file);
return;
case 'H':
if (WORDS_BIG_ENDIAN)
fputs (reg_names[REGNO (x)], file);
else
fputs (reg_names[REGNO (x)+1], file);
return;
case 'R':
fputs (reg_names[REGNO (x)+1], file);
return;
case 'S':
fputs (reg_names[REGNO (x)+2], file);
return;
case 'T':
fputs (reg_names[REGNO (x)+3], file);
return;
case 'x':
if (REGNO (x) == SPARC_ICC_REG)
{
if (GET_MODE (x) == CCmode)
fputs ("%icc", file);
else if (GET_MODE (x) == CCXmode)
fputs ("%xcc", file);
else
abort ();
}
else
fputs (reg_names[REGNO (x)], file);
return;
case 'm':
output_address (XEXP (x, 0));
return;
case 'r':
if (x == const0_rtx
|| (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
{
fputs ("%g0", file);
return;
}
else
break;
case 'A':
switch (GET_CODE (x))
{
case IOR: fputs ("or", file); break;
case AND: fputs ("and", file); break;
case XOR: fputs ("xor", file); break;
default: output_operand_lossage ("invalid %%A operand");
}
return;
case 'B':
switch (GET_CODE (x))
{
case IOR: fputs ("orn", file); break;
case AND: fputs ("andn", file); break;
case XOR: fputs ("xnor", file); break;
default: output_operand_lossage ("invalid %%B operand");
}
return;
case 'c' :
case 'C':
{
enum rtx_code rc = GET_CODE (x);
if (code == 'c')
{
enum machine_mode mode = GET_MODE (XEXP (x, 0));
if (mode == CCFPmode || mode == CCFPEmode)
rc = reverse_condition_maybe_unordered (GET_CODE (x));
else
rc = reverse_condition (GET_CODE (x));
}
switch (rc)
{
case NE: fputs ("ne", file); break;
case EQ: fputs ("e", file); break;
case GE: fputs ("ge", file); break;
case GT: fputs ("g", file); break;
case LE: fputs ("le", file); break;
case LT: fputs ("l", file); break;
case GEU: fputs ("geu", file); break;
case GTU: fputs ("gu", file); break;
case LEU: fputs ("leu", file); break;
case LTU: fputs ("lu", file); break;
case LTGT: fputs ("lg", file); break;
case UNORDERED: fputs ("u", file); break;
case ORDERED: fputs ("o", file); break;
case UNLT: fputs ("ul", file); break;
case UNLE: fputs ("ule", file); break;
case UNGT: fputs ("ug", file); break;
case UNGE: fputs ("uge", file); break;
case UNEQ: fputs ("ue", file); break;
default: output_operand_lossage (code == 'c'
? "invalid %%c operand"
: "invalid %%C operand");
}
return;
}
case 'd':
case 'D':
{
enum rtx_code rc = (code == 'd'
? reverse_condition (GET_CODE (x))
: GET_CODE (x));
switch (rc)
{
case NE: fputs ("ne", file); break;
case EQ: fputs ("e", file); break;
case GE: fputs ("gez", file); break;
case LT: fputs ("lz", file); break;
case LE: fputs ("lez", file); break;
case GT: fputs ("gz", file); break;
default: output_operand_lossage (code == 'd'
? "invalid %%d operand"
: "invalid %%D operand");
}
return;
}
case 'b':
{
int i = trunc_int_for_mode (INTVAL (x), QImode);
fprintf (file, "%d", i);
return;
}
case 'f':
if (GET_CODE (x) != MEM)
output_operand_lossage ("invalid %%f operand");
output_address (XEXP (x, 0));
return;
case 0:
break;
default:
output_operand_lossage ("invalid operand output code");
}
if (GET_CODE (x) == REG)
fputs (reg_names[REGNO (x)], file);
else if (GET_CODE (x) == MEM)
{
fputc ('[', file);
if (CONSTANT_P (XEXP (x, 0)))
fputs ("%g0+", file);
output_address (XEXP (x, 0));
fputc (']', file);
}
else if (GET_CODE (x) == HIGH)
{
fputs ("%hi(", file);
output_addr_const (file, XEXP (x, 0));
fputc (')', file);
}
else if (GET_CODE (x) == LO_SUM)
{
print_operand (file, XEXP (x, 0), 0);
if (TARGET_CM_MEDMID)
fputs ("+%l44(", file);
else
fputs ("+%lo(", file);
output_addr_const (file, XEXP (x, 1));
fputc (')', file);
}
else if (GET_CODE (x) == CONST_DOUBLE
&& (GET_MODE (x) == VOIDmode
|| GET_MODE_CLASS (GET_MODE (x)) == MODE_INT))
{
if (CONST_DOUBLE_HIGH (x) == 0)
fprintf (file, "%u", (unsigned int) CONST_DOUBLE_LOW (x));
else if (CONST_DOUBLE_HIGH (x) == -1
&& CONST_DOUBLE_LOW (x) < 0)
fprintf (file, "%d", (int) CONST_DOUBLE_LOW (x));
else
output_operand_lossage ("long long constant not a valid immediate operand");
}
else if (GET_CODE (x) == CONST_DOUBLE)
output_operand_lossage ("floating point constant not a valid immediate operand");
else { output_addr_const (file, x); }
}
static bool
sparc_assemble_integer (x, size, aligned_p)
rtx x;
unsigned int size;
int aligned_p;
{
if (aligned_p && size == 8
&& (GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE))
{
if (TARGET_V9)
{
assemble_integer_with_op ("\t.xword\t", x);
return true;
}
else
{
assemble_aligned_integer (4, const0_rtx);
assemble_aligned_integer (4, x);
return true;
}
}
return default_assemble_integer (x, size, aligned_p);
}
#ifndef SHORT_TYPE_SIZE
#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
#endif
#ifndef INT_TYPE_SIZE
#define INT_TYPE_SIZE BITS_PER_WORD
#endif
#ifndef LONG_TYPE_SIZE
#define LONG_TYPE_SIZE BITS_PER_WORD
#endif
#ifndef LONG_LONG_TYPE_SIZE
#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
#endif
#ifndef FLOAT_TYPE_SIZE
#define FLOAT_TYPE_SIZE BITS_PER_WORD
#endif
#ifndef DOUBLE_TYPE_SIZE
#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
#endif
#ifndef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
#endif
unsigned long
sparc_type_code (type)
register tree type;
{
register unsigned long qualifiers = 0;
register unsigned shift;
for (shift = 6; shift < 30; shift += 2, type = TREE_TYPE (type))
{
switch (TREE_CODE (type))
{
case ERROR_MARK:
return qualifiers;
case ARRAY_TYPE:
qualifiers |= (3 << shift);
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
qualifiers |= (2 << shift);
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
qualifiers |= (1 << shift);
break;
case RECORD_TYPE:
return (qualifiers | 8);
case UNION_TYPE:
case QUAL_UNION_TYPE:
return (qualifiers | 9);
case ENUMERAL_TYPE:
return (qualifiers | 10);
case VOID_TYPE:
return (qualifiers | 16);
case INTEGER_TYPE:
if (TREE_TYPE (type) != 0)
break;
if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
else
return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
case REAL_TYPE:
if (TREE_TYPE (type) != 0)
break;
if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
return (qualifiers | 6);
else
return (qualifiers | 7);
case COMPLEX_TYPE:
return (qualifiers | 7);
case CHAR_TYPE:
case BOOLEAN_TYPE:
case FILE_TYPE:
case SET_TYPE:
case LANG_TYPE:
return qualifiers;
default:
abort ();
}
}
return qualifiers;
}
void
sparc_initialize_trampoline (tramp, fnaddr, cxt)
rtx tramp, fnaddr, cxt;
{
#ifdef TRANSFER_FROM_TRAMPOLINE
emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
#endif
emit_move_insn
(gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
expand_binop (SImode, ior_optab,
expand_shift (RSHIFT_EXPR, SImode, fnaddr,
size_int (10), 0, 1),
GEN_INT (trunc_int_for_mode (0x03000000, SImode)),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
(gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
expand_binop (SImode, ior_optab,
expand_shift (RSHIFT_EXPR, SImode, cxt,
size_int (10), 0, 1),
GEN_INT (trunc_int_for_mode (0x05000000, SImode)),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
(gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
expand_binop (SImode, ior_optab,
expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
NULL_RTX, 1, OPTAB_DIRECT));
emit_move_insn
(gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
expand_binop (SImode, ior_optab,
expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
NULL_RTX, 1, OPTAB_DIRECT));
emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
&& sparc_cpu != PROCESSOR_ULTRASPARC3)
emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
plus_constant (tramp, 8)))));
}
void
sparc64_initialize_trampoline (tramp, fnaddr, cxt)
rtx tramp, fnaddr, cxt;
{
#ifdef TRANSFER_FROM_TRAMPOLINE
emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
#endif
emit_move_insn (gen_rtx_MEM (SImode, tramp),
GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
&& sparc_cpu != PROCESSOR_ULTRASPARC3)
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
}
struct sparc_frame_info
{
unsigned long total_size;
unsigned long var_size;
unsigned long args_size;
unsigned long extra_size;
unsigned int gp_reg_size;
unsigned int fp_reg_size;
unsigned long gmask;
unsigned long fmask;
unsigned long reg_offset;
int initialized;
};
struct sparc_frame_info current_frame_info;
struct sparc_frame_info zero_frame_info;
#define RETURN_ADDR_REGNUM 15
#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM))
#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
#define MUST_SAVE_REGISTER(regno) \
((regs_ever_live[regno] && !call_used_regs[regno]) \
|| (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
|| (regno == RETURN_ADDR_REGNUM && regs_ever_live[RETURN_ADDR_REGNUM]))
unsigned long
sparc_flat_compute_frame_size (size)
int size;
{
int regno;
unsigned long total_size;
unsigned long var_size;
unsigned long args_size;
unsigned long extra_size;
unsigned int gp_reg_size;
unsigned int fp_reg_size;
unsigned long gmask;
unsigned long fmask;
unsigned long reg_offset;
int need_aligned_p;
extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0);
var_size = size;
gp_reg_size = 0;
fp_reg_size = 0;
gmask = 0;
fmask = 0;
reg_offset = 0;
need_aligned_p = 0;
args_size = 0;
if (!leaf_function_p ())
{
args_size = current_function_outgoing_args_size + 24;
}
total_size = var_size + args_size;
for (regno = 1; regno <= 31; regno++)
{
if (MUST_SAVE_REGISTER (regno))
{
if ((regno & 0x1) == 0 && MUST_SAVE_REGISTER (regno+1))
{
if (gp_reg_size % 8 != 0)
gp_reg_size += 4;
gp_reg_size += 2 * UNITS_PER_WORD;
gmask |= 3 << regno;
regno++;
need_aligned_p = 1;
}
else
{
gp_reg_size += UNITS_PER_WORD;
gmask |= 1 << regno;
}
}
}
for (regno = 32; regno <= 63; regno++)
{
if (regs_ever_live[regno] && !call_used_regs[regno])
{
fp_reg_size += UNITS_PER_WORD;
fmask |= 1 << (regno - 32);
}
}
if (gmask || fmask)
{
int n;
reg_offset = FIRST_PARM_OFFSET(0) + args_size;
n = reg_offset % 8;
if (need_aligned_p && n != 0)
{
total_size += 8 - n;
reg_offset += 8 - n;
}
total_size += gp_reg_size + fp_reg_size;
}
if (total_size > 0)
total_size += extra_size;
else
extra_size = 0;
total_size = SPARC_STACK_ALIGN (total_size);
current_frame_info.total_size = total_size;
current_frame_info.var_size = var_size;
current_frame_info.args_size = args_size;
current_frame_info.extra_size = extra_size;
current_frame_info.gp_reg_size = gp_reg_size;
current_frame_info.fp_reg_size = fp_reg_size;
current_frame_info.gmask = gmask;
current_frame_info.fmask = fmask;
current_frame_info.reg_offset = reg_offset;
current_frame_info.initialized = reload_completed;
return total_size;
}
void
sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op,
doubleword_op, base_offset)
FILE *file;
const char *base_reg;
unsigned int offset;
unsigned long gmask;
unsigned long fmask;
const char *word_op;
const char *doubleword_op;
unsigned long base_offset;
{
int regno;
if (gmask == 0 && fmask == 0)
return;
if (gmask)
{
for (regno = 1; regno <= 31; regno++)
{
if ((gmask & (1L << regno)) != 0)
{
if ((regno & 0x1) == 0 && ((gmask & (1L << (regno+1))) != 0))
{
if (offset % 8 != 0)
offset += UNITS_PER_WORD;
if (word_op[0] == 's')
{
fprintf (file, "\t%s\t%s, [%s+%d]\n",
doubleword_op, reg_names[regno],
base_reg, offset);
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
dwarf2out_reg_save (l, regno, offset + base_offset);
dwarf2out_reg_save
(l, regno+1, offset+base_offset + UNITS_PER_WORD);
}
}
else
fprintf (file, "\t%s\t[%s+%d], %s\n",
doubleword_op, base_reg, offset,
reg_names[regno]);
offset += 2 * UNITS_PER_WORD;
regno++;
}
else
{
if (word_op[0] == 's')
{
fprintf (file, "\t%s\t%s, [%s+%d]\n",
word_op, reg_names[regno],
base_reg, offset);
if (dwarf2out_do_frame ())
dwarf2out_reg_save ("", regno, offset + base_offset);
}
else
fprintf (file, "\t%s\t[%s+%d], %s\n",
word_op, base_reg, offset, reg_names[regno]);
offset += UNITS_PER_WORD;
}
}
}
}
if (fmask)
{
for (regno = 32; regno <= 63; regno++)
{
if ((fmask & (1L << (regno - 32))) != 0)
{
if (word_op[0] == 's')
{
fprintf (file, "\t%s\t%s, [%s+%d]\n",
word_op, reg_names[regno],
base_reg, offset);
if (dwarf2out_do_frame ())
dwarf2out_reg_save ("", regno, offset + base_offset);
}
else
fprintf (file, "\t%s\t[%s+%d], %s\n",
word_op, base_reg, offset, reg_names[regno]);
offset += UNITS_PER_WORD;
}
}
}
}
static void
sparc_flat_function_prologue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
const char *sp_str = reg_names[STACK_POINTER_REGNUM];
unsigned long gmask = current_frame_info.gmask;
sparc_output_scratch_registers (file);
fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
fprintf (file, "\t%s# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
ASM_COMMENT_START,
current_frame_info.var_size,
current_frame_info.gp_reg_size / 4,
current_frame_info.fp_reg_size / 4,
current_function_outgoing_args_size,
current_frame_info.extra_size);
size = SPARC_STACK_ALIGN (size);
size = (! current_frame_info.initialized
? sparc_flat_compute_frame_size (size)
: current_frame_info.total_size);
if (size == 0 && (gmask || current_frame_info.fmask))
abort ();
if (size > 0)
{
unsigned int reg_offset = current_frame_info.reg_offset;
const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
static const char *const t1_str = "%g1";
if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
{
if (size <= 4096)
{
fprintf (file, "\tadd\t%s, %d, %s\n",
sp_str, (int) -size, sp_str);
if (gmask & HARD_FRAME_POINTER_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
fp_str, sp_str, reg_offset);
fprintf (file, "\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
sp_str, (int) -size, fp_str, ASM_COMMENT_START);
reg_offset += 4;
}
}
else
{
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
t1_str, sp_str, t1_str, sp_str);
if (gmask & HARD_FRAME_POINTER_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
fp_str, sp_str, reg_offset);
fprintf (file, "\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
sp_str, t1_str, fp_str, ASM_COMMENT_START);
reg_offset += 4;
}
}
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
if (gmask & HARD_FRAME_POINTER_MASK)
{
dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
reg_offset - 4 - size);
dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
}
else
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
}
if (gmask & RETURN_ADDR_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
if (dwarf2out_do_frame ())
dwarf2out_return_save ("", reg_offset - size);
reg_offset += 4;
}
sparc_flat_save_restore (file, sp_str, reg_offset,
gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
current_frame_info.fmask,
"st", "std", -size);
}
else
{
unsigned HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16;
unsigned HOST_WIDE_INT offset = size1 - (size - reg_offset);
if (size1 <= 4096)
{
fprintf (file, "\tadd\t%s, %d, %s\n",
sp_str, (int) -size1, sp_str);
if (gmask & HARD_FRAME_POINTER_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
fp_str, sp_str, (int) offset, sp_str, (int) -size1,
fp_str, ASM_COMMENT_START);
offset += 4;
}
}
else
{
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
t1_str, sp_str, t1_str, sp_str);
if (gmask & HARD_FRAME_POINTER_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
fp_str, sp_str, (int) offset, sp_str, t1_str,
fp_str, ASM_COMMENT_START);
offset += 4;
}
}
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
if (gmask & HARD_FRAME_POINTER_MASK)
{
dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
offset - 4 - size1);
dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
}
else
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
}
if (gmask & RETURN_ADDR_MASK)
{
fprintf (file, "\tst\t%s, [%s+%d]\n",
reg_names[RETURN_ADDR_REGNUM], sp_str, (int) offset);
if (dwarf2out_do_frame ())
dwarf2out_return_save ("", offset - size1);
offset += 4;
}
sparc_flat_save_restore (file, sp_str, offset,
gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
current_frame_info.fmask,
"st", "std", -size1);
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size - size1);
fprintf (file, ", %s\n\tsub\t%s, %s, %s\n",
t1_str, sp_str, t1_str, sp_str);
if (dwarf2out_do_frame ())
if (! (gmask & HARD_FRAME_POINTER_MASK))
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
}
}
fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
}
static void
sparc_flat_function_epilogue (file, size)
FILE *file;
HOST_WIDE_INT size;
{
rtx epilogue_delay = current_function_epilogue_delay_list;
int noepilogue = FALSE;
fprintf (file, "\t%s#EPILOGUE#\n", ASM_COMMENT_START);
size = SPARC_STACK_ALIGN (size);
size = (!current_frame_info.initialized
? sparc_flat_compute_frame_size (size)
: current_frame_info.total_size);
if (size == 0 && epilogue_delay == 0)
{
rtx insn = get_last_insn ();
if (GET_CODE (insn) == NOTE)
insn = prev_nonnote_insn (insn);
if (insn && GET_CODE (insn) == BARRIER)
noepilogue = TRUE;
}
if (!noepilogue)
{
unsigned HOST_WIDE_INT reg_offset = current_frame_info.reg_offset;
unsigned HOST_WIDE_INT size1;
const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
static const char *const t1_str = "%g1";
if (size > 4095)
{
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
fprintf (file, ", %s\n", t1_str);
}
if (frame_pointer_needed)
{
if (size > 4095)
fprintf (file,"\tsub\t%s, %s, %s\t\t%s# sp not trusted here\n",
fp_str, t1_str, sp_str, ASM_COMMENT_START);
else
fprintf (file,"\tsub\t%s, %d, %s\t\t%s# sp not trusted here\n",
fp_str, (int) size, sp_str, ASM_COMMENT_START);
}
if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
{
size1 = 0;
}
else
{
size1 = ((reg_offset - 64 - 16) + 15) & -16;
reg_offset = size1 - reg_offset;
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size1);
fprintf (file, ", %s\n\tadd\t%s, %s, %s\n",
t1_str, sp_str, t1_str, sp_str);
}
if (current_frame_info.gmask & HARD_FRAME_POINTER_MASK)
{
fprintf (file, "\tld\t[%s+%d], %s\n",
sp_str, (int) reg_offset, fp_str);
reg_offset += 4;
}
if (current_frame_info.gmask & RETURN_ADDR_MASK)
{
fprintf (file, "\tld\t[%s+%d], %s\n",
sp_str, (int) reg_offset, reg_names[RETURN_ADDR_REGNUM]);
reg_offset += 4;
}
sparc_flat_save_restore (file, sp_str, reg_offset,
current_frame_info.gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
current_frame_info.fmask,
"ld", "ldd", 0);
if (size1 > 0)
{
size -= size1;
if (size > 4095)
{
fprintf (file, "\tset\t");
fprintf (file, HOST_WIDE_INT_PRINT_DEC, size);
fprintf (file, ", %s\n", t1_str);
}
}
if (current_function_returns_struct)
fprintf (file, "\tjmp\t%%o7+12\n");
else
fprintf (file, "\tretl\n");
if (epilogue_delay)
{
if (size)
abort ();
final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
}
else if (size > 4095)
fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
else if (size > 0)
fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) size, sp_str);
else
fprintf (file, "\tnop\n");
}
current_frame_info = zero_frame_info;
sparc_output_deferred_case_vectors ();
}
int
sparc_flat_epilogue_delay_slots ()
{
if (!current_frame_info.initialized)
(void) sparc_flat_compute_frame_size (get_frame_size ());
if (current_frame_info.total_size == 0)
return 1;
return 0;
}
int
sparc_flat_eligible_for_epilogue_delay (trial, slot)
rtx trial;
int slot ATTRIBUTE_UNUSED;
{
rtx pat = PATTERN (trial);
if (get_attr_length (trial) != 1)
return 0;
if (! reg_mentioned_p (stack_pointer_rtx, pat)
&& ! reg_mentioned_p (frame_pointer_rtx, pat))
return 1;
return 0;
}
static int
supersparc_adjust_cost (insn, link, dep_insn, cost)
rtx insn;
rtx link;
rtx dep_insn;
int cost;
{
enum attr_type insn_type;
if (! recog_memoized (insn))
return 0;
insn_type = get_attr_type (insn);
if (REG_NOTE_KIND (link) == 0)
{
if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD)
return cost + 3;
if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE)
{
rtx pat = PATTERN(insn);
rtx dep_pat = PATTERN (dep_insn);
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return cost;
if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
return cost;
return cost + 3;
}
if (insn_type == TYPE_SHIFT)
return cost + 3;
}
else
{
if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
return 0;
}
return cost;
}
static int
hypersparc_adjust_cost (insn, link, dep_insn, cost)
rtx insn;
rtx link;
rtx dep_insn;
int cost;
{
enum attr_type insn_type, dep_type;
rtx pat = PATTERN(insn);
rtx dep_pat = PATTERN (dep_insn);
if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
return cost;
insn_type = get_attr_type (insn);
dep_type = get_attr_type (dep_insn);
switch (REG_NOTE_KIND (link))
{
case 0:
switch (insn_type)
{
case TYPE_STORE:
case TYPE_FPSTORE:
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
return cost;
if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
return cost;
return cost + 3;
case TYPE_LOAD:
case TYPE_SLOAD:
case TYPE_FPLOAD:
if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
{
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
|| GET_CODE (SET_DEST (dep_pat)) != MEM
|| GET_CODE (SET_SRC (pat)) != MEM
|| ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
XEXP (SET_SRC (pat), 0)))
return cost + 2;
return cost + 8;
}
break;
case TYPE_BRANCH:
if (dep_type == TYPE_COMPARE)
return 0;
if (dep_type == TYPE_FPCMP)
return cost - 1;
break;
default:
break;
}
break;
case REG_DEP_ANTI:
if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
return 0;
break;
default:
break;
}
return cost;
}
static int
sparc_adjust_cost(insn, link, dep, cost)
rtx insn;
rtx link;
rtx dep;
int cost;
{
switch (sparc_cpu)
{
case PROCESSOR_SUPERSPARC:
cost = supersparc_adjust_cost (insn, link, dep, cost);
break;
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
cost = hypersparc_adjust_cost (insn, link, dep, cost);
break;
default:
break;
}
return cost;
}
static void
sparc_sched_init (dump, sched_verbose, max_ready)
FILE *dump ATTRIBUTE_UNUSED;
int sched_verbose ATTRIBUTE_UNUSED;
int max_ready ATTRIBUTE_UNUSED;
{
}
static int
sparc_use_dfa_pipeline_interface ()
{
if ((1 << sparc_cpu) &
((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
(1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
(1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
(1 << PROCESSOR_ULTRASPARC3)))
return 1;
return 0;
}
static int
sparc_use_sched_lookahead ()
{
if (sparc_cpu == PROCESSOR_ULTRASPARC
|| sparc_cpu == PROCESSOR_ULTRASPARC3)
return 4;
if ((1 << sparc_cpu) &
((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
(1 << PROCESSOR_SPARCLITE86X)))
return 3;
return 0;
}
static int
sparc_issue_rate ()
{
switch (sparc_cpu)
{
default:
return 1;
case PROCESSOR_V9:
return 2;
case PROCESSOR_SUPERSPARC:
return 3;
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
return 2;
case PROCESSOR_ULTRASPARC:
case PROCESSOR_ULTRASPARC3:
return 4;
}
}
static int
set_extends (insn)
rtx insn;
{
register rtx pat = PATTERN (insn);
switch (GET_CODE (SET_SRC (pat)))
{
case MEM:
case ZERO_EXTEND:
case HIGH:
case LO_SUM:
case LT: case LTU:
case GT: case GTU:
case LE: case LEU:
case GE: case GEU:
case EQ:
case NE:
return 1;
case AND:
{
rtx op0 = XEXP (SET_SRC (pat), 0);
rtx op1 = XEXP (SET_SRC (pat), 1);
if (GET_CODE (op1) == CONST_INT)
return INTVAL (op1) >= 0;
if (GET_CODE (op0) != REG)
return 0;
if (sparc_check_64 (op0, insn) == 1)
return 1;
return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
}
case IOR:
case XOR:
{
rtx op0 = XEXP (SET_SRC (pat), 0);
rtx op1 = XEXP (SET_SRC (pat), 1);
if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
return 0;
if (GET_CODE (op1) == CONST_INT)
return INTVAL (op1) >= 0;
return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
}
case LSHIFTRT:
return GET_MODE (SET_SRC (pat)) == SImode;
case CONST_DOUBLE:
return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
case CONST_INT:
return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
case ASHIFTRT:
case SIGN_EXTEND:
return - (GET_MODE (SET_SRC (pat)) == SImode);
case REG:
return sparc_check_64 (SET_SRC (pat), insn);
default:
return 0;
}
}
static GTY(()) rtx sparc_addr_diff_list;
static GTY(()) rtx sparc_addr_list;
void
sparc_defer_case_vector (lab, vec, diff)
rtx lab, vec;
int diff;
{
vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
if (diff)
sparc_addr_diff_list
= gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list);
else
sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
}
static void
sparc_output_addr_vec (vec)
rtx vec;
{
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
int idx, vlen = XVECLEN (body, 0);
#ifdef ASM_OUTPUT_ADDR_VEC_START
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
#endif
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
NEXT_INSN (lab));
#else
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
#endif
for (idx = 0; idx < vlen; idx++)
{
ASM_OUTPUT_ADDR_VEC_ELT
(asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
}
#ifdef ASM_OUTPUT_ADDR_VEC_END
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
#endif
}
static void
sparc_output_addr_diff_vec (vec)
rtx vec;
{
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
rtx base = XEXP (XEXP (body, 0), 0);
int idx, vlen = XVECLEN (body, 1);
#ifdef ASM_OUTPUT_ADDR_VEC_START
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
#endif
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
NEXT_INSN (lab));
#else
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
#endif
for (idx = 0; idx < vlen; idx++)
{
ASM_OUTPUT_ADDR_DIFF_ELT
(asm_out_file,
body,
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
CODE_LABEL_NUMBER (base));
}
#ifdef ASM_OUTPUT_ADDR_VEC_END
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
#endif
}
static void
sparc_output_deferred_case_vectors ()
{
rtx t;
int align;
if (sparc_addr_list == NULL_RTX
&& sparc_addr_diff_list == NULL_RTX)
return;
function_section (current_function_decl);
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
for (t = sparc_addr_list; t ; t = XEXP (t, 1))
sparc_output_addr_vec (XEXP (t, 0));
for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
sparc_output_addr_diff_vec (XEXP (t, 0));
sparc_addr_list = sparc_addr_diff_list = NULL_RTX;
}
int
sparc_check_64 (x, insn)
rtx x, insn;
{
int set_once = 0;
rtx y = x;
if (GET_CODE (x) != REG)
abort ();
if (GET_MODE (x) == DImode)
y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
if (flag_expensive_optimizations
&& REG_N_SETS (REGNO (y)) == 1)
set_once = 1;
if (insn == 0)
{
if (set_once)
insn = get_last_insn_anywhere ();
else
return 0;
}
while ((insn = PREV_INSN (insn)))
{
switch (GET_CODE (insn))
{
case JUMP_INSN:
case NOTE:
break;
case CODE_LABEL:
case CALL_INSN:
default:
if (! set_once)
return 0;
break;
case INSN:
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) != SET)
return 0;
if (rtx_equal_p (x, SET_DEST (pat)))
return set_extends (insn);
if (y && rtx_equal_p (y, SET_DEST (pat)))
return set_extends (insn);
if (reg_overlap_mentioned_p (SET_DEST (pat), y))
return 0;
}
}
}
return 0;
}
char *
sparc_v8plus_shift (operands, insn, opcode)
rtx *operands;
rtx insn;
const char *opcode;
{
static char asm_code[60];
if (GET_CODE (operands[3]) == SCRATCH)
operands[3] = operands[0];
if (GET_CODE (operands[1]) == CONST_INT)
{
output_asm_insn ("mov\t%1, %3", operands);
}
else
{
output_asm_insn ("sllx\t%H1, 32, %3", operands);
if (sparc_check_64 (operands[1], insn) <= 0)
output_asm_insn ("srl\t%L1, 0, %L1", operands);
output_asm_insn ("or\t%L1, %3, %3", operands);
}
strcpy(asm_code, opcode);
if (which_alternative != 2)
return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
else
return strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
}
void
sparc_profile_hook (labelno)
int labelno;
{
char buf[32];
rtx lab, fun;
ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
}
#ifdef OBJECT_FORMAT_ELF
static void
sparc_elf_asm_named_section (name, flags)
const char *name;
unsigned int flags;
{
if (flags & SECTION_MERGE)
{
default_elf_asm_named_section (name, flags);
return;
}
fprintf (asm_out_file, "\t.section\t\"%s\"", name);
if (!(flags & SECTION_DEBUG))
fputs (",#alloc", asm_out_file);
if (flags & SECTION_WRITE)
fputs (",#write", asm_out_file);
if (flags & SECTION_CODE)
fputs (",#execinstr", asm_out_file);
fputc ('\n', asm_out_file);
}
#endif
static void
sparc_aout_select_section (t, reloc, align)
tree t;
int reloc;
unsigned HOST_WIDE_INT align;
{
default_select_section (t, reloc | SUNOS4_SHARED_LIBRARIES, align);
}
static void
sparc_aout_select_rtx_section (mode, x, align)
enum machine_mode mode;
rtx x;
unsigned HOST_WIDE_INT align;
{
if (align <= MAX_TEXT_ALIGN
&& ! (flag_pic && (symbolic_operand (x, mode)
|| SUNOS4_SHARED_LIBRARIES)))
readonly_data_section ();
else
data_section ();
}
int
sparc_extra_constraint_check (op, c, strict)
rtx op;
int c;
int strict;
{
int reload_ok_mem;
if (TARGET_ARCH64
&& (c == 'T' || c == 'U'))
return 0;
switch (c)
{
case 'Q':
return fp_sethi_p (op);
case 'R':
return fp_mov_p (op);
case 'S':
return fp_high_losum_p (op);
case 'U':
if (! strict
|| (GET_CODE (op) == REG
&& (REGNO (op) < FIRST_PSEUDO_REGISTER
|| reg_renumber[REGNO (op)] >= 0)))
return register_ok_for_ldd (op);
return 0;
case 'W':
case 'T':
break;
default:
return 0;
}
if (GET_CODE (op) == MEM)
{
reload_ok_mem = 0;
if ((TARGET_ARCH64 || mem_min_alignment (op, 8))
&& (! strict
|| strict_memory_address_p (Pmode, XEXP (op, 0))))
reload_ok_mem = 1;
}
else
{
reload_ok_mem = (reload_in_progress
&& GET_CODE (op) == REG
&& REGNO (op) >= FIRST_PSEUDO_REGISTER
&& reg_renumber [REGNO (op)] < 0);
}
return reload_ok_mem;
}
int
sparc_rtx_costs (x, code, outer_code)
rtx x;
enum rtx_code code, outer_code;
{
switch (code)
{
case PLUS: case MINUS: case ABS: case NEG:
case FLOAT: case UNSIGNED_FLOAT:
case FIX: case UNSIGNED_FIX:
case FLOAT_EXTEND: case FLOAT_TRUNCATE:
if (FLOAT_MODE_P (GET_MODE (x)))
{
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
case PROCESSOR_ULTRASPARC3:
return COSTS_N_INSNS (4);
case PROCESSOR_SUPERSPARC:
return COSTS_N_INSNS (3);
case PROCESSOR_CYPRESS:
return COSTS_N_INSNS (5);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
default:
return COSTS_N_INSNS (1);
}
}
return COSTS_N_INSNS (1);
case SQRT:
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (13);
else
return COSTS_N_INSNS (23);
case PROCESSOR_ULTRASPARC3:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (20);
else
return COSTS_N_INSNS (29);
case PROCESSOR_SUPERSPARC:
return COSTS_N_INSNS (12);
case PROCESSOR_CYPRESS:
return COSTS_N_INSNS (63);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
return COSTS_N_INSNS (17);
default:
return COSTS_N_INSNS (30);
}
case COMPARE:
if (FLOAT_MODE_P (GET_MODE (x)))
{
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
case PROCESSOR_ULTRASPARC3:
return COSTS_N_INSNS (1);
case PROCESSOR_SUPERSPARC:
return COSTS_N_INSNS (3);
case PROCESSOR_CYPRESS:
return COSTS_N_INSNS (5);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
default:
return COSTS_N_INSNS (1);
}
}
return COSTS_N_INSNS (1);
case MULT:
if (FLOAT_MODE_P (GET_MODE (x)))
{
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
case PROCESSOR_ULTRASPARC3:
return COSTS_N_INSNS (4);
case PROCESSOR_SUPERSPARC:
return COSTS_N_INSNS (3);
case PROCESSOR_CYPRESS:
return COSTS_N_INSNS (7);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
return COSTS_N_INSNS (1);
default:
return COSTS_N_INSNS (5);
}
}
if (sparc_cpu == PROCESSOR_ULTRASPARC)
return (GET_MODE (x) == DImode ?
COSTS_N_INSNS (34) : COSTS_N_INSNS (19));
if (sparc_cpu == PROCESSOR_ULTRASPARC3)
return COSTS_N_INSNS (6);
if (sparc_cpu == PROCESSOR_HYPERSPARC
|| sparc_cpu == PROCESSOR_SPARCLITE86X)
return COSTS_N_INSNS (17);
return (TARGET_HARD_MUL
? COSTS_N_INSNS (5)
: COSTS_N_INSNS (25));
case DIV:
case UDIV:
case MOD:
case UMOD:
if (FLOAT_MODE_P (GET_MODE (x)))
{
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (13);
else
return COSTS_N_INSNS (23);
case PROCESSOR_ULTRASPARC3:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (17);
else
return COSTS_N_INSNS (20);
case PROCESSOR_SUPERSPARC:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (6);
else
return COSTS_N_INSNS (9);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
if (GET_MODE (x) == SFmode)
return COSTS_N_INSNS (8);
else
return COSTS_N_INSNS (12);
default:
return COSTS_N_INSNS (7);
}
}
if (sparc_cpu == PROCESSOR_ULTRASPARC)
return (GET_MODE (x) == DImode ?
COSTS_N_INSNS (68) : COSTS_N_INSNS (37));
if (sparc_cpu == PROCESSOR_ULTRASPARC3)
return (GET_MODE (x) == DImode ?
COSTS_N_INSNS (71) : COSTS_N_INSNS (40));
return COSTS_N_INSNS (25);
case IF_THEN_ELSE:
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
return COSTS_N_INSNS (2);
case PROCESSOR_ULTRASPARC3:
if (FLOAT_MODE_P (GET_MODE (x)))
return COSTS_N_INSNS (3);
else
return COSTS_N_INSNS (2);
default:
return COSTS_N_INSNS (1);
}
case MEM:
switch (sparc_cpu)
{
case PROCESSOR_ULTRASPARC:
if (outer_code == ZERO_EXTEND)
return COSTS_N_INSNS (1);
else
return COSTS_N_INSNS (2);
case PROCESSOR_ULTRASPARC3:
if (outer_code == ZERO_EXTEND)
{
if (GET_MODE (x) == QImode
|| GET_MODE (x) == HImode
|| outer_code == SIGN_EXTEND)
return COSTS_N_INSNS (2);
else
return COSTS_N_INSNS (1);
}
else
{
return COSTS_N_INSNS (2);
}
case PROCESSOR_SUPERSPARC:
if (FLOAT_MODE_P (GET_MODE (x))
|| outer_code == ZERO_EXTEND
|| outer_code == SIGN_EXTEND)
return COSTS_N_INSNS (0);
else
return COSTS_N_INSNS (1);
case PROCESSOR_TSC701:
if (outer_code == ZERO_EXTEND
|| outer_code == SIGN_EXTEND)
return COSTS_N_INSNS (2);
else
return COSTS_N_INSNS (3);
case PROCESSOR_CYPRESS:
if (outer_code == ZERO_EXTEND
|| outer_code == SIGN_EXTEND)
return COSTS_N_INSNS (1);
else
return COSTS_N_INSNS (2);
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
default:
if (outer_code == ZERO_EXTEND
|| outer_code == SIGN_EXTEND)
return COSTS_N_INSNS (0);
else
return COSTS_N_INSNS (1);
}
case CONST_INT:
if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
return 0;
case HIGH:
return 2;
case CONST:
case LABEL_REF:
case SYMBOL_REF:
return 4;
case CONST_DOUBLE:
if (GET_MODE (x) == DImode)
if ((XINT (x, 3) == 0
&& (unsigned) XINT (x, 2) < 0x1000)
|| (XINT (x, 3) == -1
&& XINT (x, 2) < 0
&& XINT (x, 2) >= -0x1000))
return 0;
return 8;
default:
abort();
};
}
static void
sparc_encode_section_info (decl, first)
tree decl;
int first ATTRIBUTE_UNUSED;
{
if (TARGET_CM_EMBMEDANY && TREE_CODE (decl) == FUNCTION_DECL)
SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
}
static void
sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
FILE *file;
tree thunk_fndecl ATTRIBUTE_UNUSED;
HOST_WIDE_INT delta;
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
tree function;
{
rtx this, insn, funexp, delta_rtx, tmp;
reload_completed = 1;
no_new_pseudos = 1;
current_function_uses_only_leaf_regs = 1;
emit_note (NULL, NOTE_INSN_PROLOGUE_END);
if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1);
else
this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
delta_rtx = GEN_INT (delta);
if (!SPARC_SIMM13_P (delta))
{
rtx scratch = gen_rtx_REG (Pmode, 1);
if (TARGET_ARCH64)
sparc_emit_set_const64 (scratch, delta_rtx);
else
sparc_emit_set_const32 (scratch, delta_rtx);
delta_rtx = scratch;
}
tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
if (! TREE_USED (function))
{
assemble_external (function);
TREE_USED (function) = 1;
}
funexp = XEXP (DECL_RTL (function), 0);
funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
insn = emit_call_insn (gen_sibcall (funexp));
SIBLING_CALL_P (insn) = 1;
emit_barrier ();
insn = get_insns ();
shorten_branches (insn);
final_start_function (insn, file, 1);
final (insn, file, 1, 0);
final_end_function ();
reload_completed = 0;
no_new_pseudos = 0;
}
#include "gt-sparc.h"