summaryrefslogtreecommitdiff
path: root/gcc/config/sparc/sparc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r--gcc/config/sparc/sparc.c230
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");