diff mbox

[_eh,dawin] Allow targets to suppress epilogues in _eh frames.

Message ID 89584BF2-10CD-45DE-A4A5-4C2EE43396B3@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe Aug. 13, 2010, 7:50 p.m. UTC
As discussed off list and in  IRC with Richard,

=----=

Some (if not most) targets do not require the function epilogue in  
their _eh unwind frames.
In fact, it breaks the darwin unwinder (PR41991) my original  
motivation for looking at this.

However, as we went through the discussion it became apparent that  
this might have wider application than fixing a darwin bug, in saving  
some space in the eh.

What this does is to use the existing DW_CFA_save/restore_state and a  
new DW_CFA_GNU_start_epilogue marker to suppress the emitting of  
function epilogues - when (a) we're emitting _eh and (b) the target  
requests suppression via a hook.
The hook is a bool function to permit targets to choose whether to  
emit this data or not at run time rather than config time (the default  
hook does nothing).

----

The DW_CFA_GNU_start_epilogue marker is inserted under the  
circumstance that an epilogue is detected at the end of a function.
The save/restore markers are not touched and deal with the case that  
we are mid-function.

There is a  debug print of  # DW_CFA_GNU_start_epilogue to show where  
we are intercepting in the eh frames and not curtailing the  
debug_frames.

I'd particularly welcome someone's eye over what's happening in the  
case of section switches (it seems to me that the skipping of mid- 
function save/restore is handled OK, but I'm not familiar with that  
code - and my main target(s) don't use that facility).

====

This has only been lightly tested on i686/powerpc-darwin9 (regtested  
on i686) - but it appears to restore Unwind functionality to the  
platform :)
[gcj works again, Yay!]

====

so we get this in the _eh frame:

LECIE1:
	.globl _main.eh
_main.eh:
LSFDE1:
	.set L$set$1,LEFDE1-LASFDE1
	.long L$set$1	# FDE Length
LASFDE1:
	.long	LASFDE1-EH_frame1	# FDE CIE offset
	.long	LFB1-.	# FDE initial location
	.set L$set$2,LFE1-LFB1

<SNIP>

	.set L$set$5,LCFI4-LCFI1
	.long L$set$5
	.byte	0x83	# DW_CFA_offset, column 0x3
	.byte	0x3	# uleb128 0x3
	.byte	0x4	# DW_CFA_advance_loc4
	.set L$set$6,LCFI6-LCFI4
	.long L$set$6
#			# DW_CFA_GNU_start_epilogue
	.align 2

and this in the _debug_frame:
	.section __DWARF,__debug_frame,regular,debug
Lsection__debug_frame:
Lframe0:
	.set L$set$7,LECIE0-LSCIE0
	.long L$set$7	# Length of Common Information Entry
LSCIE0:

<SNIP>

	.byte	0x83	# DW_CFA_offset, column 0x3
	.byte	0x3	# uleb128 0x3
	.byte	0x4	# DW_CFA_advance_loc4
	.set L$set$14,LCFI6-LCFI4
	.long L$set$14
#			# DW_CFA_GNU_start_epilogue
	.byte	0xc3	# DW_CFA_restore, column 0x3
	.byte	0x4	# DW_CFA_advance_loc4
	.set L$set$15,LCFI7-LCFI6
	.long L$set$15
	.byte	0xc	# DW_CFA_def_cfa
	.byte	0x4	# uleb128 0x4
	.byte	0x4	# uleb128 0x4
	.byte	0xc5	# DW_CFA_restore, column 0x5
	.align 2
LEFDE2:

=====
thoughts?
Iain


Change notes (not a proper changelog, at this juncture)

include/dwarf2.h : DW_CFA_GNU_start_epilogue new enum.

dwarf2out.c: dwarf_cfi_name() recognize DW_CFA_GNU_start_epilogue
static scope emit_cfa_start_epilogue new var.
add_fde_cfi() : emit a marker for the epilogue start;
dwarf2out_cfi_begin_epilogue (): note that we need to emit the  
epilogue start marker when the epilogue is at the end.
dw_cfi_oprnd1_desc (): recognize DW_CFA_GNU_start_epilogue as a no-op.
output_cfi(): print debug message for DW_CFA_GNU_start_epilogue
emit_cfi_or_skip_epilogue (): New.
output_fde () : use emit_cfi_or_skip_epilogue ();

target.def: suppress_eh_epilogue_p (): New ASM Hook.

=== the remainder are the implementation on the darwin side:

gcc/config/darwin.h (TARGET_ASM_SUPPRESS_EH_EPILOGUE_P): New
gcc/config/darwin.c (darwin_asm_suppress_eh_epilogue_p): New.
gcc/config/darwin-protos.h: Declare darwin_asm_suppress_eh_epilogue_p.

========== - ===========

Comments

Richard Henderson Aug. 13, 2010, 11:27 p.m. UTC | #1
On 08/13/2010 12:50 PM, IainS wrote:
> +    DW_CFA_GNU_start_epilogue = 0x30

I'd rather not place this in dwarf2.h since we don't plan to emit this
as an actual opcode.  It only needs to be a marker in the dw_cfi_ref
linked list for internal use of gcc.

As such I think something like

# define DW_CFA_INTERNAL_start_epilogue  0x100

would be appropriate.  I believe you'll need to change

  typedef struct GTY(()) dw_cfi_struct {
    dw_cfi_ref dw_cfi_next;
-   enum dwarf_call_frame_info dw_cfi_opc;
+   unsigned int dw_cfi_opc;

in order for this to be legal.  Unfortunately that may
require a host of other type changes or type casts in
order to pass the C++ warning mode.

> +/* True if start_epilogue should be emitted before following CFI directive.  */
> +static bool emit_cfa_start_epilogue;

I don't think this is needed...

>    if (i == NULL)
> -    return;
> +    {
> +      /* But we do mark the start of the epilogue to allow it to be skipped
> +         in _eh frames.  */
> +      emit_cfa_start_epilogue = true; 
> +      return;
> +    }

... instead we want to add the cfi entry here, by hand.  The reason
being that we want to avoid the DW_CFA_advance_loc4 that would be
added by actually inserting this opcode via add_fde_cfi.

> +/* Targets might not need epilogue information in dwarf2 _eh frames.  This
> +   hook should return true if the epilogue should be suppressed in such frames.
> +   Epilogues will still be emitted in _debug_frames.  */
> +DEFHOOK_UNDOC
> +(suppress_eh_epilogue_p,
> + "",
> + bool, (void),
> + hook_bool_void_false)

As discussed on IRC, I don't think we need a target hook for this.  We
should key this off of !flag_asynchronous_unwind_tables.  That will
allow all targets that only need unwind info for call sites omit this
extra epilogue unwind info.

At that point you can adjust Darwin's override_options hook(s) to make 
sure that this flag is appropriately off.  It also seems like it would
be a good idea to add a SPEC entry to disable compact unwind if the
user explicitly uses -fasynchronous-unwind-info.

> +/* Mark the start of each dwarf debug section to allow us to compute local
> +   offsets within the sections.  We do this in darwin, rather than emitting
> +   relocs.  */
> +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \
> +	darwin_asm_output_dwarf_section_start_label

Is this an unrelated change?  I can't see how it relates to the rest.


r~
Jack Howarth Aug. 14, 2010, 2:19 a.m. UTC | #2
On Fri, Aug 13, 2010 at 08:50:29PM +0100, IainS wrote:
> As discussed off list and in  IRC with Richard,
>
> =----=
>
> Some (if not most) targets do not require the function epilogue in their 
> _eh unwind frames.
> In fact, it breaks the darwin unwinder (PR41991) my original motivation 
> for looking at this.
>
> However, as we went through the discussion it became apparent that this 
> might have wider application than fixing a darwin bug, in saving some 
> space in the eh.
>
> What this does is to use the existing DW_CFA_save/restore_state and a  
> new DW_CFA_GNU_start_epilogue marker to suppress the emitting of  
> function epilogues - when (a) we're emitting _eh and (b) the target  
> requests suppression via a hook.
> The hook is a bool function to permit targets to choose whether to emit 
> this data or not at run time rather than config time (the default hook 
> does nothing).
>
> ----
>
> The DW_CFA_GNU_start_epilogue marker is inserted under the circumstance 
> that an epilogue is detected at the end of a function.
> The save/restore markers are not touched and deal with the case that we 
> are mid-function.
>
> There is a  debug print of  # DW_CFA_GNU_start_epilogue to show where we 
> are intercepting in the eh frames and not curtailing the debug_frames.
>
> I'd particularly welcome someone's eye over what's happening in the case 
> of section switches (it seems to me that the skipping of mid-function 
> save/restore is handled OK, but I'm not familiar with that code - and my 
> main target(s) don't use that facility).
>
> ====
>
> This has only been lightly tested on i686/powerpc-darwin9 (regtested on 
> i686) - but it appears to restore Unwind functionality to the platform :)
> [gcj works again, Yay!]
>
> ====
>
> so we get this in the _eh frame:
>
> LECIE1:
> 	.globl _main.eh
> _main.eh:
> LSFDE1:
> 	.set L$set$1,LEFDE1-LASFDE1
> 	.long L$set$1	# FDE Length
> LASFDE1:
> 	.long	LASFDE1-EH_frame1	# FDE CIE offset
> 	.long	LFB1-.	# FDE initial location
> 	.set L$set$2,LFE1-LFB1
>
> <SNIP>
>
> 	.set L$set$5,LCFI4-LCFI1
> 	.long L$set$5
> 	.byte	0x83	# DW_CFA_offset, column 0x3
> 	.byte	0x3	# uleb128 0x3
> 	.byte	0x4	# DW_CFA_advance_loc4
> 	.set L$set$6,LCFI6-LCFI4
> 	.long L$set$6
> #			# DW_CFA_GNU_start_epilogue
> 	.align 2
>
> and this in the _debug_frame:
> 	.section __DWARF,__debug_frame,regular,debug
> Lsection__debug_frame:
> Lframe0:
> 	.set L$set$7,LECIE0-LSCIE0
> 	.long L$set$7	# Length of Common Information Entry
> LSCIE0:
>
> <SNIP>
>
> 	.byte	0x83	# DW_CFA_offset, column 0x3
> 	.byte	0x3	# uleb128 0x3
> 	.byte	0x4	# DW_CFA_advance_loc4
> 	.set L$set$14,LCFI6-LCFI4
> 	.long L$set$14
> #			# DW_CFA_GNU_start_epilogue
> 	.byte	0xc3	# DW_CFA_restore, column 0x3
> 	.byte	0x4	# DW_CFA_advance_loc4
> 	.set L$set$15,LCFI7-LCFI6
> 	.long L$set$15
> 	.byte	0xc	# DW_CFA_def_cfa
> 	.byte	0x4	# uleb128 0x4
> 	.byte	0x4	# uleb128 0x4
> 	.byte	0xc5	# DW_CFA_restore, column 0x5
> 	.align 2
> LEFDE2:
>
> =====
> thoughts?
> Iain
>

Iain,
   So far the only failure I see with your patch under darwin10.4.0, using the
compact unwinder (by eliminating the addition of -no_compact_unwind
in darwin10.h), is...

FAIL: g++.dg/eh/async-unwind2.C execution test

at -m32. Interestingly, if I pass -Wl,-warn_compact_unwind when building
that testcase, I get...

[MacPro:~/async_unwind] howarth% /sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../g++ -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/gcc/testsuite/g++/../../ /sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/gcc/testsuite/g++.dg/eh/async-unwind2.C -nostdinc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include/x86_64-apple-darwin10.4.0 -I/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/include -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/libsupc++ -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/include/backward -I/sw/src/fink.build/gcc46-4.6.0-1000/gcc-4.6-20100813/libstdc++-v3/testsuite/util -fmessage-length=0 -Os -fasynchronous-unwind-tables -fpic -fno-inline -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -B/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libstdc++-v3/src/.libs -L/sw/src/fink.build/gcc46-4.6.0-1000/darwin_objdir/x86_64-apple-darwin10.4.0/i386/libiberty -multiply_defined suppress -lm -m32 -g -Wl,-warn_compact_unwind -o ./async-unwind2.exe
ld: warning: can't make compact unwind encoding from dwarf for S::sfn2(int)  in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size
ld: warning: can't make compact unwind encoding from dwarf for S::sfn3(char const*) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size
ld: warning: can't make compact unwind encoding from dwarf for baz1(S const&) in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-//ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size

These errors don't appear when I do the same to build the non-failing async-unwind1.exe testcase. Can we inhibit the emission of
DW_CFA_GNU_args_size on darwin as well?
                Jack


>
> Change notes (not a proper changelog, at this juncture)
>
> include/dwarf2.h : DW_CFA_GNU_start_epilogue new enum.
>
> dwarf2out.c: dwarf_cfi_name() recognize DW_CFA_GNU_start_epilogue
> static scope emit_cfa_start_epilogue new var.
> add_fde_cfi() : emit a marker for the epilogue start;
> dwarf2out_cfi_begin_epilogue (): note that we need to emit the epilogue 
> start marker when the epilogue is at the end.
> dw_cfi_oprnd1_desc (): recognize DW_CFA_GNU_start_epilogue as a no-op.
> output_cfi(): print debug message for DW_CFA_GNU_start_epilogue
> emit_cfi_or_skip_epilogue (): New.
> output_fde () : use emit_cfi_or_skip_epilogue ();
>
> target.def: suppress_eh_epilogue_p (): New ASM Hook.
>
> === the remainder are the implementation on the darwin side:
>
> gcc/config/darwin.h (TARGET_ASM_SUPPRESS_EH_EPILOGUE_P): New
> gcc/config/darwin.c (darwin_asm_suppress_eh_epilogue_p): New.
> gcc/config/darwin-protos.h: Declare darwin_asm_suppress_eh_epilogue_p.
>
> ========== - ===========

> Index: include/dwarf2.h
> ===================================================================
> --- include/dwarf2.h	(revision 163221)
> +++ include/dwarf2.h	(working copy)
> @@ -854,7 +854,8 @@ enum dwarf_call_frame_info
>      /* GNU extensions.  */
>      DW_CFA_GNU_window_save = 0x2d,
>      DW_CFA_GNU_args_size = 0x2e,
> -    DW_CFA_GNU_negative_offset_extended = 0x2f
> +    DW_CFA_GNU_negative_offset_extended = 0x2f,
> +    DW_CFA_GNU_start_epilogue = 0x30
>    };
>  
>  #define DW_CIE_ID	  0xffffffff
> Index: gcc/dwarf2out.c
> ===================================================================
> --- gcc/dwarf2out.c	(revision 163221)
> +++ gcc/dwarf2out.c	(working copy)
> @@ -720,7 +724,9 @@ dwarf_cfi_name (unsigned int cfi_opc)
>        return "DW_CFA_GNU_args_size";
>      case DW_CFA_GNU_negative_offset_extended:
>        return "DW_CFA_GNU_negative_offset_extended";
> -
> +    case DW_CFA_GNU_start_epilogue:
> +      return "DW_CFA_GNU_start_epilogue";
> +      
>      default:
>        return "DW_CFA_<unknown>";
>      }
> @@ -801,6 +807,9 @@ dwarf2out_cfi_label (bool force)
>  /* True if remember_state should be emitted before following CFI directive.  */
>  static bool emit_cfa_remember;
>  
> +/* True if start_epilogue should be emitted before following CFI directive.  */
> +static bool emit_cfa_start_epilogue;
> +
>  /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
>     or to the CIE if LABEL is NULL.  */
>  
> @@ -809,6 +818,17 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi)
>  {
>    dw_cfi_ref *list_head;
>  
> +  if (emit_cfa_start_epilogue)
> +    {
> +      dw_cfi_ref cfi_epi_start;
> +
> +      /* Emit the state save.  */
> +      emit_cfa_start_epilogue = false;
> +      cfi_epi_start = new_cfi ();
> +      cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue;
> +      add_fde_cfi (label, cfi_epi_start);   
> +    }
> +    
>    if (emit_cfa_remember)
>      {
>        dw_cfi_ref cfi_remember;
> @@ -2898,7 +2918,12 @@ dwarf2out_cfi_begin_epilogue (rtx insn)
>    gcc_assert (i != NULL);
>    i = next_real_insn (i);
>    if (i == NULL)
> -    return;
> +    {
> +      /* But we do mark the start of the epilogue to allow it to be skipped
> +         in _eh frames.  */
> +      emit_cfa_start_epilogue = true; 
> +      return;
> +    }
>  
>    /* Insert the restore before that next real insn in the stream, and before
>       a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be
> @@ -2953,6 +2978,7 @@ dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi
>      case DW_CFA_GNU_window_save:
>      case DW_CFA_remember_state:
>      case DW_CFA_restore_state:
> +    case DW_CFA_GNU_start_epilogue:
>        return dw_cfi_oprnd_unused;
>  
>      case DW_CFA_set_loc:
> @@ -3121,6 +3148,10 @@ output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo
>        dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
>  			   "DW_CFA_restore, column %#lx", r);
>      }
> +  else if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue)
> +/* DEBUG */
> +    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
> +    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
>    else
>      {
>        dw2_asm_output_data (1, cfi->dw_cfi_opc,
> @@ -3303,6 +3334,12 @@ output_cfi_directive (dw_cfi_ref cfi)
>  	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
>        break;
>  
> +    case DW_CFA_GNU_start_epilogue:
> +/*DEBUG */
> +    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
> +    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
> +      break;
> +      
>      case DW_CFA_remember_state:
>        fprintf (asm_out_file, "\t.cfi_remember_state\n");
>        break;
> @@ -3498,6 +3535,41 @@ output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f
>      }
>  }
>  
> +/* Output cfi skipping save/restore and epilogues in _eh frames
> +   for targets that do not want them.  */
> +
> +static dw_cfi_ref
> +emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh)
> +{
> +  if (for_eh 
> +      && targetm.asm_out.suppress_eh_epilogue_p())
> +    {
> +      if (cfi->dw_cfi_opc == DW_CFA_remember_state)
> +	{
> +	  /* Skip to the restore, unless there's an error and we fall off
> +	     the end.  */
> +	  while (cfi->dw_cfi_next 
> +		 && cfi->dw_cfi_opc != DW_CFA_restore_state) 
> +	    cfi = cfi->dw_cfi_next;
> +	  return cfi;
> +        }
> +      if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue)
> +        {
> +/*DEBUG */
> +    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
> +    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
> +	  while (cfi->dw_cfi_next) 
> +	    /* Skip to the end.  */
> +	    cfi = cfi->dw_cfi_next;
> +          return cfi;
> +        }
> +    }
> +
> +  /* if it's not a special case, then just emit it.  */
> +  output_cfi (cfi, fde, for_eh);
> +  return cfi;
> +}
> +
>  /* Output one FDE.  */
>  
>  static void
> @@ -3613,13 +3685,13 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco
>    fde->dw_fde_current_label = begin;
>    if (!fde->dw_fde_switched_sections)
>      for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
> -      output_cfi (cfi, fde, for_eh);
> +      cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
>    else if (!second)
>      {
>        if (fde->dw_fde_switch_cfi)
>  	for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
>  	  {
> -	    output_cfi (cfi, fde, for_eh);
> +	    cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
>  	    if (cfi == fde->dw_fde_switch_cfi)
>  	      break;
>  	  }
> @@ -3636,7 +3707,7 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco
>  	  fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
>  	}
>        for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
> -	output_cfi (cfi, fde, for_eh);
> +	cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
>      }
>  
>    /* If we are to emit a ref/link from function bodies to their frame tables,
> Index: gcc/target.def
> ===================================================================
> --- gcc/target.def	(revision 163221)
> +++ gcc/target.def	(working copy)
> @@ -390,6 +406,15 @@ DEFHOOK
>   void, (FILE *file, int size, rtx x),
>   NULL)
>  
> +/* Targets might not need epilogue information in dwarf2 _eh frames.  This
> +   hook should return true if the epilogue should be suppressed in such frames.
> +   Epilogues will still be emitted in _debug_frames.  */
> +DEFHOOK_UNDOC
> +(suppress_eh_epilogue_p,
> + "",
> + bool, (void),
> + hook_bool_void_false)
> +
>  /* Some target machines need to postscan each insn after it is output.  */
>  DEFHOOK
>  (final_postscan_insn,
> Index: gcc/config/darwin-protos.h
> ===================================================================
> --- gcc/config/darwin-protos.h	(revision 163221)
> +++ gcc/config/darwin-protos.h	(working copy)
> @@ -83,10 +84,15 @@ extern tree darwin_handle_weak_import_attribute (t
>  extern void machopic_output_stub (FILE *, const char *, const char *);
>  extern void darwin_globalize_label (FILE *, const char *);
>  extern void darwin_assemble_visibility (tree, int);
> +
> +extern bool darwin_asm_suppress_eh_epilogue_p (void);
> +extern void darwin_asm_output_dwarf_section_start_label (FILE *file, 
> +							section *sect);
>  extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
>  					   const char *);
>  extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
>  					    section *);
> +
>  extern void darwin_asm_declare_constant_name (FILE *, const char *,
>  					      const_tree, HOST_WIDE_INT);
>  extern bool darwin_binds_local_p (const_tree);
> Index: gcc/config/darwin.h
> ===================================================================
> --- gcc/config/darwin.h	(revision 163221)
> +++ gcc/config/darwin.h	(working copy)
> @@ -669,7 +675,6 @@ extern GTY(()) int darwin_ms_struct;
>     Make Objective-C internal symbols local and in doing this, we need 
>     to accommodate the name mangling done by c++ on file scope locals.  */
>  
> -
>  int darwin_label_is_anonymous_local_objc_name (const char *name);
>  
>  #undef	ASM_OUTPUT_LABELREF
> @@ -927,6 +932,16 @@ enum machopic_addr_class {
>     ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \
>       ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
>  
> +/* Mark the start of each dwarf debug section to allow us to compute local
> +   offsets within the sections.  We do this in darwin, rather than emitting
> +   relocs.  */
> +#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \
> +	darwin_asm_output_dwarf_section_start_label
> +
> +/* For OSX compatibility we do not want to emit epilogues in _eh frames.  */
> +#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \
> +	darwin_asm_suppress_eh_epilogue_p
> +
>  #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2)  \
>    darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2)
>  
> Index: gcc/config/darwin.c
> ===================================================================
> --- gcc/config/darwin.c	(revision 163221)
> +++ gcc/config/darwin.c	(working copy)
> @@ -1666,6 +1666,36 @@ darwin_assemble_visibility (tree decl, int vis)
>  	     "not supported in this configuration; ignored");
>  }
>  
> +/* For compatibility with OSX versions that do not emit epilogues in _eh
> +   frames we suppress them.  This is made a predicate function to permit 
> +   us to add an OSX/FSF compatibility switch should that be required.  */
> +
> +bool
> +darwin_asm_suppress_eh_epilogue_p (void)
> +{
> +  return true;
> +}
> +
> +/* So that we can compute dwarf offsets within sections, we emit a known
> +   section marker at the begining of the section.  This is distinct from
> +   the ones emitted by dwarf2out.  The label is constructed by extracting
> +   sectname from __DWARF,__sectname,etc,etc.  The hook should be invoked
> +   once, after the first switch to the section.  */
> +   
> +void
> +darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect)
> +{
> +  const char *dnam;
> +  int namelen;
> +  gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG)));
> +  dnam = ((struct named_section *)sect)->name;
> +  gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0);
> +  gcc_assert (strchr (dnam + 8, ','));
> +
> +  namelen = strchr (dnam + 8, ',') - (dnam + 8);
> +  fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8);
> +}
> +
>  /* Output a difference of two labels that will be an assembly time
>     constant if the two labels are local.  (.long lab1-lab2 will be
>     very different if lab1 is at the boundary between two sections; it

>
>
>
>
>
Iain Sandoe Aug. 14, 2010, 1:49 p.m. UTC | #3
Thanks to Richard and Jakub for comments (on list and in irc)

I've nearly finished re-working the patch (in testing now).

On 14 Aug 2010, at 03:19, Jack Howarth wrote:
> FAIL: g++.dg/eh/async-unwind2.C execution test

if we say that darwin does not support -fasynchronous-unwind-tables,  
then we should simply skip this test.

> ld: warning: can't make compact unwind encoding from dwarf for  
> S::sfn2(int)  in /var/folders/1C/1CdoNxmNFHyOIjNBLNuJh++++TM/-Tmp-// 
> ccw4LTKt.o because dwarf uses DW_CFA_GNU_args_size

This is interesting - is this a dwarf-2 opcode?

It is enabled by -fasynchronous-unwind-tables (without any fall-back  
for non-gnu targets)

Does this imply that -fasynchronous-unwind-tables is only usable by a  
gnu target?

also I note that:
-fnon-call-exceptions  _unconditionally_  sets -fasynchronous-unwind- 
tables in toplev.c

(and, of course, libjava does set  -fnon-call-exceptions, so that  
builds with a bunch of warnings now - since I've added warnings for  
the two cases).

So ... where do we stand?

maybe toplev should do sth like;
if ( flag_non_call_exceptions && flag_asynchronous_unwind_tables == 2)
   flag_asynchronous_unwind_tables = 1;

Richard?, Jakub? any advice appreciated.

thanks
Iain
Mike Stump Aug. 15, 2010, 1:49 p.m. UTC | #4
On Aug 14, 2010, at 6:49 AM, IainS wrote:
> if we say that darwin does not support -fasynchronous-unwind-tables, then we should simply skip this test.

darwin would like it...  I don't know of anyone that is twisting in the wind on it however, so it could be xfailed for now, if one wants a cleaner run.
diff mbox

Patch

Index: include/dwarf2.h
===================================================================
--- include/dwarf2.h	(revision 163221)
+++ include/dwarf2.h	(working copy)
@@ -854,7 +854,8 @@  enum dwarf_call_frame_info
     /* GNU extensions.  */
     DW_CFA_GNU_window_save = 0x2d,
     DW_CFA_GNU_args_size = 0x2e,
-    DW_CFA_GNU_negative_offset_extended = 0x2f
+    DW_CFA_GNU_negative_offset_extended = 0x2f,
+    DW_CFA_GNU_start_epilogue = 0x30
   };
 
 #define DW_CIE_ID	  0xffffffff
Index: gcc/dwarf2out.c
===================================================================
--- gcc/dwarf2out.c	(revision 163221)
+++ gcc/dwarf2out.c	(working copy)
@@ -720,7 +724,9 @@  dwarf_cfi_name (unsigned int cfi_opc)
       return "DW_CFA_GNU_args_size";
     case DW_CFA_GNU_negative_offset_extended:
       return "DW_CFA_GNU_negative_offset_extended";
-
+    case DW_CFA_GNU_start_epilogue:
+      return "DW_CFA_GNU_start_epilogue";
+      
     default:
       return "DW_CFA_<unknown>";
     }
@@ -801,6 +807,9 @@  dwarf2out_cfi_label (bool force)
 /* True if remember_state should be emitted before following CFI directive.  */
 static bool emit_cfa_remember;
 
+/* True if start_epilogue should be emitted before following CFI directive.  */
+static bool emit_cfa_start_epilogue;
+
 /* Add CFI to the current fde at the PC value indicated by LABEL if specified,
    or to the CIE if LABEL is NULL.  */
 
@@ -809,6 +818,17 @@  add_fde_cfi (const char *label, dw_cfi_ref cfi)
 {
   dw_cfi_ref *list_head;
 
+  if (emit_cfa_start_epilogue)
+    {
+      dw_cfi_ref cfi_epi_start;
+
+      /* Emit the state save.  */
+      emit_cfa_start_epilogue = false;
+      cfi_epi_start = new_cfi ();
+      cfi_epi_start->dw_cfi_opc = DW_CFA_GNU_start_epilogue;
+      add_fde_cfi (label, cfi_epi_start);   
+    }
+    
   if (emit_cfa_remember)
     {
       dw_cfi_ref cfi_remember;
@@ -2898,7 +2918,12 @@  dwarf2out_cfi_begin_epilogue (rtx insn)
   gcc_assert (i != NULL);
   i = next_real_insn (i);
   if (i == NULL)
-    return;
+    {
+      /* But we do mark the start of the epilogue to allow it to be skipped
+         in _eh frames.  */
+      emit_cfa_start_epilogue = true; 
+      return;
+    }
 
   /* Insert the restore before that next real insn in the stream, and before
      a potential NOTE_INSN_EPILOGUE_BEG -- we do need these notes to be
@@ -2953,6 +2978,7 @@  dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi
     case DW_CFA_GNU_window_save:
     case DW_CFA_remember_state:
     case DW_CFA_restore_state:
+    case DW_CFA_GNU_start_epilogue:
       return dw_cfi_oprnd_unused;
 
     case DW_CFA_set_loc:
@@ -3121,6 +3148,10 @@  output_cfi (dw_cfi_ref cfi, dw_fde_ref fde, int fo
       dw2_asm_output_data (1, (cfi->dw_cfi_opc | (r & 0x3f)),
 			   "DW_CFA_restore, column %#lx", r);
     }
+  else if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue)
+/* DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
   else
     {
       dw2_asm_output_data (1, cfi->dw_cfi_opc,
@@ -3303,6 +3334,12 @@  output_cfi_directive (dw_cfi_ref cfi)
 	       cfi->dw_cfi_oprnd1.dw_cfi_offset);
       break;
 
+    case DW_CFA_GNU_start_epilogue:
+/*DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
+      break;
+      
     case DW_CFA_remember_state:
       fprintf (asm_out_file, "\t.cfi_remember_state\n");
       break;
@@ -3498,6 +3535,41 @@  output_cfis (dw_cfi_ref cfi, bool do_cfi_asm, dw_f
     }
 }
 
+/* Output cfi skipping save/restore and epilogues in _eh frames
+   for targets that do not want them.  */
+
+static dw_cfi_ref
+emit_cfi_or_skip_epilogue (dw_cfi_ref cfi, dw_fde_ref fde, bool for_eh)
+{
+  if (for_eh 
+      && targetm.asm_out.suppress_eh_epilogue_p())
+    {
+      if (cfi->dw_cfi_opc == DW_CFA_remember_state)
+	{
+	  /* Skip to the restore, unless there's an error and we fall off
+	     the end.  */
+	  while (cfi->dw_cfi_next 
+		 && cfi->dw_cfi_opc != DW_CFA_restore_state) 
+	    cfi = cfi->dw_cfi_next;
+	  return cfi;
+        }
+      if (cfi->dw_cfi_opc == DW_CFA_GNU_start_epilogue)
+        {
+/*DEBUG */
+    fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START
+    		" DW_CFA_GNU_start_epilogue\n",asm_out_file);
+	  while (cfi->dw_cfi_next) 
+	    /* Skip to the end.  */
+	    cfi = cfi->dw_cfi_next;
+          return cfi;
+        }
+    }
+
+  /* if it's not a special case, then just emit it.  */
+  output_cfi (cfi, fde, for_eh);
+  return cfi;
+}
+
 /* Output one FDE.  */
 
 static void
@@ -3613,13 +3685,13 @@  output_fde (dw_fde_ref fde, bool for_eh, bool seco
   fde->dw_fde_current_label = begin;
   if (!fde->dw_fde_switched_sections)
     for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
-      output_cfi (cfi, fde, for_eh);
+      cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
   else if (!second)
     {
       if (fde->dw_fde_switch_cfi)
 	for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
 	  {
-	    output_cfi (cfi, fde, for_eh);
+	    cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
 	    if (cfi == fde->dw_fde_switch_cfi)
 	      break;
 	  }
@@ -3636,7 +3707,7 @@  output_fde (dw_fde_ref fde, bool for_eh, bool seco
 	  fde->dw_fde_switch_cfi->dw_cfi_next = cfi_next;
 	}
       for (cfi = cfi_next; cfi != NULL; cfi = cfi->dw_cfi_next)
-	output_cfi (cfi, fde, for_eh);
+	cfi = emit_cfi_or_skip_epilogue (cfi, fde, for_eh);
     }
 
   /* If we are to emit a ref/link from function bodies to their frame tables,
Index: gcc/target.def
===================================================================
--- gcc/target.def	(revision 163221)
+++ gcc/target.def	(working copy)
@@ -390,6 +406,15 @@  DEFHOOK
  void, (FILE *file, int size, rtx x),
  NULL)
 
+/* Targets might not need epilogue information in dwarf2 _eh frames.  This
+   hook should return true if the epilogue should be suppressed in such frames.
+   Epilogues will still be emitted in _debug_frames.  */
+DEFHOOK_UNDOC
+(suppress_eh_epilogue_p,
+ "",
+ bool, (void),
+ hook_bool_void_false)
+
 /* Some target machines need to postscan each insn after it is output.  */
 DEFHOOK
 (final_postscan_insn,
Index: gcc/config/darwin-protos.h
===================================================================
--- gcc/config/darwin-protos.h	(revision 163221)
+++ gcc/config/darwin-protos.h	(working copy)
@@ -83,10 +84,15 @@  extern tree darwin_handle_weak_import_attribute (t
 extern void machopic_output_stub (FILE *, const char *, const char *);
 extern void darwin_globalize_label (FILE *, const char *);
 extern void darwin_assemble_visibility (tree, int);
+
+extern bool darwin_asm_suppress_eh_epilogue_p (void);
+extern void darwin_asm_output_dwarf_section_start_label (FILE *file, 
+							section *sect);
 extern void darwin_asm_output_dwarf_delta (FILE *, int, const char *,
 					   const char *);
 extern void darwin_asm_output_dwarf_offset (FILE *, int, const char *,
 					    section *);
+
 extern void darwin_asm_declare_constant_name (FILE *, const char *,
 					      const_tree, HOST_WIDE_INT);
 extern bool darwin_binds_local_p (const_tree);
Index: gcc/config/darwin.h
===================================================================
--- gcc/config/darwin.h	(revision 163221)
+++ gcc/config/darwin.h	(working copy)
@@ -669,7 +675,6 @@  extern GTY(()) int darwin_ms_struct;
    Make Objective-C internal symbols local and in doing this, we need 
    to accommodate the name mangling done by c++ on file scope locals.  */
 
-
 int darwin_label_is_anonymous_local_objc_name (const char *name);
 
 #undef	ASM_OUTPUT_LABELREF
@@ -927,6 +932,16 @@  enum machopic_addr_class {
    ? (DW_EH_PE_pcrel | DW_EH_PE_indirect | DW_EH_PE_sdata4) : \
      ((CODE) == 1 || (GLOBAL) == 0) ? DW_EH_PE_pcrel : DW_EH_PE_absptr)
 
+/* Mark the start of each dwarf debug section to allow us to compute local
+   offsets within the sections.  We do this in darwin, rather than emitting
+   relocs.  */
+#define TARGET_ASM_OUTPUT_DWARF_SECTION_START_LABEL \
+	darwin_asm_output_dwarf_section_start_label
+
+/* For OSX compatibility we do not want to emit epilogues in _eh frames.  */
+#define TARGET_ASM_SUPPRESS_EH_EPILOGUE_P \
+	darwin_asm_suppress_eh_epilogue_p
+
 #define ASM_OUTPUT_DWARF_DELTA(FILE,SIZE,LABEL1,LABEL2)  \
   darwin_asm_output_dwarf_delta (FILE, SIZE, LABEL1, LABEL2)
 
Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c	(revision 163221)
+++ gcc/config/darwin.c	(working copy)
@@ -1666,6 +1666,36 @@  darwin_assemble_visibility (tree decl, int vis)
 	     "not supported in this configuration; ignored");
 }
 
+/* For compatibility with OSX versions that do not emit epilogues in _eh
+   frames we suppress them.  This is made a predicate function to permit 
+   us to add an OSX/FSF compatibility switch should that be required.  */
+
+bool
+darwin_asm_suppress_eh_epilogue_p (void)
+{
+  return true;
+}
+
+/* So that we can compute dwarf offsets within sections, we emit a known
+   section marker at the begining of the section.  This is distinct from
+   the ones emitted by dwarf2out.  The label is constructed by extracting
+   sectname from __DWARF,__sectname,etc,etc.  The hook should be invoked
+   once, after the first switch to the section.  */
+   
+void
+darwin_asm_output_dwarf_section_start_label (FILE *file, section *sect)
+{
+  const char *dnam;
+  int namelen;
+  gcc_assert (sect && (sect->common.flags & (SECTION_NAMED|SECTION_DEBUG)));
+  dnam = ((struct named_section *)sect)->name;
+  gcc_assert (strncmp (dnam, "__DWARF,", 8) == 0);
+  gcc_assert (strchr (dnam + 8, ','));
+
+  namelen = strchr (dnam + 8, ',') - (dnam + 8);
+  fprintf (file, "Lsection%.*s:\n", namelen, dnam + 8);
+}
+
 /* Output a difference of two labels that will be an assembly time
    constant if the two labels are local.  (.long lab1-lab2 will be
    very different if lab1 is at the boundary between two sections; it