From 30ab9654d4023334c8b5f2fcc061110b7ef8bec2 Mon Sep 17 00:00:00 2001 From: iains Date: Sun, 11 Dec 2016 16:10:48 +0000 Subject: [Darwin] Back-port fix for PR57438. gcc/ 2016-12-11 Iain Sandoe Backport from mainline 2016-11-27 Iain Sandoe PR target/57438 * config/i386/i386.c (ix86_code_end): Note that we emitted code where the function might otherwise appear empty for picbase thunks. (ix86_output_function_epilogue): If we find a zero-sized function assume that reaching it is UB and trap. If we find a trailing label append a nop. * config/rs6000/rs6000.c (rs6000_output_function_epilogue): If we find a zero-sized function assume that reaching it is UB and trap. If we find a trailing label, append a nop. gcc/testsuite/ 2016-12-11 Iain Sandoe Backport from mainline 2016-11-27 Iain Sandoe PR target/57438 * gcc.dg/pr57438-1.c: New Test. * gcc.dg/pr57438-2.c: New Test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-6-branch@243525 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 15 +++++++ gcc/config/i386/i386.c | 91 +++++++++++++++++++++++++++------------- gcc/config/rs6000/rs6000.c | 45 +++++++++++++++++--- gcc/testsuite/ChangeLog | 10 ++++- gcc/testsuite/gcc.dg/pr57438-1.c | 16 +++++++ gcc/testsuite/gcc.dg/pr57438-2.c | 23 ++++++++++ 6 files changed, 165 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr57438-1.c create mode 100644 gcc/testsuite/gcc.dg/pr57438-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5eb4bad303a..50578c8002a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -3,6 +3,21 @@ Backport from mainline 2016-11-27 Iain Sandoe + PR target/57438 + * config/i386/i386.c (ix86_code_end): Note that we emitted code + where the function might otherwise appear empty for picbase thunks. + (ix86_output_function_epilogue): If we find a zero-sized function + assume that reaching it is UB and trap. If we find a trailing label + append a nop. + * config/rs6000/rs6000.c (rs6000_output_function_epilogue): If we + find a zero-sized function assume that reaching it is UB and trap. + If we find a trailing label, append a nop. + +2016-12-11 Iain Sandoe + + Backport from mainline + 2016-11-27 Iain Sandoe + PR target/71767 * config/darwin-sections.def (picbase_thunk_section): New. * config/darwin.c (darwin_init_sections): Set up picbase thunk diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9cbc4ccf4c1..c0855c94a17 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -11084,6 +11084,9 @@ ix86_code_end (void) current_function_decl = decl; allocate_struct_function (decl, false); init_function_start (decl); + /* We're about to hide the function body from callees of final_* by + emitting it directly; tell them we're a thunk, if they care. */ + cfun->is_thunk = true; first_function_block_is_cold = false; /* Make sure unwind info is emitted for the thunk if needed. */ final_start_function (emit_barrier (), asm_out_file, 1); @@ -13709,36 +13712,68 @@ ix86_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT) if (pic_offset_table_rtx && !ix86_use_pseudo_pic_reg ()) SET_REGNO (pic_offset_table_rtx, REAL_PIC_OFFSET_TABLE_REGNUM); -#if TARGET_MACHO - /* Mach-O doesn't support labels at the end of objects, so if - it looks like we might want one, insert a NOP. */ - { - rtx_insn *insn = get_last_insn (); - rtx_insn *deleted_debug_label = NULL; - while (insn - && NOTE_P (insn) - && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL) - { - /* Don't insert a nop for NOTE_INSN_DELETED_DEBUG_LABEL - notes only, instead set their CODE_LABEL_NUMBER to -1, - otherwise there would be code generation differences - in between -g and -g0. */ - if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL) - deleted_debug_label = insn; + + if (TARGET_MACHO) + { + rtx_insn *insn = get_last_insn (); + rtx_insn *deleted_debug_label = NULL; + + /* Mach-O doesn't support labels at the end of objects, so if + it looks like we might want one, take special action. + First, collect any sequence of deleted debug labels. */ + while (insn + && NOTE_P (insn) + && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL) + { + /* Don't insert a nop for NOTE_INSN_DELETED_DEBUG_LABEL + notes only, instead set their CODE_LABEL_NUMBER to -1, + otherwise there would be code generation differences + in between -g and -g0. */ + if (NOTE_P (insn) && NOTE_KIND (insn) + == NOTE_INSN_DELETED_DEBUG_LABEL) + deleted_debug_label = insn; + insn = PREV_INSN (insn); + } + + /* If we have: + label: + barrier + then this needs to be detected, so skip past the barrier. */ + + if (insn && BARRIER_P (insn)) insn = PREV_INSN (insn); - } - if (insn - && (LABEL_P (insn) - || (NOTE_P (insn) - && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))) - fputs ("\tnop\n", file); - else if (deleted_debug_label) - for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn)) - if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL) - CODE_LABEL_NUMBER (insn) = -1; - } -#endif + /* Up to now we've only seen notes or barriers. */ + if (insn) + { + if (LABEL_P (insn) + || (NOTE_P (insn) + && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)) + /* Trailing label. */ + fputs ("\tnop\n", file); + else if (cfun && ! cfun->is_thunk) + { + /* See if we have a completely empty function body, skipping + the special case of the picbase thunk emitted as asm. */ + while (insn && ! INSN_P (insn)) + insn = PREV_INSN (insn); + /* If we don't find any insns, we've got an empty function body; + I.e. completely empty - without a return or branch. This is + taken as the case where a function body has been removed + because it contains an inline __builtin_unreachable(). GCC + declares that reaching __builtin_unreachable() means UB so + we're not obliged to do anything special; however, we want + non-zero-sized function bodies. To meet this, and help the + user out, let's trap the case. */ + if (insn == NULL) + fputs ("\tud2\n", file); + } + } + else if (deleted_debug_label) + for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn)) + if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL) + CODE_LABEL_NUMBER (insn) = -1; + } } /* Return a scratch register to use in the split stack prologue. The diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 8907aed2c3f..e319b26755c 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -28446,11 +28446,15 @@ rs6000_output_function_epilogue (FILE *file, { #if TARGET_MACHO macho_branch_islands (); - /* Mach-O doesn't support labels at the end of objects, so if - it looks like we might want one, insert a NOP. */ + { rtx_insn *insn = get_last_insn (); rtx_insn *deleted_debug_label = NULL; + + /* Mach-O doesn't support labels at the end of objects, so if + it looks like we might want one, take special action. + + First, collect any sequence of deleted debug labels. */ while (insn && NOTE_P (insn) && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL) @@ -28463,11 +28467,40 @@ rs6000_output_function_epilogue (FILE *file, deleted_debug_label = insn; insn = PREV_INSN (insn); } - if (insn - && (LABEL_P (insn) + + /* Second, if we have: + label: + barrier + then this needs to be detected, so skip past the barrier. */ + + if (insn && BARRIER_P (insn)) + insn = PREV_INSN (insn); + + /* Up to now we've only seen notes or barriers. */ + if (insn) + { + if (LABEL_P (insn) || (NOTE_P (insn) - && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))) - fputs ("\tnop\n", file); + && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)) + /* Trailing label: . */ + fputs ("\tnop\n", file); + else + { + /* Lastly, see if we have a completely empty function body. */ + while (insn && ! INSN_P (insn)) + insn = PREV_INSN (insn); + /* If we don't find any insns, we've got an empty function body; + I.e. completely empty - without a return or branch. This is + taken as the case where a function body has been removed + because it contains an inline __builtin_unreachable(). GCC + states that reaching __builtin_unreachable() means UB so we're + not obliged to do anything special; however, we want + non-zero-sized function bodies. To meet this, and help the + user out, let's trap the case. */ + if (insn == NULL) + fputs ("\ttrap\n", file); + } + } else if (deleted_debug_label) for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn)) if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 97148591382..a3146c3a4b6 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2016-12-11 Iain Sandoe + + Backport from mainline + 2016-11-27 Iain Sandoe + + PR target/57438 + * gcc.dg/pr57438-1.c: New Test. + * gcc.dg/pr57438-2.c: New Test. + 2016-12-11 Iain Sandoe Backport from mainline @@ -10,7 +19,6 @@ * g++.dg/torture/darwin-cfstring-3.C: Likewise. * gcc.dg/const-uniq-1.c: Likewise. * gcc.dg/torture/darwin-cfstring-3.c: Likewise. - * gcc.target/i386/pr70799-1.c: Likewise. 2016-12-09 Thomas Preud'homme diff --git a/gcc/testsuite/gcc.dg/pr57438-1.c b/gcc/testsuite/gcc.dg/pr57438-1.c new file mode 100644 index 00000000000..9bfd8b9d911 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr57438-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-options "-O1" } */ +/* { dg-additional-options "-mdynamic-no-pic" { target powerpc*-*-darwin* } } + +/* This is testing that a completely empty function body results in the + insertion of a ud2/trap instruction to prevent a zero-sized FDE, and/or + the function label apparently pointing to following code. */ + +__attribute__((noinline)) +void foo (void) +{ + __builtin_unreachable(); +} + +/* { dg-final { scan-assembler "ud2" { target { i?86-*-darwin* x86_64-*-darwin* } } } } */ +/* { dg-final { scan-assembler "trap" { target { powerpc*-*-darwin* } } } } */ diff --git a/gcc/testsuite/gcc.dg/pr57438-2.c b/gcc/testsuite/gcc.dg/pr57438-2.c new file mode 100644 index 00000000000..c64a31353a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr57438-2.c @@ -0,0 +1,23 @@ +/* { dg-do compile { target *-*-darwin* } } */ +/* { dg-options "--param case-values-threshold=3 -O2" } */ +/* { dg-additional-options "-funwind-tables" { target powerpc*-*-darwin* } } + +/* This is testing that a trailing local label is followed by a + nop where required. */ + +int foo (int x) +{ + switch (x) + { + case 0: + return 10; + case 3: + return -1; + case 5: + return 29; + default: + __builtin_unreachable(); + } +} + +/* { dg-final { scan-assembler "nop\\nLFE.*" { target { *-*-darwin* } } } } */ -- cgit v1.2.1