diff options
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 230 |
1 files changed, 143 insertions, 87 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 223408def9e..a066b2ab305 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -129,6 +129,30 @@ struct processor_costs hypersparc_costs = { }; static const +struct processor_costs leon_costs = { + COSTS_N_INSNS (1), /* int load */ + COSTS_N_INSNS (1), /* int signed load */ + COSTS_N_INSNS (1), /* int zeroed load */ + COSTS_N_INSNS (1), /* float load */ + COSTS_N_INSNS (1), /* fmov, fneg, fabs */ + COSTS_N_INSNS (1), /* fadd, fsub */ + COSTS_N_INSNS (1), /* fcmp */ + COSTS_N_INSNS (1), /* fmov, fmovr */ + COSTS_N_INSNS (1), /* fmul */ + COSTS_N_INSNS (15), /* fdivs */ + COSTS_N_INSNS (15), /* fdivd */ + COSTS_N_INSNS (23), /* fsqrts */ + COSTS_N_INSNS (23), /* fsqrtd */ + COSTS_N_INSNS (5), /* imul */ + COSTS_N_INSNS (5), /* imulX */ + 0, /* imul bit factor */ + COSTS_N_INSNS (5), /* idiv */ + COSTS_N_INSNS (5), /* idivX */ + COSTS_N_INSNS (1), /* movcc/movr */ + 0, /* shift penalty */ +}; + +static const struct processor_costs sparclet_costs = { COSTS_N_INSNS (3), /* int load */ COSTS_N_INSNS (3), /* int signed load */ @@ -367,7 +391,7 @@ static rtx sparc_builtin_saveregs (void); static int epilogue_renumber (rtx *, int); static bool sparc_assemble_integer (rtx, unsigned int, int); static int set_extends (rtx); -static void load_pic_register (void); +static void load_got_register (void); static int save_or_restore_regs (int, int, rtx, int, int); static void emit_save_or_restore_regs (int); static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT); @@ -698,19 +722,20 @@ sparc_option_override (void) { NULL, (enum cmodel) 0 } }; const struct code_model *cmodel; - /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */ + /* Map TARGET_CPU_DEFAULT to value for -m{cpu,tune}=. */ static struct cpu_default { const int cpu; const char *const name; } const cpu_default[] = { /* There must be one entry here for each TARGET_CPU value. */ { TARGET_CPU_sparc, "cypress" }, - { TARGET_CPU_sparclet, "tsc701" }, - { TARGET_CPU_sparclite, "f930" }, { TARGET_CPU_v8, "v8" }, + { TARGET_CPU_supersparc, "supersparc" }, { TARGET_CPU_hypersparc, "hypersparc" }, + { TARGET_CPU_leon, "leon" }, + { TARGET_CPU_sparclite, "f930" }, { TARGET_CPU_sparclite86x, "sparclite86x" }, - { TARGET_CPU_supersparc, "supersparc" }, + { TARGET_CPU_sparclet, "tsc701" }, { TARGET_CPU_v9, "v9" }, { TARGET_CPU_ultrasparc, "ultrasparc" }, { TARGET_CPU_ultrasparc3, "ultrasparc3" }, @@ -731,28 +756,32 @@ sparc_option_override (void) { "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 }, /* TI TMS390Z55 supersparc */ { "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 }, + { "hypersparc", PROCESSOR_HYPERSPARC, MASK_ISA, MASK_V8|MASK_FPU }, + /* LEON */ + { "leon", PROCESSOR_LEON, MASK_ISA, MASK_V8|MASK_FPU }, { "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE }, - /* The Fujitsu MB86930 is the original sparclite chip, with no fpu. - The Fujitsu MB86934 is the recent sparclite chip, with an fpu. */ + /* The Fujitsu MB86930 is the original sparclite chip, with no FPU. */ { "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE }, + /* The Fujitsu MB86934 is the recent sparclite chip, with an FPU. */ { "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 }, /* TEMIC sparclet */ { "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET }, { "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 }, - /* TI ultrasparc I, II, IIi */ - { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 - /* Although insns using %y are deprecated, it is a clear win on current - ultrasparcs. */ - |MASK_DEPRECATED_V8_INSNS}, - /* TI ultrasparc III */ - /* ??? Check if %y issue still holds true in ultra3. */ - { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, + /* UltraSPARC I, II, IIi */ + { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, + /* Although insns using %y are deprecated, it is a clear win. */ + MASK_V9|MASK_DEPRECATED_V8_INSNS}, + /* UltraSPARC III */ + /* ??? Check if %y issue still holds true. */ + { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, + MASK_V9|MASK_DEPRECATED_V8_INSNS}, /* UltraSPARC T1 */ - { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS}, + { "niagara", PROCESSOR_NIAGARA, MASK_ISA, + MASK_V9|MASK_DEPRECATED_V8_INSNS}, + /* UltraSPARC T2 */ { "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9}, { 0, (enum processor_type) 0, 0, 0 } }; @@ -907,6 +936,9 @@ sparc_option_override (void) case PROCESSOR_SPARCLITE86X: sparc_costs = &hypersparc_costs; break; + case PROCESSOR_LEON: + sparc_costs = &leon_costs; + break; case PROCESSOR_SPARCLET: case PROCESSOR_TSC701: sparc_costs = &sparclet_costs; @@ -2988,26 +3020,39 @@ sparc_cannot_force_const_mem (rtx x) } } -/* PIC support. */ -static GTY(()) bool pic_helper_needed = false; -static GTY(()) rtx pic_helper_symbol; -static GTY(()) rtx global_offset_table; +/* Global Offset Table support. */ +static GTY(()) rtx got_helper_rtx = NULL_RTX; +static GTY(()) rtx global_offset_table_rtx = NULL_RTX; + +/* Return the SYMBOL_REF for the Global Offset Table. */ + +static GTY(()) rtx sparc_got_symbol = NULL_RTX; + +static rtx +sparc_got (void) +{ + if (!sparc_got_symbol) + sparc_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); + + return sparc_got_symbol; +} /* Ensure that we are not using patterns that are not OK with PIC. */ int check_pic (int i) { + rtx op; + switch (flag_pic) { case 1: - gcc_assert (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)))); + op = recog_data.operand[i]; + gcc_assert (GET_CODE (op) != SYMBOL_REF + && (GET_CODE (op) != CONST + || (GET_CODE (XEXP (op, 0)) == MINUS + && XEXP (XEXP (op, 0), 0) == sparc_got () + && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))); case 2: default: return 1; @@ -3242,9 +3287,9 @@ sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict) return 1; } -/* Construct the SYMBOL_REF for the tls_get_offset function. */ +/* Return the SYMBOL_REF for the tls_get_addr function. */ -static GTY(()) rtx sparc_tls_symbol; +static GTY(()) rtx sparc_tls_symbol = NULL_RTX; static rtx sparc_tls_get_addr (void) @@ -3255,21 +3300,28 @@ sparc_tls_get_addr (void) return sparc_tls_symbol; } +/* Return the Global Offset Table to be used in TLS mode. */ + static rtx sparc_tls_got (void) { - rtx temp; + /* In PIC mode, this is just the PIC offset table. */ if (flag_pic) { crtl->uses_pic_offset_table = 1; return pic_offset_table_rtx; } - if (!global_offset_table) - global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - temp = gen_reg_rtx (Pmode); - emit_move_insn (temp, global_offset_table); - return temp; + /* In non-PIC mode, Sun as (unlike GNU as) emits PC-relative relocations for + the GOT symbol with the 32-bit ABI, so we reload the GOT register. */ + if (TARGET_SUN_TLS && TARGET_ARCH32) + { + load_got_register (); + return global_offset_table_rtx; + } + + /* In all other cases, we load a new pseudo with the GOT symbol. */ + return copy_to_reg (sparc_got ()); } /* Return true if X contains a thread-local symbol. */ @@ -3709,59 +3761,69 @@ sparc_mode_dependent_address_p (const_rtx addr) static void get_pc_thunk_name (char name[32], unsigned int regno) { - const char *pic_name = reg_names[regno]; + const char *reg_name = reg_names[regno]; /* Skip the leading '%' as that cannot be used in a symbol name. */ - pic_name += 1; + reg_name += 1; if (USE_HIDDEN_LINKONCE) - sprintf (name, "__sparc_get_pc_thunk.%s", pic_name); + sprintf (name, "__sparc_get_pc_thunk.%s", reg_name); else ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno); } -/* Emit code to load the PIC register. */ +/* Wrapper around the load_pcrel_sym{si,di} patterns. */ -static void -load_pic_register (void) +static rtx +gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3) { int orig_flag_pic = flag_pic; + rtx insn; - if (TARGET_VXWORKS_RTP) - { - emit_insn (gen_vxworks_load_got ()); - emit_use (pic_offset_table_rtx); - return; - } - - /* If we haven't initialized the special PIC symbols, do so now. */ - if (!pic_helper_needed) - { - char name[32]; + /* The load_pcrel_sym{si,di} patterns require absolute addressing. */ + flag_pic = 0; + if (TARGET_ARCH64) + insn = gen_load_pcrel_symdi (op0, op1, op2, op3); + else + insn = gen_load_pcrel_symsi (op0, op1, op2, op3); + flag_pic = orig_flag_pic; - pic_helper_needed = true; + return insn; +} - get_pc_thunk_name (name, REGNO (pic_offset_table_rtx)); - pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); +/* Emit code to load the GOT register. */ - global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_"); - } +static void +load_got_register (void) +{ + /* In PIC mode, this will retrieve pic_offset_table_rtx. */ + if (!global_offset_table_rtx) + global_offset_table_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM); - flag_pic = 0; - if (TARGET_ARCH64) - emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table, - pic_helper_symbol)); + if (TARGET_VXWORKS_RTP) + emit_insn (gen_vxworks_load_got ()); else - emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table, - pic_helper_symbol)); - flag_pic = orig_flag_pic; + { + /* The GOT symbol is subject to a PC-relative relocation so we need a + helper function to add the PC value and thus get the final value. */ + if (!got_helper_rtx) + { + char name[32]; + get_pc_thunk_name (name, GLOBAL_OFFSET_TABLE_REGNUM); + got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + } + + emit_insn (gen_load_pcrel_sym (global_offset_table_rtx, sparc_got (), + got_helper_rtx, + GEN_INT (GLOBAL_OFFSET_TABLE_REGNUM))); + } /* Need to emit this whether or not we obey regdecls, since setjmp/longjmp can cause life info to screw up. ??? In the case where we don't obey regdecls, this is not sufficient since we may not fall out the bottom. */ - emit_use (pic_offset_table_rtx); + emit_use (global_offset_table_rtx); } /* Emit a call instruction with the pattern given by PAT. ADDR is the @@ -4447,7 +4509,7 @@ gen_stack_pointer_dec (rtx decrement) /* Expand the function prologue. The prologue is responsible for reserving storage for the frame, saving the call-saved registers and loading the - PIC register if needed. */ + GOT register if needed. */ void sparc_expand_prologue (void) @@ -4555,9 +4617,9 @@ sparc_expand_prologue (void) if (num_gfregs) emit_save_or_restore_regs (SORR_SAVE); - /* Load the PIC register if needed. */ - if (flag_pic && crtl->uses_pic_offset_table) - load_pic_register (); + /* Load the GOT register if needed. */ + if (crtl->uses_pic_offset_table) + load_got_register (); } /* This function generates the assembly code for function entry, which boils @@ -8466,7 +8528,6 @@ sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) } /* libfunc renaming. */ -#include "config/gofast.h" static void sparc_init_libfuncs (void) @@ -8560,8 +8621,6 @@ sparc_init_libfuncs (void) set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoul"); } } - - gofast_maybe_init_libfuncs (); } #define def_builtin(NAME, CODE, TYPE) \ @@ -9128,7 +9187,7 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total, /* Emit the sequence of insns SEQ while preserving the registers REG and REG2. This is achieved by means of a manual dynamic stack space allocation in the current frame. We make the assumption that SEQ doesn't contain any - function calls, with the possible exception of calls to the PIC helper. */ + function calls, with the possible exception of calls to the GOT helper. */ static void emit_and_preserve (rtx seq, rtx reg, rtx reg2) @@ -9291,20 +9350,19 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED, { /* The hoops we have to jump through in order to generate a sibcall without using delay slots... */ - rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1); + rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1); if (flag_pic) { spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */ - spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM); start_sequence (); - /* Delay emitting the PIC helper function because it needs to + /* Delay emitting the GOT helper function because it needs to change the section and we are emitting assembly code. */ - load_pic_register (); /* clobbers %o7 */ + load_got_register (); /* clobbers %o7 */ scratch = sparc_legitimize_pic_address (funexp, scratch); seq = get_insns (); end_sequence (); - emit_and_preserve (seq, spill_reg, spill_reg2); + emit_and_preserve (seq, spill_reg, pic_offset_table_rtx); } else if (TARGET_ARCH32) { @@ -9455,17 +9513,15 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x) static void sparc_file_end (void) { - /* If need to emit the special PIC helper function, do so now. */ - if (pic_helper_needed) + /* If we need to emit the special GOT helper function, do so now. */ + if (got_helper_rtx) { - unsigned int regno = REGNO (pic_offset_table_rtx); - const char *pic_name = reg_names[regno]; - char name[32]; + const char *name = XSTR (got_helper_rtx, 0); + const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM]; #ifdef DWARF2_UNWIND_INFO bool do_cfi; #endif - get_pc_thunk_name (name, regno); if (USE_HIDDEN_LINKONCE) { tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, @@ -9500,10 +9556,10 @@ sparc_file_end (void) #endif if (flag_delayed_branch) fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n", - pic_name, pic_name); + reg_name, reg_name); else fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n", - pic_name, pic_name); + reg_name, reg_name); #ifdef DWARF2_UNWIND_INFO if (do_cfi) fprintf (asm_out_file, "\t.cfi_endproc\n"); |