diff options
Diffstat (limited to 'gcc-4.6/gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc-4.6/gcc/config/sparc/sparc.c | 115 |
1 files changed, 114 insertions, 1 deletions
diff --git a/gcc-4.6/gcc/config/sparc/sparc.c b/gcc-4.6/gcc/config/sparc/sparc.c index 753028f..c93c25b 100644 --- a/gcc-4.6/gcc/config/sparc/sparc.c +++ b/gcc-4.6/gcc/config/sparc/sparc.c @@ -415,6 +415,7 @@ 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 (rtx); static rtx sparc_tls_get_addr (void); @@ -568,6 +569,9 @@ static const struct default_options sparc_option_optimization_table[] = #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 @@ -4565,8 +4569,9 @@ sparc_expand_prologue (void) else if (actual_fsize <= 8192) { insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096))); - /* %sp is still the CFA register. */ RTX_FRAME_RELATED_P (insn) = 1; + + /* %sp is still the CFA register. */ insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); } @@ -4588,8 +4593,18 @@ sparc_expand_prologue (void) else if (actual_fsize <= 8192) { insn = emit_insn (gen_save_register_window (GEN_INT (-4096))); + /* %sp is not the CFA register anymore. */ emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); + + /* Make sure no %fp-based store is issued until after the frame is + established. The offset between the frame pointer and the stack + pointer is calculated relative to the value of the stack pointer + at the end of the function prologue, and moving instructions that + access the stack via the frame pointer between the instructions + that decrement the stack pointer could result in accessing the + register window save area, which is volatile. */ + emit_insn (gen_frame_blockage ()); } else { @@ -9423,6 +9438,104 @@ 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) + 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 * |