diff options
-rw-r--r-- | gcc/ChangeLog | 24 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.c | 118 | ||||
-rw-r--r-- | gcc/config/sparc/sparc.md | 52 | ||||
-rw-r--r-- | gcc/doc/tm.texi | 16 | ||||
-rw-r--r-- | gcc/dwarf2out.c | 18 | ||||
-rw-r--r-- | gcc/target-def.h | 3 | ||||
-rw-r--r-- | gcc/target.h | 9 |
7 files changed, 159 insertions, 81 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d264229..0ac278b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2004-11-26 Eric Botcazou <ebotcazou@libertysurf.fr> + + * target.h (struct gcc_target): New field 'dwarf_handle_frame_unspec'. + * target_def.h (TARGET_DWARF_HANDLE_FRAME_UNSPEC): Define to 0. + (TARGET_INITIALIZER): Add TARGET_DWARF_HANDLE_FRAME_UNSPEC. + * dwarf2out.c (dwarf2out_frame_debug_expr): Allow REG->REG move + to a fixed reg if the source is the Return Address register. + Implement new Rule 15. + * doc/tm.texi (Frame Layout): Document TARGET_DWARF_HANDLE_FRAME_UNSPEC. + * config/sparc/sparc.c (TARGET_DWARF_HANDLE_FRAME_UNSPEC): Define to + sparc_dwarf_handle_frame_unspec. + (gen_save_register_window): New function. + (emit_stack_pointer_increment): Rename into gen_stack_pointer_inc. + (emit_stack_pointer_decrement): Rename into gen_stack_pointer_dec. + (expand_prologue): Adjust calls to emit_stack_pointer_{in,de}crement. + Set RTX_FRAME_RELATED_P on the appropriate insns and members of insns. + (sparc_asm_function_prologue): Do not emit call frame debugging info. + (emit_and_preserve): Adjust calls to emit_stack_pointer_{in,de}crement. + (sparc_expand_epilogue): Likewise. + (sparc_dwarf_handle_frame_unspec): New function. + * config/sparc/sparc.md (save_register_window): Remove. + (save_register_windowdi): Rewrite modelled on the callframe debug info. + (save_register_windowsi): Likewise. + 2004-11-26 Alexandre Oliva <aoliva@redhat.com> * config/frv/frv-protos.h: Guard ifcvt functions declarations with diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 4ab98d8..b13f820 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -356,6 +356,7 @@ static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *); static bool sparc_vector_mode_supported_p (enum machine_mode); static bool sparc_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, bool); +static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int); #ifdef SUBTARGET_ATTRIBUTE_TABLE const struct attribute_spec sparc_attribute_table[]; #endif @@ -480,6 +481,9 @@ enum processor_type sparc_cpu; #undef TARGET_VECTOR_MODE_SUPPORTED_P #define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p +#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC +#define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec + #ifdef SUBTARGET_INSERT_ATTRIBUTES #undef TARGET_INSERT_ATTRIBUTES #define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES @@ -4478,26 +4482,37 @@ emit_restore_regs (void) save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_RESTORE); } -/* Emit an increment for the stack pointer. */ +/* Generate a save_register_window insn. */ -static void -emit_stack_pointer_increment (rtx increment) +static rtx +gen_save_register_window (rtx increment) { if (TARGET_ARCH64) - emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment)); + return gen_save_register_windowdi (increment); else - emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment)); + return gen_save_register_windowsi (increment); } -/* Emit a decrement for the stack pointer. */ +/* Generate an increment for the stack pointer. */ -static void -emit_stack_pointer_decrement (rtx decrement) +static rtx +gen_stack_pointer_inc (rtx increment) { if (TARGET_ARCH64) - emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement)); + return gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment); else - emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement)); + return gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment); +} + +/* Generate a decrement for the stack pointer. */ + +static rtx +gen_stack_pointer_dec (rtx decrement) +{ + if (TARGET_ARCH64) + return gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement); + else + return gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement); } /* Expand the function prologue. The prologue is responsible for reserving @@ -4507,6 +4522,9 @@ emit_stack_pointer_decrement (rtx decrement) void sparc_expand_prologue (void) { + rtx insn; + int i; + /* Compute a snapshot of current_function_uses_only_leaf_regs. Relying on the final value of the flag means deferring the prologue/epilogue expansion until just before the second scheduling pass, which is too @@ -4556,34 +4574,48 @@ sparc_expand_prologue (void) else if (sparc_leaf_function_p) { if (actual_fsize <= 4096) - emit_stack_pointer_increment (GEN_INT (- actual_fsize)); + insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize))); else if (actual_fsize <= 8192) { - emit_stack_pointer_increment (GEN_INT (-4096)); - emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize)); + insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096))); + /* %sp is still the CFA register. */ + RTX_FRAME_RELATED_P (insn) = 1; + insn + = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize))); } else { rtx reg = gen_rtx_REG (Pmode, 1); emit_move_insn (reg, GEN_INT (-actual_fsize)); - emit_stack_pointer_increment (reg); + insn = emit_insn (gen_stack_pointer_inc (reg)); + REG_NOTES (insn) = + gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, + PATTERN (gen_stack_pointer_inc (GEN_INT (-actual_fsize))), + REG_NOTES (insn)); } + + RTX_FRAME_RELATED_P (insn) = 1; } else { if (actual_fsize <= 4096) - emit_insn (gen_save_register_window (GEN_INT (-actual_fsize))); + insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize))); else if (actual_fsize <= 8192) { - emit_insn (gen_save_register_window (GEN_INT (-4096))); - emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize)); + 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))); } else { rtx reg = gen_rtx_REG (Pmode, 1); emit_move_insn (reg, GEN_INT (-actual_fsize)); - emit_insn (gen_save_register_window (reg)); + insn = emit_insn (gen_save_register_window (reg)); } + + RTX_FRAME_RELATED_P (insn) = 1; + for (i=0; i < XVECLEN (PATTERN (insn), 0); i++) + RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1; } /* Call-saved registers are saved just above the outgoing argument area. */ @@ -4596,8 +4628,7 @@ sparc_expand_prologue (void) } /* This function generates the assembly code for function entry, which boils - down to emitting the necessary .register directives. It also informs the - DWARF-2 back-end on the layout of the frame. + down to emitting the necessary .register directives. ??? Historical cruft: "On SPARC, move-double insns between fpu and cpu need an 8-byte block of memory. If any fpu reg is used in the function, we @@ -4612,29 +4643,6 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) abort(); sparc_output_scratch_registers (file); - - if (dwarf2out_do_frame () && actual_fsize) - { - char *label = dwarf2out_cfi_label (); - - /* The canonical frame address refers to the top of the frame. */ - dwarf2out_def_cfa (label, - sparc_leaf_function_p - ? STACK_POINTER_REGNUM - : HARD_FRAME_POINTER_REGNUM, - frame_base_offset); - - if (! sparc_leaf_function_p) - { - /* Note the register window save. This tells the unwinder that - it needs to restore the window registers from the previous - frame's window save area at 0(cfa). */ - dwarf2out_window_save (label); - - /* The return address (-8) is now in %i7. */ - dwarf2out_return_reg (label, 31); - } - } } /* Expand the function epilogue, either normal or part of a sibcall. @@ -4651,17 +4659,17 @@ sparc_expand_epilogue (void) else if (sparc_leaf_function_p) { if (actual_fsize <= 4096) - emit_stack_pointer_decrement (GEN_INT (- actual_fsize)); + emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize))); else if (actual_fsize <= 8192) { - emit_stack_pointer_decrement (GEN_INT (-4096)); - emit_stack_pointer_decrement (GEN_INT (4096 - actual_fsize)); + emit_insn (gen_stack_pointer_dec (GEN_INT (-4096))); + emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - actual_fsize))); } else { rtx reg = gen_rtx_REG (Pmode, 1); emit_move_insn (reg, GEN_INT (-actual_fsize)); - emit_stack_pointer_decrement (reg); + emit_insn (gen_stack_pointer_dec (reg)); } } } @@ -8886,11 +8894,11 @@ emit_and_preserve (rtx seq, rtx reg) rtx slot = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS)); - emit_stack_pointer_decrement (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)); + emit_insn (gen_stack_pointer_dec (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT))); emit_insn (gen_rtx_SET (VOIDmode, slot, reg)); emit_insn (seq); emit_insn (gen_rtx_SET (VOIDmode, reg, slot)); - emit_stack_pointer_increment (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)); + emit_insn (gen_stack_pointer_inc (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT))); } /* Output the assembler code for a thunk function. THUNK_DECL is the @@ -9153,6 +9161,18 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED) return 0; } +/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook. + This is called from dwarf2out.c to emit call frame instructions + for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */ +static void +sparc_dwarf_handle_frame_unspec (const char *label, + rtx pattern ATTRIBUTE_UNUSED, + int index ATTRIBUTE_UNUSED) +{ + gcc_assert (index == UNSPECV_SAVEW); + dwarf2out_window_save (label); +} + /* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL. We need to emit DTP-relative relocations. */ diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md index 5e5e1f6..44879c0 100644 --- a/gcc/config/sparc/sparc.md +++ b/gcc/config/sparc/sparc.md @@ -7713,39 +7713,31 @@ DONE; }) -(define_expand "save_register_window" - [(use (match_operand 0 "arith_operand" ""))] - "" -{ - rtvec vec; - - vec = gen_rtvec (2, - gen_rtx_SET (VOIDmode, - stack_pointer_rtx, - gen_rtx_PLUS (Pmode, - hard_frame_pointer_rtx, - operands[0])), - gen_rtx_UNSPEC_VOLATILE (VOIDmode, - gen_rtvec (1, const0_rtx), - UNSPECV_SAVEW)); - - emit_insn (gen_rtx_PARALLEL (VOIDmode, vec)); - DONE; -}) - -(define_insn "*save_register_windowsi" - [(set (reg:SI 14) (plus:SI (reg:SI 30) - (match_operand:SI 0 "arith_operand" "rI"))) - (unspec_volatile [(const_int 0)] UNSPECV_SAVEW)] - "! TARGET_ARCH64" +;; The "save register window" insn is modelled as follows so that the DWARF-2 +;; backend automatically emits the required call frame debugging information +;; while it is parsing it. Therefore, the pattern should not be modified +;; without first studying the impact of the changes on the debug info. +;; [(set (%fp) (%sp)) +;; (set (%sp) (unspec_volatile [(%sp) (-frame_size)] UNSPECV_SAVEW)) +;; (set (%i7) (%o7))] + +(define_insn "save_register_windowdi" + [(set (reg:DI 30) (reg:DI 14)) + (set (reg:DI 14) (unspec_volatile [(reg:DI 14) + (match_operand:DI 0 "arith_operand" "rI")] + UNSPECV_SAVEW)) + (set (reg:DI 31) (reg:DI 15))] + "TARGET_ARCH64" "save\t%%sp, %0, %%sp" [(set_attr "type" "savew")]) -(define_insn "*save_register_windowdi" - [(set (reg:DI 14) (plus:DI (reg:DI 30) - (match_operand:DI 0 "arith_operand" "rI"))) - (unspec_volatile [(const_int 0)] UNSPECV_SAVEW)] - "TARGET_ARCH64" +(define_insn "save_register_windowsi" + [(set (reg:SI 30) (reg:SI 14)) + (set (reg:SI 14) (unspec_volatile [(reg:SI 14) + (match_operand:SI 0 "arith_operand" "rI")] + UNSPECV_SAVEW)) + (set (reg:SI 31) (reg:SI 15))] + "!TARGET_ARCH64" "save\t%%sp, %0, %%sp" [(set_attr "type" "savew")]) diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 5efac06..5a044a5 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -3005,6 +3005,22 @@ someone decided it was a good idea to use that register number to terminate the stack backtrace. New ports should avoid this. @end defmac +@deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (const char *@var{label}, rtx @var{pattern}, int @var{index}) +This target hook allows the backend to emit frame-related insns that +contain UNSPECs or UNSPEC_VOLATILEs. The DWARF 2 call frame debugging +info engine will invoke it on insns of the form +@smallexample +(set (reg) (unspec [...] UNSPEC_INDEX)) +@end smallexample +and +@smallexample +(set (reg) (unspec_volatile [...] UNSPECV_INDEX)). +@end smallexample +to let the backend emit the call frame instructions. @var{label} is +the CFI label attached to the insn, @var{pattern} is the pattern of +the insn and @var{index} is @code{UNSPEC_INDEX} or @code{UNSPECV_INDEX}. +@end deftypefn + @defmac INCOMING_FRAME_SP_OFFSET A C expression whose value is an integer giving the offset, in bytes, from the value of the stack pointer register to the top of the stack diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index bd26504..96351c4 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -1441,7 +1441,11 @@ static dw_cfa_location cfa_temp; (set (mem (postinc <reg1>:cfa_temp <const_int>)) <reg2>) effects: cfa.reg = <reg1> cfa.base_offset = -cfa_temp.offset - cfa_temp.offset -= mode_size(mem) */ + cfa_temp.offset -= mode_size(mem) + + Rule 15: + (set <reg> {unspec, unspec_volatile}) + effects: target-dependent */ static void dwarf2out_frame_debug_expr (rtx expr, const char *label) @@ -1505,7 +1509,10 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) { /* Saving a register in a register. */ gcc_assert (call_used_regs [REGNO (dest)] - && !fixed_regs [REGNO (dest)]); + && (!fixed_regs [REGNO (dest)] + /* For the SPARC and its register window. */ + || DWARF_FRAME_REGNUM (REGNO (src)) + == DWARF_FRAME_RETURN_COLUMN)); queue_reg_save (label, src, dest, 0); } break; @@ -1632,6 +1639,13 @@ dwarf2out_frame_debug_expr (rtx expr, const char *label) case HIGH: break; + /* Rule 15 */ + case UNSPEC: + case UNSPEC_VOLATILE: + gcc_assert (targetm.dwarf_handle_frame_unspec); + targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1)); + break; + default: gcc_unreachable (); } diff --git a/gcc/target-def.h b/gcc/target-def.h index 0636237..344f74c 100644 --- a/gcc/target-def.h +++ b/gcc/target-def.h @@ -381,6 +381,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TARGET_DWARF_CALLING_CONVENTION hook_int_tree_0 +#define TARGET_DWARF_HANDLE_FRAME_UNSPEC 0 + #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_false #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_false #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_false @@ -525,6 +527,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. TARGET_BUILTIN_SETJMP_FRAME_VALUE, \ TARGET_MD_ASM_CLOBBERS, \ TARGET_DWARF_CALLING_CONVENTION, \ + TARGET_DWARF_HANDLE_FRAME_UNSPEC, \ TARGET_CALLS, \ TARGET_CXX, \ TARGET_HAVE_NAMED_SECTIONS, \ diff --git a/gcc/target.h b/gcc/target.h index 0c2b1b4..4927d2b 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -495,6 +495,15 @@ struct gcc_target the function is being declared as an int. */ int (* dwarf_calling_convention) (tree); + /* This target hook allows the backend to emit frame-related insns that + contain UNSPECs or UNSPEC_VOLATILEs. The call frame debugging info + engine will invoke it on insns of the form + (set (reg) (unspec [...] UNSPEC_INDEX)) + and + (set (reg) (unspec_volatile [...] UNSPECV_INDEX)) + to let the backend emit the call frame instructions. */ + void (* dwarf_handle_frame_unspec) (const char *, rtx, int); + /* Functions relating to calls - argument passing, returns, etc. */ struct calls { bool (*promote_function_args) (tree fntype); |