diff options
Diffstat (limited to 'gcc/config/sh/sh.c')
-rw-r--r-- | gcc/config/sh/sh.c | 57 |
1 files changed, 45 insertions, 12 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 5dd9b6e..04b98c1 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -189,6 +189,7 @@ static void pop (int); static void push_regs (HARD_REG_SET *, int); static int calc_live_regs (HARD_REG_SET *); static HOST_WIDE_INT rounded_frame_size (int); +static bool sh_frame_pointer_required (void); static rtx mark_constant_pool_use (rtx); static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *); static tree sh_handle_resbank_handler_attribute (tree *, tree, @@ -503,6 +504,9 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_DWARF_CALLING_CONVENTION #define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention +#undef TARGET_FRAME_POINTER_REQUIRED +#define TARGET_FRAME_POINTER_REQUIRED sh_frame_pointer_required + /* Return regmode weight for insn. */ #define INSN_REGMODE_WEIGHT(INSN, MODE) regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)] @@ -666,7 +670,6 @@ sh_optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED) { if (level) { - flag_omit_frame_pointer = 2; if (!size) sh_div_str = "inv:minlat"; } @@ -856,16 +859,7 @@ sh_override_options (void) if (! VALID_REGISTER_P (ADDREGNAMES_REGNO (regno))) sh_additional_register_names[regno][0] = '\0'; - if (flag_omit_frame_pointer == 2) - { - /* The debugging information is sufficient, - but gdb doesn't implement this yet */ - if (0) - flag_omit_frame_pointer - = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); - else - flag_omit_frame_pointer = 0; - } + flag_omit_frame_pointer = (PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); if ((flag_pic && ! TARGET_PREFERGOT) || (TARGET_SHMEDIA && !TARGET_PT_FIXED)) @@ -897,6 +891,24 @@ sh_override_options (void) flag_schedule_insns = 0; } + if ((target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) == 0) + target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; + + /* Unwind info is not correct around the CFG unless either a frame + pointer is present or M_A_O_A is set. Fixing this requires rewriting + unwind info generation to be aware of the CFG and propagating states + around edges. */ + if ((flag_unwind_tables || flag_asynchronous_unwind_tables + || flag_exceptions || flag_non_call_exceptions) + && flag_omit_frame_pointer + && !(target_flags & MASK_ACCUMULATE_OUTGOING_ARGS)) + { + if (target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS) + warning (0, "unwind tables currently require either a frame pointer " + "or -maccumulate-outgoing-args for correctness"); + target_flags |= MASK_ACCUMULATE_OUTGOING_ARGS; + } + /* Unwinding with -freorder-blocks-and-partition does not work on this architecture, because it requires far jumps to label crossing between hot/cold sections which are rejected on this architecture. */ @@ -6583,6 +6595,9 @@ rounded_frame_size (int pushed) HOST_WIDE_INT size = get_frame_size (); HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; + if (ACCUMULATE_OUTGOING_ARGS) + size += crtl->outgoing_args_size; + return ((size + pushed + align - 1) & -align) - pushed; } @@ -7431,7 +7446,11 @@ sh_set_return_address (rtx ra, rtx tmp) pr_offset = rounded_frame_size (d); emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset))); - emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx)); + + if (frame_pointer_needed) + emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx)); + else + emit_insn (GEN_ADD3 (tmp, tmp, stack_pointer_rtx)); tmp = gen_frame_mem (Pmode, tmp); emit_insn (GEN_MOV (tmp, ra)); @@ -10936,6 +10955,20 @@ sh_vector_mode_supported_p (enum machine_mode mode) return false; } +bool +sh_frame_pointer_required (void) +{ +/* If needed override this in other tm.h files to cope with various OS + lossage requiring a frame pointer. */ + if (SUBTARGET_FRAME_POINTER_REQUIRED) + return true; + + if (crtl->profile) + return true; + + return false; +} + /* Implements target hook dwarf_calling_convention. Return an enum of dwarf_calling_convention. */ int |