This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Register window support in DWARF-2
- From: Eric Botcazou <ebotcazou at libertysurf dot fr>
- To: Richard Henderson <rth at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org,Jason Merrill <jason at redhat dot com>
- Date: Thu, 25 Nov 2004 13:18:09 +0100
- Subject: Re: Register window support in DWARF-2
- References: <200411240022.55423.ebotcazou@libertysurf.fr> <20041124003752.GB6028@redhat.com>
[Moved to gcc-patches]
> That, or a magic attribute, such that
>
> #ifdef HAVE_ATTR_window_save
> if (RTX_FRAME_RELATED_P (insn)
> && get_attr_window_save (insn))
> ...
> #endif
Thanks for the suggestion. This would have been more elegant, but it turned
out that this didn't fit in very well with low-level ordering constraints. So
I went for the target hook, which is set to dwarf2out_window_save.
Bootstrapped/regtested on sparc64-sun-solaris2.9 and sparc-sun-solaris2.8.
Does it look correct to you?
2004-11-25 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
hook_void_constcharptr.
(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. (TARGET_DWARF_HANDLE_FRAME_UNSPEC): Define to
dwarf2out_window_save.
(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_{inc,dec}rement.
Set RTX_FRAME_RELATED_P on the appropriate insns and members of insns.
(sparc_asm_function_prologue): Do not emit call frame debugging information.
(sparc_expand_epilogue): Adjust calls to emit_stack_pointer_{inc,dec}rement.
(emit_and_preserve): Likewise.
* config/sparc/sparc.md (save_register_window): Invoke the gen_* functions of
the following 2 patterns.
(save_register_windowdi): Rewrite modelled on the call frame debug info.
(save_register_windowsi): Likewise.
--
Eric Botcazou
Index: target.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target.h,v
retrieving revision 1.119
diff -u -p -r1.119 target.h
--- target.h 24 Nov 2004 08:39:31 -0000 1.119
+++ target.h 24 Nov 2004 20:26:11 -0000
@@ -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 *);
+
/* Functions relating to calls - argument passing, returns, etc. */
struct calls {
bool (*promote_function_args) (tree fntype);
Index: target-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/target-def.h,v
retrieving revision 1.107
diff -u -p -r1.107 target-def.h
--- target-def.h 24 Nov 2004 08:39:31 -0000 1.107
+++ target-def.h 24 Nov 2004 20:26:12 -0000
@@ -381,6 +381,8 @@ Foundation, 59 Temple Place - Suite 330,
#define TARGET_DWARF_CALLING_CONVENTION hook_int_tree_0
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC hook_void_constcharptr
+
#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,
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, \
Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.558
diff -u -p -r1.558 dwarf2out.c
--- dwarf2out.c 26 Oct 2004 06:08:38 -0000 1.558
+++ dwarf2out.c 24 Nov 2004 20:26:17 -0000
@@ -1430,7 +1430,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)
@@ -1494,7 +1498,10 @@ dwarf2out_frame_debug_expr (rtx expr, co
{
/* 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;
@@ -1621,6 +1628,13 @@ dwarf2out_frame_debug_expr (rtx expr, co
case HIGH:
break;
+ /* Rule 15 */
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
+ gcc_assert (targetm.dwarf_handle_frame_unspec);
+ targetm.dwarf_handle_frame_unspec (label);
+ break;
+
default:
gcc_unreachable ();
}
Index: config/sparc/sparc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v
retrieving revision 1.346
diff -u -p -r1.346 sparc.c
--- config/sparc/sparc.c 23 Nov 2004 00:35:26 -0000 1.346
+++ config/sparc/sparc.c 25 Nov 2004 10:41:31 -0000
@@ -480,6 +480,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 dwarf2out_window_save
+
#ifdef SUBTARGET_INSERT_ATTRIBUTES
#undef TARGET_INSERT_ATTRIBUTES
#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
@@ -4478,26 +4481,26 @@ 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 an increment for the stack pointer. */
-static void
-emit_stack_pointer_increment (rtx increment)
+static rtx
+gen_stack_pointer_inc (rtx increment)
{
if (TARGET_ARCH64)
- emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
+ return gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment);
else
- emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
+ return gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment);
}
-/* Emit a decrement for the stack pointer. */
+/* Generate a decrement for the stack pointer. */
-static void
-emit_stack_pointer_decrement (rtx decrement)
+static rtx
+gen_stack_pointer_dec (rtx decrement)
{
if (TARGET_ARCH64)
- emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
+ return gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement);
else
- emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
+ return gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement);
}
/* Expand the function prologue. The prologue is responsible for reserving
@@ -4507,6 +4510,9 @@ emit_stack_pointer_decrement (rtx decrem
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 +4562,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 +4616,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 +4631,6 @@ sparc_asm_function_prologue (FILE *file,
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 +4647,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 +8882,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
Index: config/sparc/sparc.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.md,v
retrieving revision 1.222
diff -u -p -r1.222 sparc.md
--- config/sparc/sparc.md 23 Nov 2004 00:35:30 -0000 1.222
+++ config/sparc/sparc.md 24 Nov 2004 20:26:23 -0000
@@ -7717,35 +7717,38 @@
[(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));
+ if (TARGET_ARCH64)
+ emit_insn (gen_save_register_windowdi (operands[0]));
+ else
+ emit_insn (gen_save_register_windowsi (operands[0]));
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")])
Index: doc/tm.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v
retrieving revision 1.396
diff -u -r1.396 tm.texi
--- doc/tm.texi 24 Nov 2004 08:39:34 -0000 1.396
+++ doc/tm.texi 24 Nov 2004 22:58:05 -0000
@@ -3005,6 +3005,20 @@
terminate the stack backtrace. New ports should avoid this.
@end defmac
+@deftypefn {Target Hook} void TARGET_DWARF_HANDLE_FRAME_UNSPEC (const char *@var{label})
+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
+@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.
+@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