This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]