From b78b513e41b3d491efa0bd639cedbad8622a09bd Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Wed, 7 Mar 2018 15:54:59 +0000 Subject: [PATCH] re PR target/84277 (A lot of new acats testsuite failures) PR target/84277 * except.h (output_function_exception_table): Adjust prototype. * except.c (output_function_exception_table): Remove FNNAME parameter and add SECTION parameter. Ouput one part of the table at a time. * final.c (final_scan_insn_1) : Output the first part of the exception table and emit unwind directives. * config/i386/i386-protos.h (i386_pe_end_cold_function): Declare. (i386_pe_seh_cold_init): Likewise. * config/i386/cygming.h (ASM_DECLARE_COLD_FUNCTION_NAME): New macro. (ASM_DECLARE_COLD_FUNCTION_SIZE): Likewise. * config/i386/i386.c (x86_expand_epilogue): Fix wording in comment. (ix86_output_call_insn): Emit a nop in one more case for SEH. * config/i386/winnt.c: Include except.h. (struct seh_frame_state): Add reg_offset, after_prologue and in_cold_section fields. (i386_pe_seh_end_prologue): Set seh->after_prologue. (i386_pe_seh_cold_init): New function. (i386_pe_seh_fini): Add COLD parameter and bail out if it is not equal to seh->in_cold_section. (seh_emit_push): Record the offset of the push. (seh_emit_save): Record the offet of the save. (i386_pe_seh_unwind_emit): Deal with NOTE_INSN_SWITCH_TEXT_SECTIONS. Test seh->after_prologue to disregard the epilogue. (i386_pe_end_function): Pass FALSE to i386_pe_seh_fini. (i386_pe_end_cold_function): New function. From-SVN: r258338 --- gcc/ChangeLog | 28 ++++++++++ gcc/config/i386/cygming.h | 17 ++++++ gcc/config/i386/i386-protos.h | 2 + gcc/config/i386/i386.c | 14 +++-- gcc/config/i386/winnt.c | 97 +++++++++++++++++++++++++++++++---- gcc/except.c | 30 ++++++++--- gcc/except.h | 2 +- gcc/final.c | 7 ++- 8 files changed, 176 insertions(+), 21 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 65fcf238fe1..00b79a553c9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,31 @@ +2018-03-07 Eric Botcazou + + PR target/84277 + * except.h (output_function_exception_table): Adjust prototype. + * except.c (output_function_exception_table): Remove FNNAME parameter + and add SECTION parameter. Ouput one part of the table at a time. + * final.c (final_scan_insn_1) : Output + the first part of the exception table and emit unwind directives. + * config/i386/i386-protos.h (i386_pe_end_cold_function): Declare. + (i386_pe_seh_cold_init): Likewise. + * config/i386/cygming.h (ASM_DECLARE_COLD_FUNCTION_NAME): New macro. + (ASM_DECLARE_COLD_FUNCTION_SIZE): Likewise. + * config/i386/i386.c (x86_expand_epilogue): Fix wording in comment. + (ix86_output_call_insn): Emit a nop in one more case for SEH. + * config/i386/winnt.c: Include except.h. + (struct seh_frame_state): Add reg_offset, after_prologue and + in_cold_section fields. + (i386_pe_seh_end_prologue): Set seh->after_prologue. + (i386_pe_seh_cold_init): New function. + (i386_pe_seh_fini): Add COLD parameter and bail out if it is not equal + to seh->in_cold_section. + (seh_emit_push): Record the offset of the push. + (seh_emit_save): Record the offet of the save. + (i386_pe_seh_unwind_emit): Deal with NOTE_INSN_SWITCH_TEXT_SECTIONS. + Test seh->after_prologue to disregard the epilogue. + (i386_pe_end_function): Pass FALSE to i386_pe_seh_fini. + (i386_pe_end_cold_function): New function. + 2018-03-07 Jakub Jelinek PR fortran/84565 diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 983a1847ab9..21b0f438a9a 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -312,10 +312,27 @@ do { \ #define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \ i386_pe_start_function (FILE, NAME, DECL) +/* Write the extra assembler code needed to declare the name of a + cold function partition properly. */ + +#undef ASM_DECLARE_COLD_FUNCTION_NAME +#define ASM_DECLARE_COLD_FUNCTION_NAME(FILE, NAME, DECL) \ + do \ + { \ + i386_pe_declare_function_type (FILE, NAME, 0); \ + i386_pe_seh_cold_init (FILE, NAME); \ + ASM_OUTPUT_LABEL (FILE, NAME); \ + } \ + while (0) + #undef ASM_DECLARE_FUNCTION_SIZE #define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \ i386_pe_end_function (FILE, NAME, DECL) +#undef ASM_DECLARE_COLD_FUNCTION_SIZE +#define ASM_DECLARE_COLD_FUNCTION_SIZE(FILE,NAME,DECL) \ + i386_pe_end_cold_function (FILE, NAME, DECL) + /* Add an external function to the list of functions to be declared at the end of the file. */ #define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 79b96c0f80b..ef7c818986f 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -256,6 +256,7 @@ extern void i386_pe_asm_output_aligned_decl_common (FILE *, tree, extern void i386_pe_file_end (void); extern void i386_pe_start_function (FILE *, const char *, tree); extern void i386_pe_end_function (FILE *, const char *, tree); +extern void i386_pe_end_cold_function (FILE *, const char *, tree); extern void i386_pe_assemble_visibility (tree, int); extern tree i386_pe_mangle_decl_assembler_name (tree, tree); extern tree i386_pe_mangle_assembler_name (const char *); @@ -263,6 +264,7 @@ extern void i386_pe_record_stub (const char *); extern void i386_pe_seh_init (FILE *); extern void i386_pe_seh_end_prologue (FILE *); +extern void i386_pe_seh_cold_init (FILE *, const char *); extern void i386_pe_seh_unwind_emit (FILE *, rtx_insn *); extern void i386_pe_seh_emit_except_personality (rtx); extern void i386_pe_seh_init_sections (void); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index e352303ca2f..af24c6ec5ba 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -14707,9 +14707,9 @@ ix86_expand_epilogue (int style) if (TARGET_SEH) { /* Prevent a catch region from being adjacent to the standard - epilogue sequence. Unfortuantely crtl->uses_eh_lsda nor - several other flags that would be interesting to test are - not yet set up. */ + epilogue sequence. Unfortunately neither crtl->uses_eh_lsda + nor several other flags that would be interesting to test are + set up yet. */ if (flag_non_call_exceptions) emit_insn (gen_nops (const1_rtx)); else @@ -29211,6 +29211,14 @@ ix86_output_call_insn (rtx_insn *insn, rtx call_op) for (i = NEXT_INSN (insn); i ; i = NEXT_INSN (i)) { + /* Prevent a catch region from being adjacent to a jump that would + be interpreted as an epilogue sequence by the unwinder. */ + if (JUMP_P(i) && CROSSING_JUMP_P (i)) + { + seh_nop_p = true; + break; + } + /* If we get to another real insn, we don't need the nop. */ if (INSN_P (i)) break; diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index 3e5396755ae..9b406f49094 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "emit-rtl.h" #include "cgraph.h" #include "lto-streamer.h" +#include "except.h" #include "output.h" #include "varasm.h" #include "lto-section-names.h" @@ -820,6 +821,15 @@ struct seh_frame_state /* The CFA is located at CFA_REG + CFA_OFFSET. */ HOST_WIDE_INT cfa_offset; rtx cfa_reg; + + /* The offset wrt the CFA where register N has been saved. */ + HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER]; + + /* True if we are past the end of the epilogue. */ + bool after_prologue; + + /* True if we are in the cold section. */ + bool in_cold_section; }; /* Set up data structures beginning output for SEH. */ @@ -850,10 +860,26 @@ i386_pe_seh_init (FILE *f) fputc ('\n', f); } +/* Emit an assembler directive for the end of the prologue. */ + void i386_pe_seh_end_prologue (FILE *f) +{ + if (!TARGET_SEH) + return; + if (cfun->is_thunk) + return; + cfun->machine->seh->after_prologue = true; + fputs ("\t.seh_endprologue\n", f); +} + +/* Emit assembler directives to reconstruct the SEH state. */ + +void +i386_pe_seh_cold_init (FILE *f, const char *name) { struct seh_frame_state *seh; + HOST_WIDE_INT offset; if (!TARGET_SEH) return; @@ -861,19 +887,56 @@ i386_pe_seh_end_prologue (FILE *f) return; seh = cfun->machine->seh; - XDELETE (seh); - cfun->machine->seh = NULL; + fputs ("\t.seh_proc\t", f); + assemble_name (f, name); + fputc ('\n', f); + + offset = seh->sp_offset - INCOMING_FRAME_SP_OFFSET; + if (offset > 0 && offset < SEH_MAX_FRAME_SIZE) + fprintf (f, "\t.seh_stackalloc\t" HOST_WIDE_INT_PRINT_DEC "\n", offset); + + for (int regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) + if (seh->reg_offset[regno] > 0) + { + fputs ((SSE_REGNO_P (regno) ? "\t.seh_savexmm\t" + : GENERAL_REGNO_P (regno) ? "\t.seh_savereg\t" + : (gcc_unreachable (), "")), f); + print_reg (gen_rtx_REG (DImode, regno), 0, f); + fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", + seh->sp_offset - seh->reg_offset[regno]); + } + + if (seh->cfa_reg != stack_pointer_rtx) + { + offset = seh->sp_offset - seh->cfa_offset; + + gcc_assert ((offset & 15) == 0); + gcc_assert (IN_RANGE (offset, 0, 240)); + + fputs ("\t.seh_setframe\t", f); + print_reg (seh->cfa_reg, 0, f); + fprintf (f, ", " HOST_WIDE_INT_PRINT_DEC "\n", offset); + } fputs ("\t.seh_endprologue\n", f); } +/* Emit an assembler directive for the end of the function. */ + static void -i386_pe_seh_fini (FILE *f) +i386_pe_seh_fini (FILE *f, bool cold) { + struct seh_frame_state *seh; + if (!TARGET_SEH) return; if (cfun->is_thunk) return; + seh = cfun->machine->seh; + if (cold != seh->in_cold_section) + return; + XDELETE (seh); + cfun->machine->seh = NULL; fputs ("\t.seh_endproc\n", f); } @@ -882,11 +945,12 @@ i386_pe_seh_fini (FILE *f) static void seh_emit_push (FILE *f, struct seh_frame_state *seh, rtx reg) { - unsigned int regno = REGNO (reg); + const unsigned int regno = REGNO (reg); gcc_checking_assert (GENERAL_REGNO_P (regno)); seh->sp_offset += UNITS_PER_WORD; + seh->reg_offset[regno] = seh->sp_offset; if (seh->cfa_reg == stack_pointer_rtx) seh->cfa_offset += UNITS_PER_WORD; @@ -901,9 +965,11 @@ static void seh_emit_save (FILE *f, struct seh_frame_state *seh, rtx reg, HOST_WIDE_INT cfa_offset) { - unsigned int regno = REGNO (reg); + const unsigned int regno = REGNO (reg); HOST_WIDE_INT offset; + seh->reg_offset[regno] = cfa_offset; + /* Negative save offsets are of course not supported, since that would be a store below the stack pointer and thus clobberable. */ gcc_assert (seh->sp_offset >= cfa_offset); @@ -1112,15 +1178,21 @@ i386_pe_seh_unwind_emit (FILE *asm_out_file, rtx_insn *insn) if (!TARGET_SEH) return; - /* We free the SEH data once done with the prologue. Ignore those - RTX_FRAME_RELATED_P insns that are associated with the epilogue. */ seh = cfun->machine->seh; - if (seh == NULL) - return; + if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_SWITCH_TEXT_SECTIONS) + { + fputs ("\t.seh_endproc\n", asm_out_file); + seh->in_cold_section = true; + return; + } if (NOTE_P (insn) || !RTX_FRAME_RELATED_P (insn)) return; + /* Skip RTX_FRAME_RELATED_P insns that are associated with the epilogue. */ + if (seh->after_prologue) + return; + for (note = REG_NOTES (insn); note ; note = XEXP (note, 1)) { switch (REG_NOTE_KIND (note)) @@ -1227,8 +1299,13 @@ i386_pe_start_function (FILE *f, const char *name, tree decl) void i386_pe_end_function (FILE *f, const char *, tree) { - i386_pe_seh_fini (f); + i386_pe_seh_fini (f, false); } +void +i386_pe_end_cold_function (FILE *f, const char *, tree) +{ + i386_pe_seh_fini (f, true); +} #include "gt-winnt.h" diff --git a/gcc/except.c b/gcc/except.c index 04d4764ee17..53e57732ea8 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -2939,7 +2939,6 @@ switch_to_exception_section (const char * ARG_UNUSED (fnname)) switch_to_section (s); } - /* Output a reference from an exception table to the type_info object TYPE. TT_FORMAT and TT_FORMAT_SIZE describe the DWARF encoding method used for the value. */ @@ -2989,6 +2988,13 @@ output_ttype (tree type, int tt_format, int tt_format_size) dw2_asm_output_encoded_addr_rtx (tt_format, value, is_public, NULL); } +/* Output an exception table for the current function according to SECTION. + + If the function has been partitioned into hot and cold parts, value 0 for + SECTION refers to the table associated with the hot part while value 1 + refers to the table associated with the cold part. If the function has + not been partitioned, value 0 refers to the single exception table. */ + static void output_one_function_exception_table (int section) { @@ -3167,13 +3173,26 @@ output_one_function_exception_table (int section) } } +/* Output an exception table for the current function according to SECTION, + switching back and forth from the function section appropriately. + + If the function has been partitioned into hot and cold parts, value 0 for + SECTION refers to the table associated with the hot part while value 1 + refers to the table associated with the cold part. If the function has + not been partitioned, value 0 refers to the single exception table. */ + void -output_function_exception_table (const char *fnname) +output_function_exception_table (int section) { + const char *fnname = get_fnname_from_decl (current_function_decl); rtx personality = get_personality_function (current_function_decl); /* Not all functions need anything. */ - if (! crtl->uses_eh_lsda) + if (!crtl->uses_eh_lsda) + return; + + /* No need to emit any boilerplate stuff for the cold part. */ + if (section == 1 && !crtl->eh.call_site_record_v[1]) return; if (personality) @@ -3189,9 +3208,8 @@ output_function_exception_table (const char *fnname) /* If the target wants a label to begin the table, emit it here. */ targetm.asm_out.emit_except_table_label (asm_out_file); - output_one_function_exception_table (0); - if (crtl->eh.call_site_record_v[1]) - output_one_function_exception_table (1); + /* Do the real work. */ + output_one_function_exception_table (section); switch_to_section (current_function_section ()); } diff --git a/gcc/except.h b/gcc/except.h index 0111b9f4c34..229e446cb65 100644 --- a/gcc/except.h +++ b/gcc/except.h @@ -229,7 +229,7 @@ extern void remove_eh_handler (eh_region); extern void remove_unreachable_eh_regions (sbitmap); extern bool current_function_has_exception_handlers (void); -extern void output_function_exception_table (const char *); +extern void output_function_exception_table (int); extern rtx expand_builtin_eh_pointer (tree); extern rtx expand_builtin_eh_filter (tree); diff --git a/gcc/final.c b/gcc/final.c index b3450a14897..87a3067f3b1 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2265,6 +2265,11 @@ final_scan_insn_1 (rtx_insn *insn, FILE *file, int optimize_p ATTRIBUTE_UNUSED, case NOTE_INSN_SWITCH_TEXT_SECTIONS: maybe_output_next_view (seen); + output_function_exception_table (0); + + if (targetm.asm_out.unwind_emit) + targetm.asm_out.unwind_emit (asm_out_file, insn); + in_cold_section_p = !in_cold_section_p; if (in_cold_section_p) @@ -4672,7 +4677,7 @@ rest_of_handle_final (void) /* The IA-64 ".handlerdata" directive must be issued before the ".endp" directive that closes the procedure descriptor. Similarly, for x64 SEH. Otherwise it's not strictly necessary, but it doesn't hurt either. */ - output_function_exception_table (fnname); + output_function_exception_table (crtl->has_bb_partition ? 1 : 0); assemble_end_function (current_function_decl, fnname); -- 2.30.2