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]

Re: [RFA patch] PR18749: epilogue not tracked in dwarf2 unwind-info


Daniel Jacobowitz wrote:
> On Mon, Jun 12, 2006 at 10:07:40PM +0200, Michael Matz wrote:
> > Hi,
> > 
> > I'm trying to fix PR18749, which is about the fact that dwarf2out.c 
> > doesn't look at epilogues at all, which makes the CFA be wrong during the 
> > epilogue, as no adjustments there (like pops, or additions to the stack 
> > pointer) are tracked.
> 
> Just FYI, there's also:
>   http://gcc.gnu.org/ml/gcc-patches/2006-02/msg01091.html

If you're interested in yet another attempt, here's a version I've been
working on a couple of years ago, but never got around to cleaning up
for submitting  ...

Bye,
Ulrich


Index: gcc/cfglayout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfglayout.c,v
retrieving revision 1.75
diff -c -p -r1.75 cfglayout.c
*** gcc/cfglayout.c	28 Sep 2004 07:59:42 -0000	1.75
--- gcc/cfglayout.c	21 Oct 2004 21:22:33 -0000
*************** insn_locators_initialize (void)
*** 319,325 ****
  	  if (!prologue_locator && file_name)
  	    prologue_locator = loc;
  	  if (!next)
! 	    epilogue_locator = loc;
  	  if (active)
  	    INSN_LOCATOR (insn) = loc;
  	}
--- 319,325 ----
  	  if (!prologue_locator && file_name)
  	    prologue_locator = loc;
  	  if (!next)
! 	    epilogue_locator = loc + 1;
  	  if (active)
  	    INSN_LOCATOR (insn) = loc;
  	}
Index: gcc/dwarf2out.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/dwarf2out.c,v
retrieving revision 1.556
diff -c -p -r1.556 dwarf2out.c
*** gcc/dwarf2out.c	14 Oct 2004 23:30:18 -0000	1.556
--- gcc/dwarf2out.c	21 Oct 2004 21:22:35 -0000
*************** lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_loc
*** 677,686 ****
      }
  }
  
! /* Find the previous value for the CFA.  */
  
  static void
! lookup_cfa (dw_cfa_location *loc)
  {
    dw_cfi_ref cfi;
  
--- 677,687 ----
      }
  }
  
! /* Find the value of the CFA immediately before NEXT.  If NEXT is NULL,
!    find the current CFA value.  */
  
  static void
! lookup_cfa_before (dw_cfi_ref next, dw_cfa_location *loc)
  {
    dw_cfi_ref cfi;
  
*************** lookup_cfa (dw_cfa_location *loc)
*** 695,705 ****
    if (fde_table_in_use)
      {
        dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
!       for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
! 	lookup_cfa_1 (cfi, loc);
      }
  }
  
  /* The current rule for calculating the DWARF2 canonical frame address.  */
  static dw_cfa_location cfa;
  
--- 696,717 ----
    if (fde_table_in_use)
      {
        dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
!       for (cfi = fde->dw_fde_cfi; cfi != next; cfi = cfi->dw_cfi_next)
! 	{
! 	  gcc_assert (cfi);
! 	  lookup_cfa_1 (cfi, loc);
! 	}
      }
  }
  
+ /* Find the previous value for the CFA.  */
+ 
+ static void
+ lookup_cfa (dw_cfa_location *loc)
+ {
+   lookup_cfa_before (NULL, loc);
+ }
+ 
  /* The current rule for calculating the DWARF2 canonical frame address.  */
  static dw_cfa_location cfa;
  
*************** reg_save (const char *label, unsigned in
*** 848,853 ****
--- 860,883 ----
    add_fde_cfi (label, cfi);
  }
  
+ /* Add the CFI for restoring a register to its initial value.
+    REG is the CFA column number, LABEL is passed to add_fde_cfi.  */
+ 
+ static void
+ reg_restore (const char *label, unsigned int reg)
+ {
+   dw_cfi_ref cfi = new_cfi ();
+ 
+   cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+ 
+   if (reg & ~0x3f)
+     cfi->dw_cfi_opc = DW_CFA_restore_extended;
+   else
+     cfi->dw_cfi_opc = DW_CFA_restore;
+ 
+   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.
*************** dwarf2out_stack_adjust (rtx insn)
*** 1122,1127 ****
--- 1152,1251 ----
    dwarf2out_args_size (label, args_size);
  }
  
+ /* Remember current CFI state.  */
+ 
+ static dw_cfi_ref *
+ dwarf2out_remember_state (void)
+ {
+   dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+   dw_cfi_ref *p;
+ 
+   /* Find the end of the chain.  */
+   for (p = &fde->dw_fde_cfi; (*p) != NULL; p = &(*p)->dw_cfi_next)
+     ;
+ 
+   return p;
+ }
+ 
+ /* Restore at current PC the state as of STATE (as returned by
+    dwarf2out_remember_state).  */
+ 
+ static void
+ dwarf2out_restore_state (dw_cfi_ref *state)
+ {
+   const char *label = dwarf2out_cfi_label ();
+   bool need_restore = false;
+   dw_cfa_location cfa;
+   dw_cfi_ref cfi;
+ 
+   /* Check whether we had any register state changes between STATE
+      and the current PC.  */
+   for (cfi = *state; cfi; cfi = cfi->dw_cfi_next)
+     switch (cfi->dw_cfi_opc)
+       {
+       /* These don't change any state.  */
+       case DW_CFA_nop:
+       case DW_CFA_set_loc:
+       case DW_CFA_advance_loc1:
+       case DW_CFA_advance_loc2:
+       case DW_CFA_advance_loc4:
+       case DW_CFA_MIPS_advance_loc8:
+ 	break;
+ 
+       /* We'll restore the CFA separately.  */
+       case DW_CFA_def_cfa:
+       case DW_CFA_def_cfa_sf:
+       case DW_CFA_def_cfa_register:
+       case DW_CFA_def_cfa_offset:
+       case DW_CFA_def_cfa_offset_sf:
+       case DW_CFA_def_cfa_expression:
+ 	break;
+ 
+       /* These mean we'll have to restore register state.  */
+       case DW_CFA_undefined:
+       case DW_CFA_same_value:
+       case DW_CFA_register:
+       case DW_CFA_offset:
+       case DW_CFA_offset_extended:
+       case DW_CFA_offset_extended_sf:
+       case DW_CFA_restore:
+       case DW_CFA_restore_extended:
+       case DW_CFA_expression:
+ 	need_restore = true;
+ 	break;
+ 
+       /* ??? We should handle these.  */
+       case DW_CFA_GNU_window_save:
+       case DW_CFA_GNU_args_size:
+ 	gcc_unreachable ();
+ 
+       /* We never generate nested remember/restore state pairs.  */
+       case DW_CFA_remember_state:
+       case DW_CFA_restore_state:
+       default:
+ 	gcc_unreachable ();
+       }
+ 
+   /* If required, save and restore register state.  */
+   if (need_restore)
+     {
+       /* Insert 'remember state' at STATE ...  */
+       cfi = new_cfi ();
+       cfi->dw_cfi_opc = DW_CFA_remember_state;
+       cfi->dw_cfi_next = *state;
+       *state = cfi;
+ 
+       /* ... and 'restore state' at current PC.  */
+       cfi = new_cfi ();
+       cfi->dw_cfi_opc = DW_CFA_restore_state;
+       add_fde_cfi (label, cfi);
+     }
+ 
+   /* Look up the CFA as of STATE, and reset the current CFA.  */
+   lookup_cfa_before (*state, &cfa);
+   def_cfa_1 (label, &cfa);
+ }
+ 
  #endif
  
  /* We delay emitting a register save until either (a) we reach the end
*************** static GTY(()) size_t num_regs_saved_in_
*** 1155,1161 ****
  static const char *last_reg_save_label;
  
  /* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
!    SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.  */
  
  static void
  queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
--- 1279,1287 ----
  static const char *last_reg_save_label;
  
  /* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
!    SREG, or if SREG is NULL then it is saved at OFFSET to the CFA.
!    If SREG is const0_rtx, REG is now restored to its original value
!    at function entry.  */
  
  static void
  queue_reg_save (const char *label, rtx reg, rtx sreg, HOST_WIDE_INT offset)
*************** flush_queued_reg_saves (void)
*** 1198,1204 ****
        for (i = 0; i < num_regs_saved_in_regs; i++)
  	if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
  	  break;
!       if (q->saved_reg && i == num_regs_saved_in_regs)
  	{
  	  gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
  	  num_regs_saved_in_regs++;
--- 1324,1331 ----
        for (i = 0; i < num_regs_saved_in_regs; i++)
  	if (REGNO (regs_saved_in_regs[i].orig_reg) == REGNO (q->reg))
  	  break;
!       if (q->saved_reg && q->saved_reg != const0_rtx
! 	  && i == num_regs_saved_in_regs)
  	{
  	  gcc_assert (i != ARRAY_SIZE (regs_saved_in_regs));
  	  num_regs_saved_in_regs++;
*************** flush_queued_reg_saves (void)
*** 1206,1220 ****
        if (i != num_regs_saved_in_regs)
  	{
  	  regs_saved_in_regs[i].orig_reg = q->reg;
! 	  regs_saved_in_regs[i].saved_in_reg = q->saved_reg;
  	}
  
        reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
!       if (q->saved_reg)
! 	sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
        else
! 	sreg = INVALID_REGNUM;
!       reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
      }
  
    queued_reg_saves = NULL;
--- 1333,1355 ----
        if (i != num_regs_saved_in_regs)
  	{
  	  regs_saved_in_regs[i].orig_reg = q->reg;
! 	  regs_saved_in_regs[i].saved_in_reg = 
! 	    q->saved_reg != const0_rtx ? q->saved_reg : NULL_RTX;
  	}
  
        reg = DWARF_FRAME_REGNUM (REGNO (q->reg));
! 
!       if (q->saved_reg != const0_rtx)
! 	{
! 	  if (q->saved_reg)
! 	    sreg = DWARF_FRAME_REGNUM (REGNO (q->saved_reg));
! 	  else
! 	    sreg = INVALID_REGNUM;
! 
! 	  reg_save (last_reg_save_label, reg, sreg, q->cfa_offset);
! 	}
        else
! 	reg_restore (last_reg_save_label, reg);
      }
  
    queued_reg_saves = NULL;
*************** dwarf2out_frame_debug_expr (rtx expr, co
*** 1490,1495 ****
--- 1625,1636 ----
  	      cfa_temp.reg = cfa.reg;
  	      cfa_temp.offset = cfa.offset;
  	    }
+ 	  else if (REGNO (dest) == REGNO (src))
+ 	    {
+ 	      /* This is a marker for an epilogue insn that restores a
+ 		 register to its initial value at function entry.  */
+ 	      queue_reg_save (label, dest, const0_rtx, 0);
+ 	    }
  	  else
  	    {
  	      /* Saving a register in a register.  */
*************** dwarf2out_frame_debug_expr (rtx expr, co
*** 1772,1779 ****
  void
  dwarf2out_frame_debug (rtx insn)
  {
    const char *label;
!   rtx src;
  
    if (insn == NULL_RTX)
      {
--- 1913,1921 ----
  void
  dwarf2out_frame_debug (rtx insn)
  {
+   static dw_cfi_ref *epilogue_state;
    const char *label;
!   rtx src, next;
  
    if (insn == NULL_RTX)
      {
*************** dwarf2out_frame_debug (rtx insn)
*** 1798,1809 ****
--- 1940,1961 ----
  	  regs_saved_in_regs[i].saved_in_reg = NULL_RTX;
  	}
        num_regs_saved_in_regs = 0;
+       epilogue_state = NULL;
        return;
      }
  
    if (!NONJUMP_INSN_P (insn) || clobbers_queued_reg_save (insn))
      flush_queued_reg_saves ();
  
+   /* If we run into the end of the epilogue, and we had emitted CFI for it,
+      restore CFA and register state for instructions after the epilogue.  */
+   if (BARRIER_P (insn) && epilogue_state
+       && (next = next_active_insn (insn)) != NULL_RTX)
+     {
+       dwarf2out_restore_state (epilogue_state);
+       epilogue_state = NULL;
+     }
+ 
    if (! RTX_FRAME_RELATED_P (insn))
      {
        if (!ACCUMULATE_OUTGOING_ARGS)
*************** dwarf2out_frame_debug (rtx insn)
*** 1812,1817 ****
--- 1964,1974 ----
        return;
      }
  
+   /* If we start emitting CFI for epilogue instructions, remember the
+      start of the epilogue so we can restore the state later.  */
+   if (!epilogue_state && INSN_LOCATOR (insn) == epilogue_locator)
+     epilogue_state = dwarf2out_remember_state ();
+ 
    label = dwarf2out_cfi_label ();
    src = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
    if (src)
*************** dw_cfi_oprnd1_desc (enum dwarf_call_fram
*** 1834,1839 ****
--- 1991,1998 ----
    switch (cfi)
      {
      case DW_CFA_nop:
+     case DW_CFA_remember_state:
+     case DW_CFA_restore_state:
      case DW_CFA_GNU_window_save:
        return dw_cfi_oprnd_unused;
  
*************** dw_cfi_oprnd1_desc (enum dwarf_call_fram
*** 1849,1854 ****
--- 2008,2014 ----
      case DW_CFA_def_cfa:
      case DW_CFA_offset_extended_sf:
      case DW_CFA_def_cfa_sf:
+     case DW_CFA_restore:
      case DW_CFA_restore_extended:
      case DW_CFA_undefined:
      case DW_CFA_same_value:
*************** output_cfi (dw_cfi_ref cfi, dw_fde_ref f
*** 2007,2012 ****
--- 2167,2174 ----
  	  dw2_asm_output_data_sleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset, NULL);
  	  break;
  
+ 	case DW_CFA_remember_state:
+ 	case DW_CFA_restore_state:
  	case DW_CFA_GNU_window_save:
  	  break;
  
Index: gcc/emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.420
diff -c -p -r1.420 emit-rtl.c
*** gcc/emit-rtl.c	18 Oct 2004 01:56:03 -0000	1.420
--- gcc/emit-rtl.c	21 Oct 2004 21:22:35 -0000
*************** emit_copy_of_insn_after (rtx insn, rtx a
*** 5527,5532 ****
--- 5527,5533 ----
      {
      case INSN:
        new = emit_insn_after (copy_insn (PATTERN (insn)), after);
+       RTX_FRAME_RELATED_P (new) = RTX_FRAME_RELATED_P (insn);
        break;
  
      case JUMP_INSN:
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.194
diff -c -p -r1.194 s390.c
*** gcc/config/s390/s390.c	14 Oct 2004 18:32:04 -0000	1.194
--- gcc/config/s390/s390.c	21 Oct 2004 21:22:38 -0000
*************** restore_gprs (rtx base, int offset, int 
*** 6624,6636 ****
          insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
        else
          insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
  
!       return insn;
      }
  
-   insn = gen_load_multiple (gen_rtx_REG (Pmode, first),
- 			    addr,
- 			    GEN_INT (last - first + 1));
    return insn;
  }
  
--- 6624,6651 ----
          insn = gen_movdi (gen_rtx_REG (Pmode, first), addr);
        else
          insn = gen_movsi (gen_rtx_REG (Pmode, first), addr);
+     }
+   else
+     insn = gen_load_multiple (gen_rtx_REG (Pmode, first), addr,
+ 			      GEN_INT (last - first + 1));
+ 
+   /* Generate DWARF-2 CFI annotations to restore the CFA for use within the
+      epilogue.  */
+ 
+   if (first <= STACK_POINTER_REGNUM && STACK_POINTER_REGNUM <= last)
+     {
+       rtx fp, note;
  
!       fp = frame_pointer_needed? hard_frame_pointer_rtx : stack_pointer_rtx;
!       note = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
! 			  plus_constant (fp, cfun_frame_layout.frame_size));
! 
!       REG_NOTES (insn) =
! 	gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, note, REG_NOTES (insn));
!  
!       RTX_FRAME_RELATED_P (insn) = 1;
      }
  
    return insn;
  }
  
*************** s390_emit_epilogue (bool sibcall)
*** 7007,7012 ****
--- 7022,7029 ----
  
    if (TARGET_64BIT)
      {
+       rtx insn;
+ 
        if (cfun_save_high_fprs_p)
  	{
  	  next_offset = cfun_frame_layout.f8_offset;
*************** s390_emit_epilogue (bool sibcall)
*** 7014,7026 ****
  	    {
  	      if (cfun_fpr_bit_p (i - 16))
  		{
! 		  restore_fpr (frame_pointer,
! 			       offset + next_offset, i);
  		  next_offset += 8;
  		}
  	    }
  	}
- 	      
      }
    else
      {
--- 7031,7048 ----
  	    {
  	      if (cfun_fpr_bit_p (i - 16))
  		{
! 		  insn = restore_fpr (frame_pointer, offset + next_offset, i);
! 		  RTX_FRAME_RELATED_P (insn) = 1;
! 		  REG_NOTES (insn) =
! 		    gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
! 				       gen_rtx_SET (VOIDmode,
! 						    gen_rtx_REG (DFmode, i),
! 						    gen_rtx_REG (DFmode, i)),
! 				       REG_NOTES (insn));
  		  next_offset += 8;
  		}
  	    }
  	}
      }
    else
      {

-- 
  Dr. Ulrich Weigand
  Linux on zSeries Development
  Ulrich.Weigand@de.ibm.com


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