aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/config/sparc/sparc.c118
-rw-r--r--gcc/config/sparc/sparc.md52
-rw-r--r--gcc/doc/tm.texi16
-rw-r--r--gcc/dwarf2out.c18
-rw-r--r--gcc/target-def.h3
-rw-r--r--gcc/target.h9
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);