diff options
Diffstat (limited to 'gcc-4.8/gcc/config/sparc')
-rw-r--r-- | gcc-4.8/gcc/config/sparc/leon.md | 66 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc-opts.h | 1 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc-protos.h | 3 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc.c | 515 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc.h | 46 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc.md | 427 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sparc.opt | 17 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/sync.md | 32 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/t-rtems | 4 | ||||
-rw-r--r-- | gcc-4.8/gcc/config/sparc/t-sparc | 2 |
10 files changed, 710 insertions, 403 deletions
diff --git a/gcc-4.8/gcc/config/sparc/leon.md b/gcc-4.8/gcc/config/sparc/leon.md index 60815079d..b511397fe 100644 --- a/gcc-4.8/gcc/config/sparc/leon.md +++ b/gcc-4.8/gcc/config/sparc/leon.md @@ -17,40 +17,48 @@ ;; along with GCC; see the file COPYING3. If not see ;; <http://www.gnu.org/licenses/>. +;; Leon is a single-issue processor. (define_automaton "leon") -(define_cpu_unit "leon_memory, leon_fpalu" "leon") -(define_cpu_unit "leon_fpmds" "leon") -(define_cpu_unit "write_buf" "leon") +(define_cpu_unit "leon_memory" "leon") (define_insn_reservation "leon_load" 1 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "load,sload,fpload")) + (and (eq_attr "cpu" "leon") (eq_attr "type" "load,sload")) "leon_memory") -(define_insn_reservation "leon_store" 1 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "store,fpstore")) - "leon_memory+write_buf") - -(define_insn_reservation "leon_fp_alu" 1 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "fp,fpmove")) - "leon_fpalu, nothing") - -(define_insn_reservation "leon_fp_mult" 1 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "fpmul")) - "leon_fpmds, nothing") - -(define_insn_reservation "leon_fp_div" 16 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "fpdivs,fpdivd")) - "leon_fpmds, nothing*15") - -(define_insn_reservation "leon_fp_sqrt" 23 - (and (eq_attr "cpu" "leon") - (eq_attr "type" "fpsqrts,fpsqrtd")) - "leon_fpmds, nothing*21") +;; Use a double reservation to work around the load pipeline hazard on UT699. +(define_insn_reservation "leon3_load" 1 + (and (eq_attr "cpu" "leon3") (eq_attr "type" "load,sload")) + "leon_memory*2") +(define_insn_reservation "leon_store" 2 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "store")) + "leon_memory*2") + +;; This describes Gaisler Research's FPU + +(define_automaton "grfpu") + +(define_cpu_unit "grfpu_alu" "grfpu") +(define_cpu_unit "grfpu_ds" "grfpu") + +(define_insn_reservation "leon_fp_alu" 4 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fp,fpcmp,fpmul")) + "grfpu_alu, nothing*3") + +(define_insn_reservation "leon_fp_divs" 16 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpdivs")) + "grfpu_ds*14, nothing*2") + +(define_insn_reservation "leon_fp_divd" 17 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpdivd")) + "grfpu_ds*15, nothing*2") + +(define_insn_reservation "leon_fp_sqrts" 24 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpsqrts")) + "grfpu_ds*22, nothing*2") + +(define_insn_reservation "leon_fp_sqrtd" 25 + (and (eq_attr "cpu" "leon,leon3") (eq_attr "type" "fpsqrtd")) + "grfpu_ds*23, nothing*2") diff --git a/gcc-4.8/gcc/config/sparc/sparc-opts.h b/gcc-4.8/gcc/config/sparc/sparc-opts.h index 72791772e..b5e9761af 100644 --- a/gcc-4.8/gcc/config/sparc/sparc-opts.h +++ b/gcc-4.8/gcc/config/sparc/sparc-opts.h @@ -30,6 +30,7 @@ enum processor_type { PROCESSOR_SUPERSPARC, PROCESSOR_HYPERSPARC, PROCESSOR_LEON, + PROCESSOR_LEON3, PROCESSOR_SPARCLITE, PROCESSOR_F930, PROCESSOR_F934, diff --git a/gcc-4.8/gcc/config/sparc/sparc-protos.h b/gcc-4.8/gcc/config/sparc/sparc-protos.h index a0c1a7a05..adaeb6d9d 100644 --- a/gcc-4.8/gcc/config/sparc/sparc-protos.h +++ b/gcc-4.8/gcc/config/sparc/sparc-protos.h @@ -69,7 +69,6 @@ extern bool sparc_expand_move (enum machine_mode, rtx *); extern void sparc_emit_set_symbolic_const64 (rtx, rtx, rtx); extern int sparc_splitdi_legitimate (rtx, rtx); extern int sparc_split_regreg_legitimate (rtx, rtx); -extern int sparc_absnegfloat_split_legitimate (rtx, rtx); extern const char *output_ubranch (rtx, rtx); extern const char *output_cbranch (rtx, rtx, int, int, int, rtx); extern const char *output_return (rtx); @@ -84,9 +83,9 @@ extern void emit_conditional_branch_insn (rtx []); extern int mems_ok_for_ldd_peep (rtx, rtx, rtx); extern int empty_delay_slot (rtx); extern int emit_cbcond_nop (rtx); +extern int eligible_for_call_delay (rtx); extern int eligible_for_return_delay (rtx); extern int eligible_for_sibcall_delay (rtx); -extern int tls_call_delay (rtx); extern int emit_move_sequence (rtx, enum machine_mode); extern int fp_sethi_p (rtx); extern int fp_mov_p (rtx); diff --git a/gcc-4.8/gcc/config/sparc/sparc.c b/gcc-4.8/gcc/config/sparc/sparc.c index 7e87b4716..25b7e53f2 100644 --- a/gcc-4.8/gcc/config/sparc/sparc.c +++ b/gcc-4.8/gcc/config/sparc/sparc.c @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "params.h" #include "df.h" #include "opts.h" +#include "tree-pass.h" /* Processor costs */ @@ -226,6 +227,30 @@ struct processor_costs leon_costs = { }; static const +struct processor_costs leon3_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 (14), /* fdivs */ + COSTS_N_INSNS (15), /* fdivd */ + COSTS_N_INSNS (22), /* fsqrts */ + COSTS_N_INSNS (23), /* fsqrtd */ + COSTS_N_INSNS (5), /* imul */ + COSTS_N_INSNS (5), /* imulX */ + 0, /* imul bit factor */ + COSTS_N_INSNS (35), /* idiv */ + COSTS_N_INSNS (35), /* 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 */ @@ -538,7 +563,6 @@ static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT, HOST_WIDE_INT, const_tree); -static void sparc_reorg (void); static struct machine_function * sparc_init_machine_status (void); static bool sparc_cannot_force_const_mem (enum machine_mode, rtx); static rtx sparc_tls_get_addr (void); @@ -680,9 +704,6 @@ char sparc_hard_reg_printed[8]; #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk -#undef TARGET_MACHINE_DEPENDENT_REORG -#define TARGET_MACHINE_DEPENDENT_REORG sparc_reorg - #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS sparc_rtx_costs #undef TARGET_ADDRESS_COST @@ -804,6 +825,306 @@ char sparc_hard_reg_printed[8]; struct gcc_target targetm = TARGET_INITIALIZER; +/* Return the memory reference contained in X if any, zero otherwise. */ + +static rtx +mem_ref (rtx x) +{ + if (GET_CODE (x) == SIGN_EXTEND || GET_CODE (x) == ZERO_EXTEND) + x = XEXP (x, 0); + + if (MEM_P (x)) + return x; + + return NULL_RTX; +} + +/* We use a machine specific pass to enable workarounds for errata. + We need to have the (essentially) final form of the insn stream in order + to properly detect the various hazards. Therefore, this machine specific + pass runs as late as possible. The pass is inserted in the pass pipeline + at the end of sparc_option_override. */ + +static bool +sparc_gate_work_around_errata (void) +{ + /* The only errata we handle are those of the AT697F and UT699. */ + return sparc_fix_at697f != 0 || sparc_fix_ut699 != 0; +} + +static unsigned int +sparc_do_work_around_errata (void) +{ + rtx insn, next; + + /* Force all instructions to be split into their final form. */ + split_all_insns_noflow (); + + /* Now look for specific patterns in the insn stream. */ + for (insn = get_insns (); insn; insn = next) + { + bool insert_nop = false; + rtx set; + + /* Look into the instruction in a delay slot. */ + if (NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE) + insn = XVECEXP (PATTERN (insn), 0, 1); + + /* Look for a single-word load into an odd-numbered FP register. */ + if (sparc_fix_at697f + && NONJUMP_INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 + && MEM_P (SET_SRC (set)) + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) > 31 + && REGNO (SET_DEST (set)) % 2 != 0) + { + /* The wrong dependency is on the enclosing double register. */ + const unsigned int x = REGNO (SET_DEST (set)) - 1; + unsigned int src1, src2, dest; + int code; + + next = next_active_insn (insn); + if (!next) + break; + /* If the insn is a branch, then it cannot be problematic. */ + if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) + continue; + + extract_insn (next); + code = INSN_CODE (next); + + switch (code) + { + case CODE_FOR_adddf3: + case CODE_FOR_subdf3: + case CODE_FOR_muldf3: + case CODE_FOR_divdf3: + dest = REGNO (recog_data.operand[0]); + src1 = REGNO (recog_data.operand[1]); + src2 = REGNO (recog_data.operand[2]); + if (src1 != src2) + { + /* Case [1-4]: + ld [address], %fx+1 + FPOPd %f{x,y}, %f{y,x}, %f{x,y} */ + if ((src1 == x || src2 == x) + && (dest == src1 || dest == src2)) + insert_nop = true; + } + else + { + /* Case 5: + ld [address], %fx+1 + FPOPd %fx, %fx, %fx */ + if (src1 == x + && dest == src1 + && (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3)) + insert_nop = true; + } + break; + + case CODE_FOR_sqrtdf2: + dest = REGNO (recog_data.operand[0]); + src1 = REGNO (recog_data.operand[1]); + /* Case 6: + ld [address], %fx+1 + fsqrtd %fx, %fx */ + if (src1 == x && dest == src1) + insert_nop = true; + break; + + default: + break; + } + } + + /* Look for a single-word load into an integer register. */ + else if (sparc_fix_ut699 + && NONJUMP_INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) <= 4 + && mem_ref (SET_SRC (set)) != NULL_RTX + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) < 32) + { + /* There is no problem if the second memory access has a data + dependency on the first single-cycle load. */ + rtx x = SET_DEST (set); + + next = next_active_insn (insn); + if (!next) + break; + /* If the insn is a branch, then it cannot be problematic. */ + if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) + continue; + + /* Look for a second memory access to/from an integer register. */ + if ((set = single_set (next)) != NULL_RTX) + { + rtx src = SET_SRC (set); + rtx dest = SET_DEST (set); + rtx mem; + + /* LDD is affected. */ + if ((mem = mem_ref (src)) != NULL_RTX + && REG_P (dest) + && REGNO (dest) < 32 + && !reg_mentioned_p (x, XEXP (mem, 0))) + insert_nop = true; + + /* STD is *not* affected. */ + else if (MEM_P (dest) + && GET_MODE_SIZE (GET_MODE (dest)) <= 4 + && (src == CONST0_RTX (GET_MODE (dest)) + || (REG_P (src) + && REGNO (src) < 32 + && REGNO (src) != REGNO (x))) + && !reg_mentioned_p (x, XEXP (dest, 0))) + insert_nop = true; + } + } + + /* Look for a single-word load/operation into an FP register. */ + else if (sparc_fix_ut699 + && NONJUMP_INSN_P (insn) + && (set = single_set (insn)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) > 31) + { + /* Number of instructions in the problematic window. */ + const int n_insns = 4; + /* The problematic combination is with the sibling FP register. */ + const unsigned int x = REGNO (SET_DEST (set)); + const unsigned int y = x ^ 1; + rtx after; + int i; + + next = next_active_insn (insn); + if (!next) + break; + /* If the insn is a branch, then it cannot be problematic. */ + if (!NONJUMP_INSN_P (next) || GET_CODE (PATTERN (next)) == SEQUENCE) + continue; + + /* Look for a second load/operation into the sibling FP register. */ + if (!((set = single_set (next)) != NULL_RTX + && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 + && REG_P (SET_DEST (set)) + && REGNO (SET_DEST (set)) == y)) + continue; + + /* Look for a (possible) store from the FP register in the next N + instructions, but bail out if it is again modified or if there + is a store from the sibling FP register before this store. */ + for (after = next, i = 0; i < n_insns; i++) + { + bool branch_p; + + after = next_active_insn (after); + if (!after) + break; + + /* This is a branch with an empty delay slot. */ + if (!NONJUMP_INSN_P (after)) + { + if (++i == n_insns) + break; + branch_p = true; + after = NULL_RTX; + } + /* This is a branch with a filled delay slot. */ + else if (GET_CODE (PATTERN (after)) == SEQUENCE) + { + if (++i == n_insns) + break; + branch_p = true; + after = XVECEXP (PATTERN (after), 0, 1); + } + /* This is a regular instruction. */ + else + branch_p = false; + + if (after && (set = single_set (after)) != NULL_RTX) + { + const rtx src = SET_SRC (set); + const rtx dest = SET_DEST (set); + const unsigned int size = GET_MODE_SIZE (GET_MODE (dest)); + + /* If the FP register is again modified before the store, + then the store isn't affected. */ + if (REG_P (dest) + && (REGNO (dest) == x + || (REGNO (dest) == y && size == 8))) + break; + + if (MEM_P (dest) && REG_P (src)) + { + /* If there is a store from the sibling FP register + before the store, then the store is not affected. */ + if (REGNO (src) == y || (REGNO (src) == x && size == 8)) + break; + + /* Otherwise, the store is affected. */ + if (REGNO (src) == x && size == 4) + { + insert_nop = true; + break; + } + } + } + + /* If we have a branch in the first M instructions, then we + cannot see the (M+2)th instruction so we play safe. */ + if (branch_p && i <= (n_insns - 2)) + { + insert_nop = true; + break; + } + } + } + + else + next = NEXT_INSN (insn); + + if (insert_nop) + emit_insn_before (gen_nop (), next); + } + + return 0; +} + +struct rtl_opt_pass pass_work_around_errata = +{ + { + RTL_PASS, + "errata", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + sparc_gate_work_around_errata, /* gate */ + sparc_do_work_around_errata, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_MACH_DEP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_verify_rtl_sharing, /* todo_flags_finish */ + } +}; + +struct register_pass_info insert_pass_work_around_errata = +{ + &pass_work_around_errata.pass, /* pass */ + "dbr", /* reference_pass_name */ + 1, /* ref_pass_instance_number */ + PASS_POS_INSERT_AFTER /* po_op */ +}; + +/* Helpers for TARGET_DEBUG_OPTIONS. */ static void dump_target_flag_bits (const int flags) { @@ -888,6 +1209,7 @@ sparc_option_override (void) { TARGET_CPU_supersparc, PROCESSOR_SUPERSPARC }, { TARGET_CPU_hypersparc, PROCESSOR_HYPERSPARC }, { TARGET_CPU_leon, PROCESSOR_LEON }, + { TARGET_CPU_leon3, PROCESSOR_LEON3 }, { TARGET_CPU_sparclite, PROCESSOR_F930 }, { TARGET_CPU_sparclite86x, PROCESSOR_SPARCLITE86X }, { TARGET_CPU_sparclet, PROCESSOR_TSC701 }, @@ -902,7 +1224,7 @@ sparc_option_override (void) }; const struct cpu_default *def; /* Table of values for -m{cpu,tune}=. This must match the order of - the PROCESSOR_* enumeration. */ + the enum processor_type in sparc-opts.h. */ static struct cpu_table { const char *const name; const int disable; @@ -914,8 +1236,8 @@ sparc_option_override (void) /* TI TMS390Z55 supersparc */ { "supersparc", MASK_ISA, MASK_V8 }, { "hypersparc", MASK_ISA, MASK_V8|MASK_FPU }, - /* LEON */ - { "leon", MASK_ISA, MASK_V8|MASK_FPU }, + { "leon", MASK_ISA, MASK_V8|MASK_LEON|MASK_FPU }, + { "leon3", MASK_ISA, MASK_V8|MASK_LEON3|MASK_FPU }, { "sparclite", MASK_ISA, MASK_SPARCLITE }, /* The Fujitsu MB86930 is the original sparclite chip, with no FPU. */ { "f930", MASK_ISA|MASK_FPU, MASK_SPARCLITE }, @@ -1075,6 +1397,9 @@ sparc_option_override (void) #ifndef HAVE_AS_SPARC4 & ~MASK_CBCOND #endif +#ifndef HAVE_AS_LEON + & ~(MASK_LEON | MASK_LEON3) +#endif ); /* If -mfpu or -mno-fpu was explicitly used, don't override with @@ -1164,6 +1489,9 @@ sparc_option_override (void) case PROCESSOR_LEON: sparc_costs = &leon_costs; break; + case PROCESSOR_LEON3: + sparc_costs = &leon3_costs; + break; case PROCESSOR_SPARCLET: case PROCESSOR_TSC701: sparc_costs = &sparclet_costs; @@ -1200,6 +1528,10 @@ sparc_option_override (void) /* Choose the most relaxed model for the processor. */ else if (TARGET_V9) sparc_memory_model = SMM_RMO; + else if (TARGET_LEON3) + sparc_memory_model = SMM_TSO; + else if (TARGET_LEON) + sparc_memory_model = SMM_SC; else if (TARGET_V8) sparc_memory_model = SMM_PSO; else @@ -1241,6 +1573,13 @@ sparc_option_override (void) pessimizes for double floating-point registers. */ if (!global_options_set.x_flag_ira_share_save_slots) flag_ira_share_save_slots = 0; + + /* We register a machine specific pass to work around errata, if any. + The pass mut be scheduled as late as possible so that we have the + (essentially) final form of the insn stream to work on. + Registering the pass must be done at start up. It's convenient to + do it here. */ + register_pass (&insert_pass_work_around_errata); } /* Miscellaneous utilities. */ @@ -3090,10 +3429,13 @@ emit_cbcond_nop (rtx insn) /* Return nonzero if TRIAL can go into the call delay slot. */ int -tls_call_delay (rtx trial) +eligible_for_call_delay (rtx trial) { rtx pat; + if (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_FALSE) + return 0; + /* Binutils allows call __tls_get_addr, %tgd_call (foo) add %l7, %o0, %o0, %tgd_add (foo) @@ -3175,11 +3517,7 @@ eligible_for_restore_insn (rtx trial, bool return_p) /* If we have the 'return' instruction, anything that does not use local or output registers and can go into a delay slot wins. */ - else if (return_p - && TARGET_V9 - && !epilogue_renumber (&pat, 1) - && get_attr_in_uncond_branch_delay (trial) - == IN_UNCOND_BRANCH_DELAY_TRUE) + else if (return_p && TARGET_V9 && !epilogue_renumber (&pat, 1)) return 1; /* The 'restore src1,src2,dest' pattern for SImode. */ @@ -3222,21 +3560,20 @@ eligible_for_return_delay (rtx trial) int regno; rtx pat; - if (GET_CODE (trial) != INSN) - return 0; - - if (get_attr_length (trial) != 1) - return 0; - /* If the function uses __builtin_eh_return, the eh_return machinery occupies the delay slot. */ if (crtl->calls_eh_return) return 0; + if (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_FALSE) + return 0; + /* In the case of a leaf or flat function, anything can go into the slot. */ if (sparc_leaf_function_p || TARGET_FLAT) - return - get_attr_in_uncond_branch_delay (trial) == IN_UNCOND_BRANCH_DELAY_TRUE; + return 1; + + if (!NONJUMP_INSN_P (trial)) + return 0; pat = PATTERN (trial); if (GET_CODE (pat) == PARALLEL) @@ -3256,9 +3593,7 @@ eligible_for_return_delay (rtx trial) if (regno >= 8 && regno < 24) return 0; } - return !epilogue_renumber (&pat, 1) - && (get_attr_in_uncond_branch_delay (trial) - == IN_UNCOND_BRANCH_DELAY_TRUE); + return !epilogue_renumber (&pat, 1); } if (GET_CODE (pat) != SET) @@ -3278,10 +3613,7 @@ eligible_for_return_delay (rtx trial) instruction, it can probably go in. But restore will not work with FP_REGS. */ if (! SPARC_INT_REG_P (regno)) - return (TARGET_V9 - && !epilogue_renumber (&pat, 1) - && get_attr_in_uncond_branch_delay (trial) - == IN_UNCOND_BRANCH_DELAY_TRUE); + return TARGET_V9 && !epilogue_renumber (&pat, 1); return eligible_for_restore_insn (trial, true); } @@ -3293,10 +3625,10 @@ eligible_for_sibcall_delay (rtx trial) { rtx pat; - if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET) + if (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_FALSE) return 0; - if (get_attr_length (trial) != 1) + if (!NONJUMP_INSN_P (trial)) return 0; pat = PATTERN (trial); @@ -3315,6 +3647,9 @@ eligible_for_sibcall_delay (rtx trial) return 1; } + if (GET_CODE (pat) != SET) + return 0; + /* Otherwise, only operations which can be done in tandem with a `restore' insn can go into the delay slot. */ if (GET_CODE (SET_DEST (pat)) != REG @@ -8134,22 +8469,6 @@ sparc_split_regreg_legitimate (rtx reg1, rtx reg2) return 0; } -/* Return 1 if x and y are some kind of REG and they refer to - different hard registers. This test is guaranteed to be - run after reload. */ - -int -sparc_absnegfloat_split_legitimate (rtx x, rtx y) -{ - if (GET_CODE (x) != REG) - return 0; - if (GET_CODE (y) != REG) - return 0; - if (REGNO (x) == REGNO (y)) - return 0; - return 1; -} - /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1. This makes them candidates for using ldd and std insns. @@ -10355,7 +10674,8 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tmp = e0.add_with_sign (tmp, false, &add1_ovf); if (tmp.is_negative ()) tmp = tmp.neg_with_overflow (&neg2_ovf); - + else + neg2_ovf = false; result = result.add_with_sign (tmp, false, &add2_ovf); overflow |= neg1_ovf | neg2_ovf | add1_ovf | add2_ovf; } @@ -10897,107 +11217,6 @@ sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED, return (vcall_offset >= -32768 || ! fixed_regs[5]); } -/* We use the machine specific reorg pass to enable workarounds for errata. */ - -static void -sparc_reorg (void) -{ - rtx insn, next; - - /* The only erratum we handle for now is that of the AT697F processor. */ - if (!sparc_fix_at697f) - return; - - /* We need to have the (essentially) final form of the insn stream in order - to properly detect the various hazards. Run delay slot scheduling. */ - if (optimize > 0 && flag_delayed_branch) - { - cleanup_barriers (); - dbr_schedule (get_insns ()); - } - - /* Now look for specific patterns in the insn stream. */ - for (insn = get_insns (); insn; insn = next) - { - bool insert_nop = false; - rtx set; - - /* Look for a single-word load into an odd-numbered FP register. */ - if (NONJUMP_INSN_P (insn) - && (set = single_set (insn)) != NULL_RTX - && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4 - && MEM_P (SET_SRC (set)) - && REG_P (SET_DEST (set)) - && REGNO (SET_DEST (set)) > 31 - && REGNO (SET_DEST (set)) % 2 != 0) - { - /* The wrong dependency is on the enclosing double register. */ - unsigned int x = REGNO (SET_DEST (set)) - 1; - unsigned int src1, src2, dest; - int code; - - /* If the insn has a delay slot, then it cannot be problematic. */ - next = next_active_insn (insn); - if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE) - code = -1; - else - { - extract_insn (next); - code = INSN_CODE (next); - } - - switch (code) - { - case CODE_FOR_adddf3: - case CODE_FOR_subdf3: - case CODE_FOR_muldf3: - case CODE_FOR_divdf3: - dest = REGNO (recog_data.operand[0]); - src1 = REGNO (recog_data.operand[1]); - src2 = REGNO (recog_data.operand[2]); - if (src1 != src2) - { - /* Case [1-4]: - ld [address], %fx+1 - FPOPd %f{x,y}, %f{y,x}, %f{x,y} */ - if ((src1 == x || src2 == x) - && (dest == src1 || dest == src2)) - insert_nop = true; - } - else - { - /* Case 5: - ld [address], %fx+1 - FPOPd %fx, %fx, %fx */ - if (src1 == x - && dest == src1 - && (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3)) - insert_nop = true; - } - break; - - case CODE_FOR_sqrtdf2: - dest = REGNO (recog_data.operand[0]); - src1 = REGNO (recog_data.operand[1]); - /* Case 6: - ld [address], %fx+1 - fsqrtd %fx, %fx */ - if (src1 == x && dest == src1) - insert_nop = true; - break; - - default: - break; - } - } - else - next = NEXT_INSN (insn); - - if (insert_nop) - emit_insn_after (gen_nop (), insn); - } -} - /* How to allocate a 'struct machine_function'. */ static struct machine_function * diff --git a/gcc-4.8/gcc/config/sparc/sparc.h b/gcc-4.8/gcc/config/sparc/sparc.h index c6122c115..d96c1b6b4 100644 --- a/gcc-4.8/gcc/config/sparc/sparc.h +++ b/gcc-4.8/gcc/config/sparc/sparc.h @@ -136,21 +136,22 @@ extern enum cmodel sparc_cmodel; #define TARGET_CPU_supersparc 2 #define TARGET_CPU_hypersparc 3 #define TARGET_CPU_leon 4 -#define TARGET_CPU_sparclite 5 -#define TARGET_CPU_f930 5 /* alias */ -#define TARGET_CPU_f934 5 /* alias */ -#define TARGET_CPU_sparclite86x 6 -#define TARGET_CPU_sparclet 7 -#define TARGET_CPU_tsc701 7 /* alias */ -#define TARGET_CPU_v9 8 /* generic v9 implementation */ -#define TARGET_CPU_sparcv9 8 /* alias */ -#define TARGET_CPU_sparc64 8 /* alias */ -#define TARGET_CPU_ultrasparc 9 -#define TARGET_CPU_ultrasparc3 10 -#define TARGET_CPU_niagara 11 -#define TARGET_CPU_niagara2 12 -#define TARGET_CPU_niagara3 13 -#define TARGET_CPU_niagara4 14 +#define TARGET_CPU_leon3 5 +#define TARGET_CPU_sparclite 6 +#define TARGET_CPU_f930 6 /* alias */ +#define TARGET_CPU_f934 6 /* alias */ +#define TARGET_CPU_sparclite86x 7 +#define TARGET_CPU_sparclet 8 +#define TARGET_CPU_tsc701 8 /* alias */ +#define TARGET_CPU_v9 9 /* generic v9 implementation */ +#define TARGET_CPU_sparcv9 9 /* alias */ +#define TARGET_CPU_sparc64 9 /* alias */ +#define TARGET_CPU_ultrasparc 10 +#define TARGET_CPU_ultrasparc3 11 +#define TARGET_CPU_niagara 12 +#define TARGET_CPU_niagara2 13 +#define TARGET_CPU_niagara3 14 +#define TARGET_CPU_niagara4 15 #if TARGET_CPU_DEFAULT == TARGET_CPU_v9 \ || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc \ @@ -232,9 +233,10 @@ extern enum cmodel sparc_cmodel; #define ASM_CPU32_DEFAULT_SPEC "" #endif -#if TARGET_CPU_DEFAULT == TARGET_CPU_leon +#if TARGET_CPU_DEFAULT == TARGET_CPU_leon \ + || TARGET_CPU_DEFAULT == TARGET_CPU_leon3 #define CPP_CPU32_DEFAULT_SPEC "-D__leon__ -D__sparc_v8__" -#define ASM_CPU32_DEFAULT_SPEC "" +#define ASM_CPU32_DEFAULT_SPEC AS_LEON_FLAG #endif #endif @@ -282,6 +284,7 @@ extern enum cmodel sparc_cmodel; %{mcpu=supersparc:-D__supersparc__ -D__sparc_v8__} \ %{mcpu=hypersparc:-D__hypersparc__ -D__sparc_v8__} \ %{mcpu=leon:-D__leon__ -D__sparc_v8__} \ +%{mcpu=leon3:-D__leon__ -D__sparc_v8__} \ %{mcpu=v9:-D__sparc_v9__} \ %{mcpu=ultrasparc:-D__sparc_v9__} \ %{mcpu=ultrasparc3:-D__sparc_v9__} \ @@ -329,7 +332,8 @@ extern enum cmodel sparc_cmodel; %{mcpu=v8:-Av8} \ %{mcpu=supersparc:-Av8} \ %{mcpu=hypersparc:-Av8} \ -%{mcpu=leon:-Av8} \ +%{mcpu=leon:" AS_LEON_FLAG "} \ +%{mcpu=leon3:" AS_LEON_FLAG "} \ %{mv8plus:-Av8plus} \ %{mcpu=v9:-Av9} \ %{mcpu=ultrasparc:%{!mv8plus:-Av9a}} \ @@ -1754,6 +1758,12 @@ extern int sparc_indent_opcode; #define AS_NIAGARA4_FLAG "-Av9" AS_NIAGARA3_FLAG #endif +#ifdef HAVE_AS_LEON +#define AS_LEON_FLAG "-Aleon" +#else +#define AS_LEON_FLAG "-Av8" +#endif + /* We use gcc _mcount for profiling. */ #define NO_PROFILE_COUNTERS 0 diff --git a/gcc-4.8/gcc/config/sparc/sparc.md b/gcc-4.8/gcc/config/sparc/sparc.md index b60af4333..f380a414f 100644 --- a/gcc-4.8/gcc/config/sparc/sparc.md +++ b/gcc-4.8/gcc/config/sparc/sparc.md @@ -206,7 +206,7 @@ ;; 'f' for all DF/TFmode values, including those that are specific to the v8. ;; Attribute for cpu type. -;; These must match the values for enum processor_type in sparc.h. +;; These must match the values of the enum processor_type in sparc-opts.h. (define_attr "cpu" "v7, cypress, @@ -214,6 +214,7 @@ supersparc, hypersparc, leon, + leon3, sparclite, f930, f934, @@ -284,7 +285,8 @@ (const_string "none")) (define_attr "pic" "false,true" - (symbol_ref "(flag_pic != 0 ? PIC_TRUE : PIC_FALSE)")) + (symbol_ref "(flag_pic != 0 + ? PIC_TRUE : PIC_FALSE)")) (define_attr "calls_alloca" "false,true" (symbol_ref "(cfun->calls_alloca != 0 @@ -306,6 +308,10 @@ (symbol_ref "(TARGET_FLAT != 0 ? FLAT_TRUE : FLAT_FALSE)")) +(define_attr "fix_ut699" "false,true" + (symbol_ref "(sparc_fix_ut699 != 0 + ? FIX_UT699_TRUE : FIX_UT699_FALSE)")) + ;; Length (in # of insns). ;; Beware that setting a length greater or equal to 3 for conditional branches ;; has a side-effect (see output_cbranch and output_v9branch). @@ -412,6 +418,10 @@ (define_attr "fptype" "single,double" (const_string "single")) +;; FP precision specific to the UT699. +(define_attr "fptype_ut699" "none,single" + (const_string "none")) + ;; UltraSPARC-III integer load type. (define_attr "us3load_type" "2cycle,3cycle" (const_string "2cycle")) @@ -420,32 +430,18 @@ [(set_attr "length" "2") (set_attr "type" "multi")]) -;; Attributes for instruction and branch scheduling -(define_attr "tls_call_delay" "false,true" - (symbol_ref "(tls_call_delay (insn) - ? TLS_CALL_DELAY_TRUE : TLS_CALL_DELAY_FALSE)")) - +;; Attributes for branch scheduling (define_attr "in_call_delay" "false,true" - (cond [(eq_attr "type" "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") - (const_string "false") - (eq_attr "type" "load,fpload,store,fpstore") - (if_then_else (eq_attr "length" "1") - (const_string "true") - (const_string "false"))] - (if_then_else (and (eq_attr "length" "1") - (eq_attr "tls_call_delay" "true")) - (const_string "true") - (const_string "false")))) - -(define_attr "eligible_for_sibcall_delay" "false,true" + (symbol_ref "(eligible_for_call_delay (insn) + ? IN_CALL_DELAY_TRUE : IN_CALL_DELAY_FALSE)")) + +(define_attr "in_sibcall_delay" "false,true" (symbol_ref "(eligible_for_sibcall_delay (insn) - ? ELIGIBLE_FOR_SIBCALL_DELAY_TRUE - : ELIGIBLE_FOR_SIBCALL_DELAY_FALSE)")) + ? IN_SIBCALL_DELAY_TRUE : IN_SIBCALL_DELAY_FALSE)")) -(define_attr "eligible_for_return_delay" "false,true" +(define_attr "in_return_delay" "false,true" (symbol_ref "(eligible_for_return_delay (insn) - ? ELIGIBLE_FOR_RETURN_DELAY_TRUE - : ELIGIBLE_FOR_RETURN_DELAY_FALSE)")) + ? IN_RETURN_DELAY_TRUE : IN_RETURN_DELAY_FALSE)")) ;; ??? !v9: Should implement the notion of predelay slots for floating-point ;; branches. This would allow us to remove the nop always inserted before @@ -460,39 +456,33 @@ ;; because it prevents us from moving back the final store of inner loops. (define_attr "in_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") - (eq_attr "length" "1")) - (const_string "true") - (const_string "false"))) - -(define_attr "in_uncond_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") - (eq_attr "length" "1")) - (const_string "true") - (const_string "false"))) - -(define_attr "in_annul_branch_delay" "false,true" - (if_then_else (and (eq_attr "type" "!uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") - (eq_attr "length" "1")) + (cond [(eq_attr "type" "uncond_branch,branch,cbcond,uncond_cbcond,call,sibcall,call_no_delay_slot,multi") + (const_string "false") + (and (eq_attr "fix_ut699" "true") (eq_attr "type" "load,sload")) + (const_string "false") + (and (eq_attr "fix_ut699" "true") + (and (eq_attr "type" "fpload,fp,fpmove,fpmul,fpdivs,fpsqrts") + (ior (eq_attr "fptype" "single") + (eq_attr "fptype_ut699" "single")))) + (const_string "false") + (eq_attr "length" "1") (const_string "true") - (const_string "false"))) + ] (const_string "false"))) (define_delay (eq_attr "type" "call") [(eq_attr "in_call_delay" "true") (nil) (nil)]) (define_delay (eq_attr "type" "sibcall") - [(eq_attr "eligible_for_sibcall_delay" "true") (nil) (nil)]) + [(eq_attr "in_sibcall_delay" "true") (nil) (nil)]) + +(define_delay (eq_attr "type" "return") + [(eq_attr "in_return_delay" "true") (nil) (nil)]) (define_delay (eq_attr "type" "branch") - [(eq_attr "in_branch_delay" "true") - (nil) (eq_attr "in_annul_branch_delay" "true")]) + [(eq_attr "in_branch_delay" "true") (nil) (eq_attr "in_branch_delay" "true")]) (define_delay (eq_attr "type" "uncond_branch") - [(eq_attr "in_uncond_branch_delay" "true") - (nil) (nil)]) - -(define_delay (eq_attr "type" "return") - [(eq_attr "eligible_for_return_delay" "true") (nil) (nil)]) + [(eq_attr "in_branch_delay" "true") (nil) (nil)]) ;; Include SPARC DFA schedulers @@ -3513,7 +3503,8 @@ "TARGET_FPU" "fdtos\t%1, %0" [(set_attr "type" "fp") - (set_attr "fptype" "double")]) + (set_attr "fptype" "double") + (set_attr "fptype_ut699" "single")]) (define_expand "trunctfsf2" [(set (match_operand:SF 0 "register_operand" "") @@ -3554,7 +3545,7 @@ "TARGET_FPU" "fitos\t%1, %0" [(set_attr "type" "fp") - (set_attr "fptype" "double")]) + (set_attr "fptype" "single")]) (define_insn "floatsidf2" [(set (match_operand:DF 0 "register_operand" "=e") @@ -3641,7 +3632,7 @@ "TARGET_FPU" "fstoi\t%1, %0" [(set_attr "type" "fp") - (set_attr "fptype" "double")]) + (set_attr "fptype" "single")]) (define_insn "fix_truncdfsi2" [(set (match_operand:SI 0 "register_operand" "=f") @@ -3649,7 +3640,8 @@ "TARGET_FPU" "fdtoi\t%1, %0" [(set_attr "type" "fp") - (set_attr "fptype" "double")]) + (set_attr "fptype" "double") + (set_attr "fptype_ut699" "single")]) (define_expand "fix_trunctfsi2" [(set (match_operand:SI 0 "register_operand" "") @@ -5548,7 +5540,7 @@ [(set (match_operand:DF 0 "register_operand" "=e") (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "f")) (float_extend:DF (match_operand:SF 2 "register_operand" "f"))))] - "(TARGET_V8 || TARGET_V9) && TARGET_FPU" + "(TARGET_V8 || TARGET_V9) && TARGET_FPU && !sparc_fix_ut699" "fsmuld\t%1, %2, %0" [(set_attr "type" "fpmul") (set_attr "fptype" "double")]) @@ -5575,73 +5567,89 @@ (match_operand:TF 2 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" "fdivq\t%1, %2, %0" - [(set_attr "type" "fpdivd")]) + [(set_attr "type" "fpdivs")]) -(define_insn "divdf3" +(define_expand "divdf3" [(set (match_operand:DF 0 "register_operand" "=e") (div:DF (match_operand:DF 1 "register_operand" "e") (match_operand:DF 2 "register_operand" "e")))] "TARGET_FPU" + "") + +(define_insn "*divdf3_nofix" + [(set (match_operand:DF 0 "register_operand" "=e") + (div:DF (match_operand:DF 1 "register_operand" "e") + (match_operand:DF 2 "register_operand" "e")))] + "TARGET_FPU && !sparc_fix_ut699" "fdivd\t%1, %2, %0" [(set_attr "type" "fpdivd") (set_attr "fptype" "double")]) +(define_insn "*divdf3_fix" + [(set (match_operand:DF 0 "register_operand" "=e") + (div:DF (match_operand:DF 1 "register_operand" "e") + (match_operand:DF 2 "register_operand" "e")))] + "TARGET_FPU && sparc_fix_ut699" + "fdivd\t%1, %2, %0\n\tstd\t%0, [%%sp-8]" + [(set_attr "type" "fpdivd") + (set_attr "fptype" "double") + (set_attr "length" "2")]) + (define_insn "divsf3" [(set (match_operand:SF 0 "register_operand" "=f") (div:SF (match_operand:SF 1 "register_operand" "f") (match_operand:SF 2 "register_operand" "f")))] - "TARGET_FPU" + "TARGET_FPU && !sparc_fix_ut699" "fdivs\t%1, %2, %0" [(set_attr "type" "fpdivs")]) (define_expand "negtf2" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (neg:TF (match_operand:TF 1 "register_operand" "0,e")))] + [(set (match_operand:TF 0 "register_operand" "") + (neg:TF (match_operand:TF 1 "register_operand" "")))] "TARGET_FPU" "") -(define_insn_and_split "*negtf2_notv9" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (neg:TF (match_operand:TF 1 "register_operand" "0,e")))] - ; We don't use quad float insns here so we don't need TARGET_HARD_QUAD. - "TARGET_FPU - && ! TARGET_V9" - "@ - fnegs\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (neg:SF (match_dup 3))) - (set (match_dup 4) (match_dup 5)) - (set (match_dup 6) (match_dup 7))] - "operands[2] = gen_rtx_raw_REG (SFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (SFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (SFmode, REGNO (operands[0]) + 1); - operands[5] = gen_rtx_raw_REG (SFmode, REGNO (operands[1]) + 1); - operands[6] = gen_rtx_raw_REG (DFmode, REGNO (operands[0]) + 2); - operands[7] = gen_rtx_raw_REG (DFmode, REGNO (operands[1]) + 2);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2")]) - -(define_insn_and_split "*negtf2_v9" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (neg:TF (match_operand:TF 1 "register_operand" "0,e")))] - ; We don't use quad float insns here so we don't need TARGET_HARD_QUAD. - "TARGET_FPU && TARGET_V9" - "@ - fnegd\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (neg:DF (match_dup 3))) - (set (match_dup 4) (match_dup 5))] - "operands[2] = gen_rtx_raw_REG (DFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (DFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (DFmode, REGNO (operands[0]) + 2); - operands[5] = gen_rtx_raw_REG (DFmode, REGNO (operands[1]) + 2);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2") - (set_attr "fptype" "double")]) +(define_insn "*negtf2_hq" + [(set (match_operand:TF 0 "register_operand" "=e") + (neg:TF (match_operand:TF 1 "register_operand" "e")))] + "TARGET_FPU && TARGET_HARD_QUAD" + "fnegq\t%1, %0" + [(set_attr "type" "fpmove")]) + +(define_insn_and_split "*negtf2" + [(set (match_operand:TF 0 "register_operand" "=e") + (neg:TF (match_operand:TF 1 "register_operand" "e")))] + "TARGET_FPU && !TARGET_HARD_QUAD" + "#" + "&& reload_completed" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + dest1 = gen_df_reg (set_dest, 0); + dest2 = gen_df_reg (set_dest, 1); + src1 = gen_df_reg (set_src, 0); + src2 = gen_df_reg (set_src, 1); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (reg_overlap_mentioned_p (dest1, src2)) + { + emit_insn (gen_movdf (dest2, src2)); + emit_insn (gen_negdf2 (dest1, src1)); + } + else + { + emit_insn (gen_negdf2 (dest1, src1)); + if (REGNO (dest2) != REGNO (src2)) + emit_insn (gen_movdf (dest2, src2)); + } + DONE; +} + [(set_attr "length" "2")]) (define_expand "negdf2" [(set (match_operand:DF 0 "register_operand" "") @@ -5650,22 +5658,39 @@ "") (define_insn_and_split "*negdf2_notv9" - [(set (match_operand:DF 0 "register_operand" "=e,e") - (neg:DF (match_operand:DF 1 "register_operand" "0,e")))] - "TARGET_FPU && ! TARGET_V9" - "@ - fnegs\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (neg:SF (match_dup 3))) - (set (match_dup 4) (match_dup 5))] - "operands[2] = gen_rtx_raw_REG (SFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (SFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (SFmode, REGNO (operands[0]) + 1); - operands[5] = gen_rtx_raw_REG (SFmode, REGNO (operands[1]) + 1);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2")]) + [(set (match_operand:DF 0 "register_operand" "=e") + (neg:DF (match_operand:DF 1 "register_operand" "e")))] + "TARGET_FPU && !TARGET_V9" + "#" + "&& reload_completed" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + dest1 = gen_highpart (SFmode, set_dest); + dest2 = gen_lowpart (SFmode, set_dest); + src1 = gen_highpart (SFmode, set_src); + src2 = gen_lowpart (SFmode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (reg_overlap_mentioned_p (dest1, src2)) + { + emit_insn (gen_movsf (dest2, src2)); + emit_insn (gen_negsf2 (dest1, src1)); + } + else + { + emit_insn (gen_negsf2 (dest1, src1)); + if (REGNO (dest2) != REGNO (src2)) + emit_insn (gen_movsf (dest2, src2)); + } + DONE; +} + [(set_attr "length" "2")]) (define_insn "*negdf2_v9" [(set (match_operand:DF 0 "register_operand" "=e") @@ -5688,56 +5713,47 @@ "TARGET_FPU" "") -(define_insn_and_split "*abstf2_notv9" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (abs:TF (match_operand:TF 1 "register_operand" "0,e")))] - ; We don't use quad float insns here so we don't need TARGET_HARD_QUAD. - "TARGET_FPU && ! TARGET_V9" - "@ - fabss\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (abs:SF (match_dup 3))) - (set (match_dup 4) (match_dup 5)) - (set (match_dup 6) (match_dup 7))] - "operands[2] = gen_rtx_raw_REG (SFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (SFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (SFmode, REGNO (operands[0]) + 1); - operands[5] = gen_rtx_raw_REG (SFmode, REGNO (operands[1]) + 1); - operands[6] = gen_rtx_raw_REG (DFmode, REGNO (operands[0]) + 2); - operands[7] = gen_rtx_raw_REG (DFmode, REGNO (operands[1]) + 2);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2")]) - -(define_insn "*abstf2_hq_v9" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (abs:TF (match_operand:TF 1 "register_operand" "0,e")))] - "TARGET_FPU && TARGET_V9 && TARGET_HARD_QUAD" - "@ - fabsd\t%0, %0 - fabsq\t%1, %0" - [(set_attr "type" "fpmove") - (set_attr "fptype" "double,*")]) +(define_insn "*abstf2_hq" + [(set (match_operand:TF 0 "register_operand" "=e") + (abs:TF (match_operand:TF 1 "register_operand" "e")))] + "TARGET_FPU && TARGET_HARD_QUAD" + "fabsq\t%1, %0" + [(set_attr "type" "fpmove")]) -(define_insn_and_split "*abstf2_v9" - [(set (match_operand:TF 0 "register_operand" "=e,e") - (abs:TF (match_operand:TF 1 "register_operand" "0,e")))] - "TARGET_FPU && TARGET_V9 && !TARGET_HARD_QUAD" - "@ - fabsd\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (abs:DF (match_dup 3))) - (set (match_dup 4) (match_dup 5))] - "operands[2] = gen_rtx_raw_REG (DFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (DFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (DFmode, REGNO (operands[0]) + 2); - operands[5] = gen_rtx_raw_REG (DFmode, REGNO (operands[1]) + 2);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2") - (set_attr "fptype" "double,*")]) +(define_insn_and_split "*abstf2" + [(set (match_operand:TF 0 "register_operand" "=e") + (abs:TF (match_operand:TF 1 "register_operand" "e")))] + "TARGET_FPU && !TARGET_HARD_QUAD" + "#" + "&& reload_completed" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + dest1 = gen_df_reg (set_dest, 0); + dest2 = gen_df_reg (set_dest, 1); + src1 = gen_df_reg (set_src, 0); + src2 = gen_df_reg (set_src, 1); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (reg_overlap_mentioned_p (dest1, src2)) + { + emit_insn (gen_movdf (dest2, src2)); + emit_insn (gen_absdf2 (dest1, src1)); + } + else + { + emit_insn (gen_absdf2 (dest1, src1)); + if (REGNO (dest2) != REGNO (src2)) + emit_insn (gen_movdf (dest2, src2)); + } + DONE; +} + [(set_attr "length" "2")]) (define_expand "absdf2" [(set (match_operand:DF 0 "register_operand" "") @@ -5746,22 +5762,39 @@ "") (define_insn_and_split "*absdf2_notv9" - [(set (match_operand:DF 0 "register_operand" "=e,e") - (abs:DF (match_operand:DF 1 "register_operand" "0,e")))] - "TARGET_FPU && ! TARGET_V9" - "@ - fabss\t%0, %0 - #" - "&& reload_completed - && sparc_absnegfloat_split_legitimate (operands[0], operands[1])" - [(set (match_dup 2) (abs:SF (match_dup 3))) - (set (match_dup 4) (match_dup 5))] - "operands[2] = gen_rtx_raw_REG (SFmode, REGNO (operands[0])); - operands[3] = gen_rtx_raw_REG (SFmode, REGNO (operands[1])); - operands[4] = gen_rtx_raw_REG (SFmode, REGNO (operands[0]) + 1); - operands[5] = gen_rtx_raw_REG (SFmode, REGNO (operands[1]) + 1);" - [(set_attr "type" "fpmove,*") - (set_attr "length" "*,2")]) + [(set (match_operand:DF 0 "register_operand" "=e") + (abs:DF (match_operand:DF 1 "register_operand" "e")))] + "TARGET_FPU && !TARGET_V9" + "#" + "&& reload_completed" + [(clobber (const_int 0))] +{ + rtx set_dest = operands[0]; + rtx set_src = operands[1]; + rtx dest1, dest2; + rtx src1, src2; + + dest1 = gen_highpart (SFmode, set_dest); + dest2 = gen_lowpart (SFmode, set_dest); + src1 = gen_highpart (SFmode, set_src); + src2 = gen_lowpart (SFmode, set_src); + + /* Now emit using the real source and destination we found, swapping + the order if we detect overlap. */ + if (reg_overlap_mentioned_p (dest1, src2)) + { + emit_insn (gen_movsf (dest2, src2)); + emit_insn (gen_abssf2 (dest1, src1)); + } + else + { + emit_insn (gen_abssf2 (dest1, src1)); + if (REGNO (dest2) != REGNO (src2)) + emit_insn (gen_movsf (dest2, src2)); + } + DONE; +} + [(set_attr "length" "2")]) (define_insn "*absdf2_v9" [(set (match_operand:DF 0 "register_operand" "=e") @@ -5789,20 +5822,35 @@ (sqrt:TF (match_operand:TF 1 "register_operand" "e")))] "TARGET_FPU && TARGET_HARD_QUAD" "fsqrtq\t%1, %0" - [(set_attr "type" "fpsqrtd")]) + [(set_attr "type" "fpsqrts")]) -(define_insn "sqrtdf2" +(define_expand "sqrtdf2" [(set (match_operand:DF 0 "register_operand" "=e") (sqrt:DF (match_operand:DF 1 "register_operand" "e")))] "TARGET_FPU" + "") + +(define_insn "*sqrtdf2_nofix" + [(set (match_operand:DF 0 "register_operand" "=e") + (sqrt:DF (match_operand:DF 1 "register_operand" "e")))] + "TARGET_FPU && !sparc_fix_ut699" "fsqrtd\t%1, %0" [(set_attr "type" "fpsqrtd") (set_attr "fptype" "double")]) +(define_insn "*sqrtdf2_fix" + [(set (match_operand:DF 0 "register_operand" "=e") + (sqrt:DF (match_operand:DF 1 "register_operand" "e")))] + "TARGET_FPU && sparc_fix_ut699" + "fsqrtd\t%1, %0\n\tstd\t%0, [%%sp-8]" + [(set_attr "type" "fpsqrtd") + (set_attr "fptype" "double") + (set_attr "length" "2")]) + (define_insn "sqrtsf2" [(set (match_operand:SF 0 "register_operand" "=f") (sqrt:SF (match_operand:SF 1 "register_operand" "f")))] - "TARGET_FPU" + "TARGET_FPU && !sparc_fix_ut699" "fsqrts\t%1, %0" [(set_attr "type" "fpsqrts")]) @@ -5821,19 +5869,6 @@ } [(set_attr "type" "shift")]) -(define_insn "*ashlsi3_extend" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (ashift:SI (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "arith_operand" "rI"))))] - "TARGET_ARCH64" -{ - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - return "sll\t%1, %2, %0"; -} - [(set_attr "type" "shift")]) - (define_expand "ashldi3" [(set (match_operand:DI 0 "register_operand" "=r") (ashift:DI (match_operand:DI 1 "register_operand" "r") diff --git a/gcc-4.8/gcc/config/sparc/sparc.opt b/gcc-4.8/gcc/config/sparc/sparc.opt index 764c652e8..9de981b85 100644 --- a/gcc-4.8/gcc/config/sparc/sparc.opt +++ b/gcc-4.8/gcc/config/sparc/sparc.opt @@ -113,6 +113,10 @@ mrelax Target Optimize tail call instructions in assembler and linker +muser-mode +Target Report Mask(USER_MODE) +Do not generate code that can only run in supervisor mode + mcpu= Target RejectNegative Joined Var(sparc_cpu_and_features) Enum(sparc_processor_type) Init(PROCESSOR_V7) Use features of and schedule code for given CPU @@ -146,6 +150,9 @@ EnumValue Enum(sparc_processor_type) String(leon) Value(PROCESSOR_LEON) EnumValue +Enum(sparc_processor_type) String(leon3) Value(PROCESSOR_LEON3) + +EnumValue Enum(sparc_processor_type) String(sparclite) Value(PROCESSOR_SPARCLITE) EnumValue @@ -201,9 +208,19 @@ Target Report RejectNegative Var(sparc_fix_at697f) Enable workaround for single erratum of AT697F processor (corresponding to erratum #13 of AT697E processor) +mfix-ut699 +Target Report RejectNegative Var(sparc_fix_ut699) +Enable workarounds for the errata of the UT699 processor + Mask(LONG_DOUBLE_128) ;; Use 128-bit long double +Mask(LEON) +;; Generate code for LEON + +Mask(LEON3) +;; Generate code for LEON3 + Mask(SPARCLITE) ;; Generate code for SPARClite diff --git a/gcc-4.8/gcc/config/sparc/sync.md b/gcc-4.8/gcc/config/sparc/sync.md index 1c1b9774b..cf909853b 100644 --- a/gcc-4.8/gcc/config/sparc/sync.md +++ b/gcc-4.8/gcc/config/sparc/sync.md @@ -161,7 +161,8 @@ (match_operand:SI 5 "const_int_operand" "") ;; is_weak (match_operand:SI 6 "const_int_operand" "") ;; mod_s (match_operand:SI 7 "const_int_operand" "")] ;; mod_f - "TARGET_V9 && (<MODE>mode != DImode || TARGET_ARCH64 || TARGET_V8PLUS)" + "(TARGET_V9 || TARGET_LEON3) + && (<MODE>mode != DImode || TARGET_ARCH64 || TARGET_V8PLUS)" { sparc_expand_compare_and_swap (operands); DONE; @@ -176,7 +177,7 @@ [(match_operand:I48MODE 2 "register_operand" "") (match_operand:I48MODE 3 "register_operand" "")] UNSPECV_CAS))])] - "TARGET_V9" + "TARGET_V9 || TARGET_LEON3" "") (define_insn "*atomic_compare_and_swap<mode>_1" @@ -187,10 +188,27 @@ [(match_operand:I48MODE 2 "register_operand" "r") (match_operand:I48MODE 3 "register_operand" "0")] UNSPECV_CAS))] - "TARGET_V9 && (<MODE>mode == SImode || TARGET_ARCH64)" + "TARGET_V9 && (<MODE>mode != DImode || TARGET_ARCH64)" "cas<modesuffix>\t%1, %2, %0" [(set_attr "type" "multi")]) +(define_insn "*atomic_compare_and_swap_leon3_1" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "mem_noofs_operand" "+w")) + (set (match_dup 1) + (unspec_volatile:SI + [(match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "0")] + UNSPECV_CAS))] + "TARGET_LEON3" +{ + if (TARGET_USER_MODE) + return "casa\t%1 0xa, %2, %0"; /* ASI for user data space. */ + else + return "casa\t%1 0xb, %2, %0"; /* ASI for supervisor data space. */ +} + [(set_attr "type" "multi")]) + (define_insn "*atomic_compare_and_swapdi_v8plus" [(set (match_operand:DI 0 "register_operand" "=h") (match_operand:DI 1 "mem_noofs_operand" "+w")) @@ -220,7 +238,7 @@ (match_operand:SI 1 "memory_operand" "") (match_operand:SI 2 "register_operand" "") (match_operand:SI 3 "const_int_operand" "")] - "TARGET_V8 || TARGET_V9" + "(TARGET_V8 || TARGET_V9) && !sparc_fix_ut699" { enum memmodel model = (enum memmodel) INTVAL (operands[3]); @@ -236,7 +254,7 @@ UNSPECV_SWAP)) (set (match_dup 1) (match_operand:SI 2 "register_operand" "0"))] - "TARGET_V8 || TARGET_V9" + "(TARGET_V8 || TARGET_V9) && !sparc_fix_ut699" "swap\t%1, %0" [(set_attr "type" "multi")]) @@ -244,7 +262,7 @@ [(match_operand:QI 0 "register_operand" "") (match_operand:QI 1 "memory_operand" "") (match_operand:SI 2 "const_int_operand" "")] - "" + "!sparc_fix_ut699" { enum memmodel model = (enum memmodel) INTVAL (operands[2]); rtx ret; @@ -268,6 +286,6 @@ (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")] UNSPECV_LDSTUB)) (set (match_dup 1) (const_int -1))] - "" + "!sparc_fix_ut699" "ldstub\t%1, %0" [(set_attr "type" "multi")]) diff --git a/gcc-4.8/gcc/config/sparc/t-rtems b/gcc-4.8/gcc/config/sparc/t-rtems index 63d021770..f1a3d845e 100644 --- a/gcc-4.8/gcc/config/sparc/t-rtems +++ b/gcc-4.8/gcc/config/sparc/t-rtems @@ -17,6 +17,6 @@ # <http://www.gnu.org/licenses/>. # -MULTILIB_OPTIONS = msoft-float mcpu=v8 -MULTILIB_DIRNAMES = soft v8 +MULTILIB_OPTIONS = msoft-float mcpu=v8/mcpu=leon3 +MULTILIB_DIRNAMES = soft v8 leon3 MULTILIB_MATCHES = msoft-float=mno-fpu diff --git a/gcc-4.8/gcc/config/sparc/t-sparc b/gcc-4.8/gcc/config/sparc/t-sparc index d7b17fbd0..664f4a424 100644 --- a/gcc-4.8/gcc/config/sparc/t-sparc +++ b/gcc-4.8/gcc/config/sparc/t-sparc @@ -23,7 +23,7 @@ sparc.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ insn-codes.h conditions.h output.h $(INSN_ATTR_H) $(FLAGS_H) \ $(FUNCTION_H) $(EXCEPT_H) $(EXPR_H) $(OPTABS_H) $(RECOG_H) \ $(DIAGNOSTIC_CORE_H) $(GGC_H) $(TM_P_H) debug.h $(TARGET_H) \ - $(TARGET_DEF_H) $(COMMON_TARGET_H) $(GIMPLE_H) \ + $(TARGET_DEF_H) $(COMMON_TARGET_H) $(GIMPLE_H) $(TREE_PASS_H) \ langhooks.h reload.h $(PARAMS_H) $(DF_H) $(OPTS_H) \ gt-sparc.h |