summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2018-03-07 15:54:59 +0000
committerebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>2018-03-07 15:54:59 +0000
commit720d31166435c7d4446bc6323301914cd52fcdab (patch)
tree5043355c1914fa0a327adcad08751d898419f92f
parentd47db6951939a4f595ae66cef747a486f83e54af (diff)
downloadgcc-720d31166435c7d4446bc6323301914cd52fcdab.tar.gz
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) <NOTE_INSN_SWITCH_TEXT_SECTIONS>: 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@258338 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog28
-rw-r--r--gcc/config/i386/cygming.h17
-rw-r--r--gcc/config/i386/i386-protos.h2
-rw-r--r--gcc/config/i386/i386.c14
-rw-r--r--gcc/config/i386/winnt.c97
-rw-r--r--gcc/except.c30
-rw-r--r--gcc/except.h2
-rw-r--r--gcc/final.c7
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 <ebotcazou@adacore.com>
+
+ 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) <NOTE_INSN_SWITCH_TEXT_SECTIONS>: 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 <jakub@redhat.com>
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);