This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[4/7] v7: Update DWARF2
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: rguenther at suse dot de, jason at redhat dot com
- Date: Sat, 28 Jun 2008 11:19:44 -0700
- Subject: [4/7] v7: Update DWARF2
This complete rewrite from the last patch for DWARF2 stack alignment.
The change looks large since we moved reg_save and int_loc_descriptor
to differences places due to function calls and type definitions.
The real change is much smaller. The key changes are
1. Use DW_CFA_expression to restore register when stack is aligned.
2. Use DW_CFA_def_cfa_expression to define CFA when stack is aligned
and FP isn't used to save the original stack pointer.
Tested on Linux/ia32, Linux/x86-64 and Linux/x86-64.
Jason, is this OK for trunk?
Thanks.
H.J.
----
2008-06-28 Xuepeng Guo <xuepeng.guo@intel.com>
* dwarf2out.c (dw_fde_struct): Add cfa_uses_expression.
(add_cfi): Don't redefine CFA when CFA was defined with
DW_CFA_def_cfa_expression.
(reg_save): Moved before build_cfa_loc. Handle stack
alignment.
(dwarf2out_frame_debug_expr): Add rules 16-19 to handle stack
realign.
(int_loc_descriptor): Moved before output_cfa_loc.
(output_cfa_loc): Handle DW_CFA_expression.
(based_loc_descr): Update assert for stack realign.
(compute_frame_pointer_to_fb_displacement): Likewise.
diff -up ../../gcc/gcc/dwarf2out.c gcc/gcc
--- ../../gcc/gcc/dwarf2out.c 2008-06-27 08:52:44.000000000 -0700
+++ gcc/gcc/dwarf2out.c 2008-06-27 10:00:31.000000000 -0700
@@ -239,9 +239,14 @@ typedef struct dw_fde_struct GTY(())
bool dw_fde_switched_sections;
dw_cfi_ref dw_fde_cfi;
unsigned funcdef_number;
+ HOST_WIDE_INT stack_realignment;
unsigned all_throwers_are_sibcalls : 1;
unsigned nothrow : 1;
unsigned uses_eh_lsda : 1;
+ /* Whether we did stack realign in this call frame. */
+ unsigned stack_realign : 1;
+ /* Whether cfa is defined by expression. */
+ unsigned cfa_uses_expression : 1;
}
dw_fde_node;
@@ -621,6 +626,23 @@ static inline void
add_cfi (dw_cfi_ref *list_head, dw_cfi_ref cfi)
{
dw_cfi_ref *p;
+ dw_fde_ref fde = current_fde ();
+
+ /* When the CFA is defined with an expression, redefine it may lead
+ to a different CFA value. FIXME: Will the value of CFA expression
+ ever change? */
+ if (fde && fde->cfa_uses_expression)
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_def_cfa_offset_sf:
+ case DW_CFA_def_cfa:
+ case DW_CFA_def_cfa_sf:
+ return;
+ default:
+ break;
+ }
/* Find the end of the chain. */
for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
@@ -871,55 +893,6 @@ def_cfa_1 (const char *label, dw_cfa_loc
add_fde_cfi (label, cfi);
}
-/* Add the CFI for saving a register. REG is the CFA column number.
- LABEL is passed to add_fde_cfi.
- If SREG is -1, the register is saved at OFFSET from the CFA;
- otherwise it is saved in SREG. */
-
-static void
-reg_save (const char *label, unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
-{
- dw_cfi_ref cfi = new_cfi ();
-
- cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
-
- if (sreg == INVALID_REGNUM)
- {
- if (reg & ~0x3f)
- /* The register number won't fit in 6 bits, so we have to use
- the long form. */
- cfi->dw_cfi_opc = DW_CFA_offset_extended;
- else
- cfi->dw_cfi_opc = DW_CFA_offset;
-
-#ifdef ENABLE_CHECKING
- {
- /* If we get an offset that is not a multiple of
- DWARF_CIE_DATA_ALIGNMENT, there is either a bug in the
- definition of DWARF_CIE_DATA_ALIGNMENT, or a bug in the machine
- description. */
- HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
-
- gcc_assert (check_offset * DWARF_CIE_DATA_ALIGNMENT == offset);
- }
-#endif
- offset /= DWARF_CIE_DATA_ALIGNMENT;
- if (offset < 0)
- cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
-
- cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
- }
- else if (sreg == reg)
- cfi->dw_cfi_opc = DW_CFA_same_value;
- else
- {
- cfi->dw_cfi_opc = DW_CFA_register;
- cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
- }
-
- add_fde_cfi (label, cfi);
-}
-
/* Add the CFI for saving a register window. LABEL is passed to reg_save.
This CFI tells the unwinder that it needs to restore the window registers
from the previous frame's window save area.
@@ -1445,6 +1418,11 @@ static dw_cfa_location cfa_temp;
difference of the original location and cfa_store's
location (or cfa_temp's location if cfa_temp is used).
+ Rules 16-19: If AND operation happens on sp in prologue, we assume
+ stack is realigned. We will use a group of DW_OP_XXX
+ expressions to represent the location of the stored
+ register instead of CFA+offset.
+
The Rules
"{a,b}" indicates a choice of a xor b.
@@ -1538,13 +1516,38 @@ static dw_cfa_location cfa_temp;
Rule 15:
(set <reg> {unspec, unspec_volatile})
- effects: target-dependent */
+ effects: target-dependent
+
+ Rule 16:
+ (set sp (and: sp <const_int>))
+ constraints: cfa_store.reg == sp
+ effects: current_fde.stack_realign = 1
+ cfa_store.offset = 0
+
+ Rule 17:
+ (set (mem ({pre_inc, pre_dec} sp)) (mem (plus (cfa.reg) (const_int))))
+ effects: cfa_store.offset += -/+ mode_size(mem)
+
+ Rule 18:
+ (set (mem ({pre_inc, pre_dec} sp)) fp)
+ constraints: fde->stack_realign == 1
+ && cfa.reg != fp (means use drap)
+ effects: cfa_store.offset = 0
+
+ Rule 19:
+ (set (mem ({pre_inc, pre_dec} sp)) cfa.reg)
+ constraints: fde->stack_realign == 1
+ && cfa.offset == 0
+ && cfa.indirect == 0
+ && cfa.reg != HARD_FRAME_POINTER_REGNUM
+ effects: Use DW_CFA_def_cfa_expression to define cfa. */
static void
dwarf2out_frame_debug_expr (rtx expr, const char *label)
{
rtx src, dest, span;
HOST_WIDE_INT offset;
+ dw_fde_ref fde;
/* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
the PARALLEL independently. The first element is always processed if
@@ -1595,6 +1598,8 @@ dwarf2out_frame_debug_expr (rtx expr, co
src = rsi;
}
+ fde = current_fde ();
+
switch (GET_CODE (dest))
{
case REG:
@@ -1756,6 +1761,20 @@ dwarf2out_frame_debug_expr (rtx expr, co
targetm.dwarf_handle_frame_unspec (label, expr, XINT (src, 1));
return;
+ /* Rule 16 */
+ case AND:
+ /* If this AND operation happens on stack pointer in prologue,
+ we assume the stack is realigned and we extract the
+ alignment. */
+ if (fde && XEXP (src, 0) == stack_pointer_rtx)
+ {
+ gcc_assert (cfa_store.reg == REGNO (XEXP (src, 0)));
+ fde->stack_realign = 1;
+ fde->stack_realignment = INTVAL (XEXP (src, 1));
+ cfa_store.offset = 0;
+ }
+ return;
+
default:
gcc_unreachable ();
}
@@ -1764,7 +1783,6 @@ dwarf2out_frame_debug_expr (rtx expr, co
break;
case MEM:
- gcc_assert (REG_P (src));
/* Saving a register to the stack. Make sure dest is relative to the
CFA register. */
@@ -1795,10 +1813,21 @@ dwarf2out_frame_debug_expr (rtx expr, co
if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
offset = -offset;
- gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
+ gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0))
+ == STACK_POINTER_REGNUM)
&& cfa_store.reg == STACK_POINTER_REGNUM);
cfa_store.offset += offset;
+
+ /* Rule 18: If stack is aligned, we will use FP as a
+ reference to represent the address of the stored
+ regiser. */
+ if (fde
+ && fde->stack_realign
+ && cfa.reg != HARD_FRAME_POINTER_REGNUM
+ && src == hard_frame_pointer_rtx)
+ cfa_store.offset = 0;
+
if (cfa.reg == STACK_POINTER_REGNUM)
cfa.offset = cfa_store.offset;
@@ -1867,6 +1896,33 @@ dwarf2out_frame_debug_expr (rtx expr, co
if (cfa.offset == 0)
{
+ /* Rule 19 */
+ /* If stack is aligned, putting CFA reg into stack means
+ we can no longer use reg + offset to represent CFA.
+ Here we use DW_CFA_def_cfa_expression instead. The
+ result of this expression equals to the original CFA
+ value. */
+ if (fde
+ && fde->stack_realign
+ && cfa.indirect == 0
+ && cfa.reg != HARD_FRAME_POINTER_REGNUM)
+ {
+ dw_cfa_location cfa_uses_expression;
+
+ cfa_uses_expression.indirect = 1;
+ cfa_uses_expression.reg = HARD_FRAME_POINTER_REGNUM;
+ cfa_uses_expression.base_offset = offset;
+ cfa_uses_expression.offset = 0;
+
+ def_cfa_1 (label, &cfa_uses_expression);
+
+ fde->cfa_uses_expression = 1;
+
+ queue_reg_save (label, stack_pointer_rtx, NULL_RTX,
+ offset);
+ break;
+ }
+
/* If the source register is exactly the CFA, assume
we're saving SP like any other register; this happens
on the ARM. */
@@ -1891,6 +1947,12 @@ dwarf2out_frame_debug_expr (rtx expr, co
break;
}
}
+ /* Rule 17 */
+ /* If the source operand of this MEM operation is not a
+ register, basically the source is return address. Here
+ we only care how much stack grew and we don't save it. */
+ if (!REG_P (src))
+ break;
def_cfa_1 (label, &cfa);
{
@@ -3548,6 +3610,45 @@ output_loc_sequence (dw_loc_descr_ref lo
}
}
+/* Return a location descriptor that designates a constant. */
+
+static dw_loc_descr_ref
+int_loc_descriptor (HOST_WIDE_INT i)
+{
+ enum dwarf_location_atom op;
+
+ /* Pick the smallest representation of a constant, rather than just
+ defaulting to the LEB encoding. */
+ if (i >= 0)
+ {
+ if (i <= 31)
+ op = DW_OP_lit0 + i;
+ else if (i <= 0xff)
+ op = DW_OP_const1u;
+ else if (i <= 0xffff)
+ op = DW_OP_const2u;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i <= 0xffffffff)
+ op = DW_OP_const4u;
+ else
+ op = DW_OP_constu;
+ }
+ else
+ {
+ if (i >= -0x80)
+ op = DW_OP_const1s;
+ else if (i >= -0x8000)
+ op = DW_OP_const2s;
+ else if (HOST_BITS_PER_WIDE_INT == 32
+ || i >= -0x80000000)
+ op = DW_OP_const4s;
+ else
+ op = DW_OP_consts;
+ }
+
+ return new_loc_descr (op, i, 0);
+}
+
/* This routine will generate the correct assembly data for a location
description based on a cfi entry with a complex address. */
@@ -3557,6 +3658,9 @@ output_cfa_loc (dw_cfi_ref cfi)
dw_loc_descr_ref loc;
unsigned long size;
+ if (cfi->dw_cfi_opc == DW_CFA_expression)
+ dw2_asm_output_data (1, cfi->dw_cfi_oprnd2.dw_cfi_reg_num, NULL);
+
/* Output the size of the block. */
loc = cfi->dw_cfi_oprnd1.dw_cfi_loc;
size = size_of_locs (loc);
@@ -3566,6 +3670,93 @@ output_cfa_loc (dw_cfi_ref cfi)
output_loc_sequence (loc);
}
+/* Add the CFI for saving a register. REG is the CFA column number.
+ LABEL is passed to add_fde_cfi.
+ If SREG is -1, the register is saved at OFFSET from the CFA;
+ otherwise it is saved in SREG. */
+
+static void
+reg_save (const char *label, unsigned int reg, unsigned int sreg,
+ HOST_WIDE_INT offset)
+{
+ dw_cfi_ref cfi = new_cfi ();
+ dw_fde_ref fde = current_fde ();
+
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+ /* When stack is aligned, store REG using DW_CFA_expression with
+ FP. */
+ if (fde
+ && fde->stack_realign
+ && sreg == INVALID_REGNUM)
+ {
+ struct dw_loc_descr_struct *head, *tmp;
+ unsigned int dwarf_fp
+ = DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM);
+
+ cfi->dw_cfi_opc = DW_CFA_expression;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = reg;
+
+ /* When CFA is defined as FP+OFFSET, emulate stack alignment. */
+ if (cfa.reg == HARD_FRAME_POINTER_REGNUM
+ && cfa.indirect == 0)
+ {
+ if (dwarf_fp <= 31)
+ head = tmp = new_loc_descr (DW_OP_breg0 + dwarf_fp, 0, 0);
+ else
+ head = tmp = new_loc_descr (DW_OP_bregx, dwarf_fp, 0);
+
+ tmp = tmp->dw_loc_next
+ = int_loc_descriptor (fde->stack_realignment);
+ tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_and, 0, 0);
+
+ tmp = tmp->dw_loc_next = int_loc_descriptor (offset);
+ tmp = tmp->dw_loc_next = new_loc_descr (DW_OP_plus, 0, 0);
+ }
+ else if (dwarf_fp <= 31)
+ head = tmp = new_loc_descr (DW_OP_breg0 + dwarf_fp, offset, 0);
+ else
+ head = tmp = new_loc_descr (DW_OP_bregx, dwarf_fp, offset);
+
+ cfi->dw_cfi_oprnd1.dw_cfi_loc = head;
+ }
+ else if (sreg == INVALID_REGNUM)
+ {
+ if (reg & ~0x3f)
+ /* The register number won't fit in 6 bits, so we have to use
+ the long form. */
+ cfi->dw_cfi_opc = DW_CFA_offset_extended;
+ else
+ cfi->dw_cfi_opc = DW_CFA_offset;
+
+#ifdef ENABLE_CHECKING
+ {
+ /* If we get an offset that is not a multiple of
+ DWARF_CIE_DATA_ALIGNMENT, there is either a bug in the
+ definition of DWARF_CIE_DATA_ALIGNMENT, or a bug in the machine
+ description. */
+ HOST_WIDE_INT check_offset = offset / DWARF_CIE_DATA_ALIGNMENT;
+
+ gcc_assert (check_offset * DWARF_CIE_DATA_ALIGNMENT == offset);
+ }
+#endif
+ offset /= DWARF_CIE_DATA_ALIGNMENT;
+ if (offset < 0)
+ cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
+
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+ }
+ else if (sreg == reg)
+ cfi->dw_cfi_opc = DW_CFA_same_value;
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_register;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+ }
+
+ add_fde_cfi (label, cfi);
+}
+
/* This function builds a dwarf location descriptor sequence from a
dw_cfa_location, adding the given OFFSET to the result of the
expression. */
@@ -4284,7 +4475,6 @@ static dw_loc_descr_ref one_reg_loc_desc
enum var_init_status);
static dw_loc_descr_ref multiple_reg_loc_descriptor (rtx, rtx,
enum var_init_status);
-static dw_loc_descr_ref int_loc_descriptor (HOST_WIDE_INT);
static dw_loc_descr_ref based_loc_descr (rtx, HOST_WIDE_INT,
enum var_init_status);
static int is_based_loc (const_rtx);
@@ -8971,45 +9161,6 @@ multiple_reg_loc_descriptor (rtx rtl, rt
return loc_result;
}
-/* Return a location descriptor that designates a constant. */
-
-static dw_loc_descr_ref
-int_loc_descriptor (HOST_WIDE_INT i)
-{
- enum dwarf_location_atom op;
-
- /* Pick the smallest representation of a constant, rather than just
- defaulting to the LEB encoding. */
- if (i >= 0)
- {
- if (i <= 31)
- op = DW_OP_lit0 + i;
- else if (i <= 0xff)
- op = DW_OP_const1u;
- else if (i <= 0xffff)
- op = DW_OP_const2u;
- else if (HOST_BITS_PER_WIDE_INT == 32
- || i <= 0xffffffff)
- op = DW_OP_const4u;
- else
- op = DW_OP_constu;
- }
- else
- {
- if (i >= -0x80)
- op = DW_OP_const1s;
- else if (i >= -0x8000)
- op = DW_OP_const2s;
- else if (HOST_BITS_PER_WIDE_INT == 32
- || i >= -0x80000000)
- op = DW_OP_const4s;
- else
- op = DW_OP_consts;
- }
-
- return new_loc_descr (op, i, 0);
-}
-
/* Return a location descriptor that designates a base+offset location. */
static dw_loc_descr_ref
@@ -9034,8 +9185,12 @@ based_loc_descr (rtx reg, HOST_WIDE_INT
offset += INTVAL (XEXP (elim, 1));
elim = XEXP (elim, 0);
}
- gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
+ gcc_assert ((SUPPORTS_STACK_ALIGNMENT
+ && (elim == hard_frame_pointer_rtx
+ || elim == stack_pointer_rtx))
+ || elim == (frame_pointer_needed
+ ? hard_frame_pointer_rtx
+ : stack_pointer_rtx));
offset += frame_pointer_fb_offset;
return new_loc_descr (DW_OP_fbreg, offset, 0);
@@ -11088,8 +11243,13 @@ compute_frame_pointer_to_fb_displacement
offset += INTVAL (XEXP (elim, 1));
elim = XEXP (elim, 0);
}
- gcc_assert (elim == (frame_pointer_needed ? hard_frame_pointer_rtx
- : stack_pointer_rtx));
+
+ gcc_assert ((SUPPORTS_STACK_ALIGNMENT
+ && (elim == hard_frame_pointer_rtx
+ || elim == stack_pointer_rtx))
+ || elim == (frame_pointer_needed
+ ? hard_frame_pointer_rtx
+ : stack_pointer_rtx));
frame_pointer_fb_offset = -offset;
}