From patchwork Sun Aug 15 19:53:31 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [_eh, dawin, Version2] Allow targets to suppress epilogues in _eh frames. Date: Sun, 15 Aug 2010 09:53:31 -0000 From: IainS X-Patchwork-Id: 61757 Message-Id: <6FABA122-72B5-4F9B-8573-FCFF1481700C@sandoe-acoustics.co.uk> To: Richard Henderson Cc: GCC Patches , mrs@gcc.gnu.org Hi Richard, Well, of course your suggestions (and Jakub's comments in irc) resulted a better solution. [the questions in a previous follow-up mail re. the GNU opcode still stand - but don't affect the base patch]. this has been looped around a few times on darwin9 & 10 and bootstrapped on x86_64-unk-linux-gnu. Ok for trunk now? Iain On 14 Aug 2010, at 00:27, Richard Henderson wrote: > 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; done. > 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. done >> +/* 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. done. > At that point you can adjust Darwin's override_options hook(s) to make > sure that this flag is appropriately off. not so simple - because toplev.c manipulates it unconditionally - I've adjusted toplev to set the flag only if it is unset. and will make manipulation of default settings on darwin a separate patch (darwin does not yet use that hook). > 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. At present, I'm going to leave the compact unwinder disabled on Darwin10, it seems from the testing done by Jack that there are a bunch of other (probably non-gnu) issues to iron out on that yet. Ergo, the spec is not needed yet. === gcc: * gcc/dwarf2out.c: DW_CFA_INTERNAL_start_epilogue, CFI_T New. (struct dw_cfi_struct): Adjust type of dw_cfi_opc. (add_fde_cfi): Handle DW_CFA_INTERNAL_start_epilogue. (dwarf2out_cfi_begin_epilogue): Insert epilogue marker. (dw_cfi_oprnd1_desc): Adjust argument type. (dw_cfi_oprnd2_desc): Ditto. (output_cfi_directive): Handle DW_CFA_INTERNAL_start_epilogue. (emit_cfi_or_skip_epilogue): New. (output_fde): Use emit_cfi_or_skip_epilogue. *gcc/toplev.c (process_options): Do not set flag_asynchronous_unwind_tables unless it is unset by the target. Set flag_unwind_tables for either flag_asynchronous_unwind_tables or flag_non_call_exceptions. * gcc/config/darwin.c (darwin_override_options): Warn the the target does not fully support flag_asynchronous_unwind_tables. Switch flag_unwind_tables on for flag_non_call_exceptions or flag_exceptions on darwin versions supporting _eh frames. Ensure that all table flags are switched off for kernel code. ==== Index: gcc/dwarf2out.c =================================================================== --- gcc/dwarf2out.c (revision 163267) +++ gcc/dwarf2out.c (working copy) @@ -268,12 +272,20 @@ typedef union GTY(()) dw_cfi_oprnd_struct { } dw_cfi_oprnd; +/* Use the first out-of-band opcode number as a marker for the start of + epilogues. */ +#define DW_CFA_INTERNAL_start_epilogue 0x100 +#define CFI_T enum dwarf_call_frame_info + +static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc (unsigned int cfi); +static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc (unsigned int cfi); + typedef struct GTY(()) dw_cfi_struct { dw_cfi_ref dw_cfi_next; - enum dwarf_call_frame_info dw_cfi_opc; - dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc (%1.dw_cfi_opc)"))) + unsigned int dw_cfi_opc; + dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd1_desc ((unsigned int)%1.dw_cfi_opc)"))) dw_cfi_oprnd1; - dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc (%1.dw_cfi_opc)"))) + dw_cfi_oprnd GTY ((desc ("dw_cfi_oprnd2_desc ((unsigned int)%1.dw_cfi_opc)"))) dw_cfi_oprnd2; } dw_cfi_node; @@ -821,9 +833,15 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) } list_head = &cie_cfi_head; - - if (dwarf2out_do_cfi_asm ()) + + if (cfi->dw_cfi_opc == DW_CFA_INTERNAL_start_epilogue) { + dw_fde_ref fde = current_fde (); + gcc_assert (fde != NULL); + list_head = &fde->dw_fde_cfi; + } + else if (dwarf2out_do_cfi_asm ()) + { if (label) { dw_fde_ref fde = current_fde (); @@ -850,6 +868,7 @@ add_fde_cfi (const char *label, dw_cfi_ref cfi) case DW_CFA_def_cfa_sf: case DW_CFA_def_cfa_expression: case DW_CFA_restore_state: + case DW_CFA_INTERNAL_start_epilogue: if (*label == 0 || strcmp (label, "") == 0) label = dwarf2out_cfi_label (true); @@ -2894,12 +2913,22 @@ dwarf2out_cfi_begin_epilogue (rtx insn) return; /* Otherwise, search forward to see if the return insn was the last - basic block of the function. If so, we don't need save/restore. */ + basic block of the function. If so, we don't need save/restore. + However, we do mark the position so that we can skip the epilogue + in _eh frames where required. */ gcc_assert (i != NULL); i = next_real_insn (i); if (i == NULL) - return; + { + dw_cfi_ref cfi_epi_start; + /* Emit a marker for the epilogue start. */ + cfi_epi_start = new_cfi (); + cfi_epi_start->dw_cfi_opc = DW_CFA_INTERNAL_start_epilogue; + add_fde_cfi ("", cfi_epi_start); + 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 properly nested. This should be after any label or alignment. This @@ -2941,11 +2970,9 @@ dwarf2out_frame_debug_restore_state (void) } /* Describe for the GTY machinery what parts of dw_cfi_oprnd1 are used. */ -static enum dw_cfi_oprnd_type dw_cfi_oprnd1_desc - (enum dwarf_call_frame_info cfi); static enum dw_cfi_oprnd_type -dw_cfi_oprnd1_desc (enum dwarf_call_frame_info cfi) +dw_cfi_oprnd1_desc (unsigned int cfi) { switch (cfi) { @@ -2953,6 +2980,7 @@ static enum dw_cfi_oprnd_type case DW_CFA_GNU_window_save: case DW_CFA_remember_state: case DW_CFA_restore_state: + case DW_CFA_INTERNAL_start_epilogue: return dw_cfi_oprnd_unused; case DW_CFA_set_loc: @@ -2990,11 +3018,9 @@ static enum dw_cfi_oprnd_type } /* Describe for the GTY machinery what parts of dw_cfi_oprnd2 are used. */ -static enum dw_cfi_oprnd_type dw_cfi_oprnd2_desc - (enum dwarf_call_frame_info cfi); static enum dw_cfi_oprnd_type -dw_cfi_oprnd2_desc (enum dwarf_call_frame_info cfi) +dw_cfi_oprnd2_desc (unsigned int cfi) { switch (cfi) { @@ -3121,6 +3148,13 @@ 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_INTERNAL_start_epilogue) + { + /* This is a nop unless we want a debug message. */ + if (flag_debug_asm) + fputs (ASM_COMMENT_START"\t\t\t" ASM_COMMENT_START + " DW_CFA_INTERNAL_start_epilogue\n",asm_out_file); + } else { dw2_asm_output_data (1, cfi->dw_cfi_opc, @@ -3303,6 +3337,13 @@ output_cfi_directive (dw_cfi_ref cfi) cfi->dw_cfi_oprnd1.dw_cfi_offset); break; + case DW_CFA_INTERNAL_start_epilogue: + /* no-op apart from an informational message. */ + if (flag_debug_asm) + fputs (ASM_COMMENT_START"\t\t\t" ASM_COMMENT_START + " DW_CFA_INTERNAL_start_epilogue\n",asm_out_file); + break; + case DW_CFA_remember_state: fprintf (asm_out_file, "\t.cfi_remember_state\n"); break; @@ -3498,6 +3539,46 @@ 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 + && !flag_asynchronous_unwind_tables) + { + if (cfi->dw_cfi_opc == DW_CFA_remember_state) + { + if (flag_debug_asm) + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_remember/restore_state pair skipped\n",asm_out_file); + /* 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_INTERNAL_start_epilogue) + { + if (flag_debug_asm) + fputs (ASM_COMMENT_START"\t\t\t"ASM_COMMENT_START + " DW_CFA_INTERNAL_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 carry on. + This will also cause the no-op 'DW_CFA_INTERNAL_start_epilogue' to be + listed when flag_debug_asm is set. */ + output_cfi (cfi, fde, for_eh); + return cfi; +} + /* Output one FDE. */ static void @@ -3613,13 +3694,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; } @@ -3627,7 +3708,6 @@ output_fde (dw_fde_ref fde, bool for_eh, bool seco else { dw_cfi_ref cfi_next = fde->dw_fde_cfi; - if (fde->dw_fde_switch_cfi) { cfi_next = fde->dw_fde_switch_cfi->dw_cfi_next; @@ -3636,7 +3716,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/toplev.c =================================================================== --- gcc/toplev.c (revision 163267) +++ gcc/toplev.c (working copy) @@ -1798,9 +1801,9 @@ process_options (void) if (flag_rename_registers == AUTODETECT_VALUE) flag_rename_registers = flag_unroll_loops || flag_peel_loops; - if (flag_non_call_exceptions) + if (flag_non_call_exceptions && flag_asynchronous_unwind_tables == 2) flag_asynchronous_unwind_tables = 1; - if (flag_asynchronous_unwind_tables) + if (flag_asynchronous_unwind_tables || flag_non_call_exceptions) flag_unwind_tables = 1; if (flag_value_profile_transformations) Index: gcc/config/darwin.c =================================================================== --- gcc/config/darwin.c (revision 163267) +++ gcc/config/darwin.c (working copy) @@ -1884,7 +1915,22 @@ darwin_override_options (void) flag_reorder_blocks_and_partition = 0; flag_reorder_blocks = 1; } + + if (flag_asynchronous_unwind_tables) + { + if (flag_asynchronous_unwind_tables == 2) + flag_asynchronous_unwind_tables = 0; + else + /* Issue a warning */ + warning (OPT_Wall, + "this architecture does not fully support" + " -fasynchronous-unwind-tables"); + } + if ((flag_exceptions || flag_non_call_exceptions) + && strverscmp (darwin_macosx_version_min, "10.4") >= 0) + flag_unwind_tables = 1; + if (flag_mkernel || flag_apple_kext) { /* -mkernel implies -fapple-kext for C++ */ @@ -1897,6 +1943,9 @@ darwin_override_options (void) flag_exceptions = 0; /* No -fnon-call-exceptions data in kexts. */ flag_non_call_exceptions = 0; + /* so no tables either.. */ + flag_unwind_tables = 0; + flag_asynchronous_unwind_tables = 0; /* We still need to emit branch islands for kernel context. */ darwin_emit_branch_islands = true; }