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]

PATCH: Comment dwarf2out.c and Fix -O3 -g Error


When trying to fix mips-sgi-irix6.5 gcc compilation errors occurring
with "-O3 -fomit-frame-pointer" and "-O3 -g", Mark Mitchell and I
discovered that the generated MIPS prologue code did not match the
assumptions that gcc/dwarf2out.c:dwarf2out_frame_debug_expr() was
making.  Thus, I documented the function, making a slight
generalization that resolved the compilation error.

Documentation for RTX_FRAME_RELATED_P was also improved during our
investigations.

This is joint work with Mark Mitchell (mark@codesourcery.com).  Thanks
to Jason Merrill (jason@redhat.com) for assistance.  All mistakes are,
of course, mine.

2001-02-01  Jeffrey Oldham  <oldham@codesourcery.com>

        * dwarf2out.c: Added explanation of abbreviations.
        (def_cfa_1): Added comments listing DWARF2 instructions.
        (cfa_temp_reg): Removed in favor of cfa_temp.
        (cfa_temp_value): Removed in favor of cfa_temp.
        (cfa_temp): New global variable.
        (dwarf2out_frame_debug_expr): Added extensive introductory
        comments explaining the function's transformations.  Revised to
        use cfa_temp.  Added some rtx checking.  Generalize IOR case.
        (dwarf2out_frame_debug): Revised to use cfa_temp.
        (output_aranges): Cast as "unsigned" to avoid warning.
        * rtl.texi (RTX_FRAME_RELATED_P): Revise entry to emphasize better
        explain which instructions must be marked.

Tested on       mips-sgi-irix6.5 and i686-pc-linux-gnu
Approved by     Mark Mitchell (mark@codesourcery.com)

Thanks,
Jeffrey D. Oldham
oldham@codesourcery.com
Index: dwarf2out.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/dwarf2out.c,v
retrieving revision 1.237
diff -c -p -r1.237 dwarf2out.c
*** dwarf2out.c	2001/01/28 01:50:05	1.237
--- dwarf2out.c	2001/02/02 05:51:03
*************** Boston, MA 02111-1307, USA.  */
*** 55,60 ****
--- 55,78 ----
  #include "md5.h"
  #include "tm_p.h"
  
+ /* DWARF2 Abbreviation Glossary:
+    CFA = Canonical Frame Address
+ 	   stack address identifying a stack call frame; its value is
+ 	   the value of the stack pointer just before the call to the
+ 	   current function
+    CFI = Canonical Frame Instruction
+            information describing entries in a stack call frame, e.g.,
+ 	   CIE and FDE
+    CIE = Common Information Entry
+ 	   information describing information common to one or more FDEs
+    DIE = Debugging Information Entry
+    FDE = Frame Description Entry
+ 	   information describing the stack call frame, in particular,
+ 	   how to restore registers
+ 
+    DW_CFA_... = DWARF2 CFA call frame instruction
+    DW_TAG_... = DWARF2 DIE tag */
+ 
  /* Decide whether we want to emit frame unwind information for the current
     translation unit.  */
  
*************** dwarf2out_def_cfa (label, reg, offset)
*** 855,861 ****
    def_cfa_1 (label, &loc);
  }
  
! /* This routine does the actual work. The CFA is now calculated from
     the dw_cfa_location structure.  */
  static void
  def_cfa_1 (label, loc_p)
--- 873,879 ----
    def_cfa_1 (label, &loc);
  }
  
! /* This routine does the actual work.  The CFA is now calculated from
     the dw_cfa_location structure.  */
  static void
  def_cfa_1 (label, loc_p)
*************** def_cfa_1 (label, loc_p)
*** 879,884 ****
--- 897,904 ----
      {
        if (loc.indirect == 0
  	  || loc.base_offset == old_cfa.base_offset)
+ 	/* Nothing changed so no need to issue any call frame
+            instructions.  */
  	return;
      }
  
*************** def_cfa_1 (label, loc_p)
*** 886,891 ****
--- 906,914 ----
  
    if (loc.reg == old_cfa.reg && !loc.indirect)
      {
+       /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction,
+ 	 indicating the CFA register did not change but the offset
+ 	 did.  */
        cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
        cfi->dw_cfi_oprnd1.dw_cfi_offset = loc.offset;
      }
*************** def_cfa_1 (label, loc_p)
*** 894,899 ****
--- 917,925 ----
    else if (loc.offset == old_cfa.offset && old_cfa.reg != (unsigned long) -1
  	   && !loc.indirect)
      {
+       /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
+ 	 indicating the CFA register has changed to <register> but the
+ 	 offset has not changed.  */
        cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
        cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
      }
*************** def_cfa_1 (label, loc_p)
*** 901,912 ****
--- 927,944 ----
  
    else if (loc.indirect == 0)
      {
+       /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
+ 	 indicating the CFA register has changed to <register> with
+ 	 the specified offset.  */
        cfi->dw_cfi_opc = DW_CFA_def_cfa;
        cfi->dw_cfi_oprnd1.dw_cfi_reg_num = loc.reg;
        cfi->dw_cfi_oprnd2.dw_cfi_offset = loc.offset;
      }
    else
      {
+       /* Construct a DW_CFA_def_cfa_expression instruction to
+ 	 calculate the CFA using a full location expression since no
+ 	 register-offset pair is available.  */
        struct dw_loc_descr_struct *loc_list;
        cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
        loc_list = build_cfa_loc (&loc);
*************** dwarf2out_stack_adjust (insn)
*** 1237,1252 ****
    dwarf2out_args_size (label, args_size);
  }
  
! /* A temporary register used in adjusting SP or setting up the store_reg.  */
! static unsigned cfa_temp_reg;
  
- /* A temporary value used in adjusting SP or setting up the store_reg.  */
- static long cfa_temp_value;
- 
- /* Record call frame debugging information for an expression, which either
-    sets SP or FP (adjusting how we calculate the frame address) or saves a
-    register to the stack.  */
- 
  static void
  dwarf2out_frame_debug_expr (expr, label)
       rtx expr;
--- 1269,1401 ----
    dwarf2out_args_size (label, args_size);
  }
  
! /* A temporary register holding an integral value used in adjusting SP
!    or setting up the store_reg.  The "offset" field holds the integer
!    value, not an offset.  */
! dw_cfa_location cfa_temp;
! 
! /* Record call frame debugging information for an expression EXPR,
!    which either sets SP or FP (adjusting how we calculate the frame
!    address) or saves a register to the stack.  LABEL indicates the
!    address of EXPR.
! 
!    This function encodes a state machine mapping rtxes to actions on
!    cfa, cfa_store, and cfa_temp.reg.  We describe these rules so
!    users need not read the source code.
! 
!   Invariants / Summaries of Rules
! 
!   cfa	       current register used to calculate the DWARF2 canonical
! 	       frame address register and offset
!   cfa_store    register used by prologue code to save things to the stack
! 	       cfa_store.offset is the offset from the value of
! 	       cfa_store.reg to the actual CFA
!   cfa_temp     register holding an integral value.  cfa_temp.offset
! 	       stores the value, which will be used to adjust the
! 	       stack pointer.
!  
!   Rules  1- 4: Setting a register's value to cfa.reg or an expression
!   	       with cfa.reg as the first operand changes the cfa.reg and its
! 	       cfa.offset.
! 	       (For an unknown reason, Rule 4 does not fully obey the
! 	       invariant.)
! 
!   Rules  6- 9: Set a non-cfa.reg register value to a constant or an
! 	       expression yielding a constant.  This sets cfa_temp.reg
! 	       and cfa_temp.offset.
! 
!   Rule 5:      Create a new register cfa_store used to save items to the
! 	       stack.
! 
!   Rules 10-13: Save a register to the stack.  Record the location in
! 	       cfa_store.offset.  Define offset as the difference of
! 	       the original location and cfa_store's location.
! 
!   The Rules
! 
!   "{a,b}" indicates a choice of a xor b.
!   "<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
! 
!   Rule 1:
!   (set <reg1> <reg2>:cfa.reg)
!   effects: cfa.reg = <REG1>
!            cfa.offset unchanged
! 
!   Rule 2:
!   (set sp ({minus,plus} {sp,fp}:cfa.reg {<const_int>,<reg>:cfa_temp.reg}))
!   effects: cfa.reg = sp if fp used
!  	   cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
! 	   cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
! 	     if cfa_store.reg==sp
! 
!   Rule 3:
!   (set fp ({minus,plus} <reg>:cfa.reg <const_int>))
!   effects: cfa.reg = fp
!   	   cfa_offset += +/- <const_int>
! 
!   Rule 4:
!   (set <reg1> (plus <reg2>:cfa.reg <const_int>))
!   constraints: <reg1> != fp
!   	       <reg1> != sp
!   effects: cfa.reg = <reg1>
!   questions: Where is <const_int> used?
! 	     Should cfa.offset be changed?
! 
!   Rule 5:
!   (set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
!   constraints: <reg1> != fp
!   	       <reg1> != sp
!   effects: cfa_store.reg = <reg1>
!   	   cfa_store.offset = cfa.offset - cfa_temp.offset
! 
!   Rule 6:
!   (set <reg> <const_int>)
!   effects: cfa_temp.reg = <reg>
!   	   cfa_temp.offset = <const_int>
! 
!   Rule 7:
!   (set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
!   effects: cfa_temp.reg = <reg1>
! 	   cfa_temp.offset |= <const_int>
! 
!   Rule 8:
!   (set <reg> (high <exp>))
!   effects: none
! 
!   Rule 9:
!   (set <reg> (lo_sum <exp> <const_int>))
!   effects: cfa_temp.reg = <reg>
!   	   cfa_temp.offset = <const_int>
! 
!   Rule 10:
!   (set (mem (pre_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
!   effects: cfa_store.offset -= <const_int>
! 	   cfa.offset = cfa_store.offset if cfa.reg == sp
! 	   offset = -cfa_store.offset
! 	   cfa.reg = sp
! 	   cfa.base_offset = offset
! 
!   Rule 11:
!   (set (mem ({pre_inc,pre_dec} sp:cfa_store.reg)) <reg>)
!   effects: cfa_store.offset += -/+ mode_size(mem)
! 	   cfa.offset = cfa_store.offset if cfa.reg == sp
! 	   offset = -cfa_store.offset
! 	   cfa.reg = sp
! 	   cfa.base_offset = offset
! 
!   Rule 12:
!   (set (mem ({minus,plus} <reg1>:cfa_store <const_int>)) <reg2>)
!   effects: cfa_store.offset += -/+ <const_int>
! 	   offset = -cfa_store.offset
! 	   cfa.reg = <reg1
! 	   cfa.base_offset = offset
! 
!   Rule 13:
!   (set (mem <reg1>:cfa_store) <reg2>)
!   effects: offset = -cfa_store.offset
! 	   cfa.reg = <reg1>
! 	   cfa.base_offset = offset */
  
  static void
  dwarf2out_frame_debug_expr (expr, label)
       rtx expr;
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1257,1263 ****
  
    /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
       the PARALLEL independently. The first element is always processed if
!      it is a SET. This is for backward compatability.   Other elements
       are processed only if they are SETs and the RTX_FRAME_RELATED_P
       flag is set in them.  */
  
--- 1406,1412 ----
  
    /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
       the PARALLEL independently. The first element is always processed if
!      it is a SET. This is for backward compatibility.   Other elements
       are processed only if they are SETs and the RTX_FRAME_RELATED_P
       flag is set in them.  */
  
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1287,1292 ****
--- 1436,1442 ----
    switch (GET_CODE (dest))
      {
      case REG:
+       /* Rule 1 */
        /* Update the CFA rule wrt SP or FP.  Make sure src is
           relative to the current CFA register.  */
        switch (GET_CODE (src))
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1310,1315 ****
--- 1460,1466 ----
  	case MINUS:
  	  if (dest == stack_pointer_rtx)
  	    {
+ 	      /* Rule 2 */
  	      /* Adjusting SP.  */
  	      switch (GET_CODE (XEXP (src, 1)))
  		{
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1317,1325 ****
  		  offset = INTVAL (XEXP (src, 1));
  		  break;
  		case REG:
! 		  if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp_reg)
  		    abort ();
! 		  offset = cfa_temp_value;
  		  break;
  		default:
  		  abort ();
--- 1468,1476 ----
  		  offset = INTVAL (XEXP (src, 1));
  		  break;
  		case REG:
! 		  if ((unsigned) REGNO (XEXP (src, 1)) != cfa_temp.reg)
  		    abort ();
! 		  offset = cfa_temp.offset;
  		  break;
  		default:
  		  abort ();
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1344,1349 ****
--- 1495,1501 ----
  	    }
  	  else if (dest == hard_frame_pointer_rtx)
  	    {
+ 	      /* Rule 3 */
  	      /* Either setting the FP from an offset of the SP,
  		 or adjusting the FP */
  	      if (! frame_pointer_needed)
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1367,1405 ****
  	      if (GET_CODE (src) != PLUS)
  		abort ();
  
  	      if (GET_CODE (XEXP (src, 0)) == REG
  		  && REGNO (XEXP (src, 0)) == cfa.reg
  		  && GET_CODE (XEXP (src, 1)) == CONST_INT)
  		/* Setting the FP (or a scratch that will be copied into the FP
  		   later on) from SP + const.  */
  		cfa.reg = REGNO (dest);
  	      else
  		{
  		  if (XEXP (src, 1) != stack_pointer_rtx)
  		    abort ();
  		  if (GET_CODE (XEXP (src, 0)) != REG
! 		      || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg)
  		    abort ();
  		  if (cfa.reg != STACK_POINTER_REGNUM)
  		    abort ();
  		  cfa_store.reg = REGNO (dest);
! 		  cfa_store.offset = cfa.offset - cfa_temp_value;
  		}
  	    }
  	  break;
  
  	case CONST_INT:
! 	  cfa_temp_reg = REGNO (dest);
! 	  cfa_temp_value = INTVAL (src);
  	  break;
  
  	case IOR:
  	  if (GET_CODE (XEXP (src, 0)) != REG
! 	      || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp_reg
! 	      || (unsigned) REGNO (dest) != cfa_temp_reg
  	      || GET_CODE (XEXP (src, 1)) != CONST_INT)
  	    abort ();
! 	  cfa_temp_value |= INTVAL (XEXP (src, 1));
  	  break;
  
  	default:
--- 1519,1562 ----
  	      if (GET_CODE (src) != PLUS)
  		abort ();
  
+ 	      /* Rule 4 */
  	      if (GET_CODE (XEXP (src, 0)) == REG
  		  && REGNO (XEXP (src, 0)) == cfa.reg
  		  && GET_CODE (XEXP (src, 1)) == CONST_INT)
  		/* Setting the FP (or a scratch that will be copied into the FP
  		   later on) from SP + const.  */
  		cfa.reg = REGNO (dest);
+ 	      /* Rule 5 */
  	      else
  		{
  		  if (XEXP (src, 1) != stack_pointer_rtx)
  		    abort ();
  		  if (GET_CODE (XEXP (src, 0)) != REG
!  		      || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg)
  		    abort ();
  		  if (cfa.reg != STACK_POINTER_REGNUM)
  		    abort ();
  		  cfa_store.reg = REGNO (dest);
! 		  cfa_store.offset = cfa.offset - cfa_temp.offset;
  		}
  	    }
  	  break;
  
+ 	  /* Rule 6 */
  	case CONST_INT:
! 	  cfa_temp.reg = REGNO (dest);
! 	  cfa_temp.offset = INTVAL (src);
  	  break;
  
+ 	  /* Rule 7 */
  	case IOR:
  	  if (GET_CODE (XEXP (src, 0)) != REG
! 	      || (unsigned) REGNO (XEXP (src, 0)) != cfa_temp.reg
  	      || GET_CODE (XEXP (src, 1)) != CONST_INT)
  	    abort ();
! 	  if ((unsigned) REGNO (dest) != cfa_temp.reg)
! 	    cfa_temp.reg = REGNO (dest);
! 	  cfa_temp.offset |= INTVAL (XEXP (src, 1));
  	  break;
  
  	default:
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1410,1421 ****
  
        /* Skip over HIGH, assuming it will be followed by a LO_SUM, which
  	 will fill in all of the bits.  */
      case HIGH:
        break;
  
      case LO_SUM:
!       cfa_temp_reg = REGNO (dest);
!       cfa_temp_value = INTVAL (XEXP (src, 1));
        break;
  
      case MEM:
--- 1567,1582 ----
  
        /* Skip over HIGH, assuming it will be followed by a LO_SUM, which
  	 will fill in all of the bits.  */
+       /* Rule 8 */
      case HIGH:
        break;
  
+       /* Rule 9 */
      case LO_SUM:
!       if (GET_CODE (XEXP (src, 1)) != CONST_INT)
! 	abort ();
!       cfa_temp.reg = REGNO (dest);
!       cfa_temp.offset = INTVAL (XEXP (src, 1));
        break;
  
      case MEM:
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1426,1431 ****
--- 1587,1593 ----
  	 CFA register.  */
        switch (GET_CODE (XEXP (dest, 0)))
  	{
+ 	  /* Rule 10 */
  	  /* With a push.  */
  	case PRE_MODIFY:
  	  /* We can't handle variable size modifications.  */
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1442,1447 ****
--- 1604,1610 ----
  
  	  offset = -cfa_store.offset;
  	  break;
+ 	  /* Rule 11 */
  	case PRE_INC:
  	case PRE_DEC:
  	  offset = GET_MODE_SIZE (GET_MODE (dest));
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1458,1466 ****
--- 1621,1632 ----
  	  offset = -cfa_store.offset;
  	  break;
  
+ 	  /* Rule 12 */
  	  /* With an offset.  */
  	case PLUS:
  	case MINUS:
+ 	  if (GET_CODE (XEXP (XEXP (dest, 0), 1)) != CONST_INT)
+ 	    abort ();
  	  offset = INTVAL (XEXP (XEXP (dest, 0), 1));
  	  if (GET_CODE (XEXP (dest, 0)) == MINUS)
  	    offset = -offset;
*************** dwarf2out_frame_debug_expr (expr, label)
*** 1470,1475 ****
--- 1636,1642 ----
  	  offset -= cfa_store.offset;
  	  break;
  
+ 	  /* Rule 13 */
  	  /* Without an offset.  */
  	case REG:
  	  if (cfa_store.reg != (unsigned) REGNO (XEXP (dest, 0)))
*************** dwarf2out_frame_debug (insn)
*** 1543,1550 ****
  	abort ();
        cfa.reg = STACK_POINTER_REGNUM;
        cfa_store = cfa;
!       cfa_temp_reg = -1;
!       cfa_temp_value = 0;
        return;
      }
  
--- 1710,1717 ----
  	abort ();
        cfa.reg = STACK_POINTER_REGNUM;
        cfa_store = cfa;
!       cfa_temp.reg = -1;
!       cfa_temp.offset = 0;
        return;
      }
  
*************** output_aranges ()
*** 6356,6362 ****
        /* Pad using a 2 bytes word so that padding is correct
           for any pointer size.  */
        ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0);
!       for (i = 2; i < DWARF_ARANGES_PAD_SIZE; i += 2)
  	fprintf (asm_out_file, ",0");
        if (flag_debug_asm)
  	fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
--- 6523,6529 ----
        /* Pad using a 2 bytes word so that padding is correct
           for any pointer size.  */
        ASM_OUTPUT_DWARF_DATA2 (asm_out_file, 0);
!       for (i = 2; i < (unsigned) DWARF_ARANGES_PAD_SIZE; i += 2)
  	fprintf (asm_out_file, ",0");
        if (flag_debug_asm)
  	fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
Index: rtl.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/rtl.texi,v
retrieving revision 1.34
diff -c -p -r1.34 rtl.texi
*** rtl.texi	2001/01/22 16:58:08	1.34
--- rtl.texi	2001/02/02 05:51:06
*************** Stored in the @code{integrated} field an
*** 458,467 ****
  
  @findex RTX_FRAME_RELATED_P
  @item RTX_FRAME_RELATED_P (@var{x})
! Nonzero in an insn or expression which is part of a function
! prologue and sets the stack pointer, sets the frame pointer, or saves a 
! register. This flag is required for exception handling support
! on targets with RTL prologues.
  
  @findex SYMBOL_REF_USED
  @cindex @code{used}, in @code{symbol_ref}
--- 458,486 ----
  
  @findex RTX_FRAME_RELATED_P
  @item RTX_FRAME_RELATED_P (@var{x})
! Nonzero in an insn or expression which is part of a function prologue
! and sets the stack pointer, sets the frame pointer, or saves a register.
! This flag should also be set on an instruction that sets up a temporary
! register to use in place of the frame pointer.
! 
! In particular, on RISC targets where there are limits on the sizes of
! immediate constants, it is sometimes impossible to reach the register
! save area directly from the stack pointer.  In that case, a temporary
! register is used that is near enough to the register save area, and the
! Canonical Frame Address, i.e., DWARF2's logical frame pointer, register
! must (temporarily) be changed to be this temporary register.  So, the
! instruction that sets this temporary register must be marked as
! @code{RTX_FRAME_RELATED_P}.
! 
! If the marked instruction is overly complex (defined in terms of what
! @code{dwarf2out_frame_debug_expr} can handle), you will also have to
! create a @code{REG_FRAME_RELATED_EXPR} note and attach it to the
! instruction.  This note should contain a simple expression of the
! computation performed by this instruction, i.e., one that
! @code{dwarf2out_frame_debug_expr} can handle.
! 
! This flag is required for exception handling support on targets with RTL
! prologues.
  
  @findex SYMBOL_REF_USED
  @cindex @code{used}, in @code{symbol_ref}

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