diff --git a/gcc/config/rs6000/rs6000-logue.cc b/gcc/config/rs6000/rs6000-logue.cc index aa07d79d974..52f44b114b0 100644 --- a/gcc/config/rs6000/rs6000-logue.cc +++ b/gcc/config/rs6000/rs6000-logue.cc @@ -4005,8 +4005,8 @@ rs6000_output_function_prologue (FILE *file) unsigned short patch_area_size = crtl->patch_area_size; unsigned short patch_area_entry = crtl->patch_area_entry; - /* Need to emit the patching area. */ - if (patch_area_size > 0) + /* Emit non-split patching area now. */ + if (!TARGET_SPLIT_PATCH_NOPS && patch_area_size > 0) { cfun->machine->global_entry_emitted = true; /* As ELFv2 ABI shows, the allowable bytes between the global @@ -4027,7 +4027,6 @@ rs6000_output_function_prologue (FILE *file) patch_area_entry); rs6000_print_patchable_function_entry (file, patch_area_entry, true); - patch_area_size -= patch_area_entry; } } @@ -4037,9 +4036,13 @@ rs6000_output_function_prologue (FILE *file) assemble_name (file, name); fputs ("\n", file); /* Emit the nops after local entry. */ - if (patch_area_size > 0) - rs6000_print_patchable_function_entry (file, patch_area_size, - patch_area_entry == 0); + if (patch_area_size > patch_area_entry) + { + patch_area_size -= patch_area_entry; + cfun->machine->stop_patch_area_print = false; + rs6000_print_patchable_function_entry (file, patch_area_size, + patch_area_entry == 0); + } } else if (rs6000_pcrel_p ()) diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc index 675b039c2b6..737c3d6f7c7 100644 --- a/gcc/config/rs6000/rs6000.cc +++ b/gcc/config/rs6000/rs6000.cc @@ -15245,11 +15245,25 @@ rs6000_print_patchable_function_entry (FILE *file, { bool global_entry_needed_p = rs6000_global_entry_point_prologue_needed_p (); /* For a function which needs global entry point, we will emit the - patchable area before and after local entry point under the control of - cfun->machine->global_entry_emitted, see the handling in function - rs6000_output_function_prologue. */ - if (!global_entry_needed_p || cfun->machine->global_entry_emitted) + patchable area when it isn't split before and after local entry point + under the control of cfun->machine->global_entry_emitted, see the + handling in function rs6000_output_function_prologue. */ + if (!TARGET_SPLIT_PATCH_NOPS + && (!global_entry_needed_p || cfun->machine->global_entry_emitted)) default_print_patchable_function_entry (file, patch_area_size, record_p); + + /* For split patch nops we emit the before nops (from generic code) + in front of the global entry point and after the local entry point, + under the control of cfun->machine->stop_patch_area_print, see + rs6000_output_function_prologue and rs6000_elf_declare_function_name. */ + if (TARGET_SPLIT_PATCH_NOPS) + { + if (!cfun->machine->stop_patch_area_print) + default_print_patchable_function_entry (file, patch_area_size, + record_p); + else + gcc_assert (global_entry_needed_p); + } } enum rtx_code @@ -21365,6 +21379,11 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl) fprintf (file, "\t.previous\n"); } ASM_OUTPUT_FUNCTION_LABEL (file, name, decl); + /* At this time, the "before" NOPs have been already emitted. + For split nops stop generic code from printing the "after" NOPs and + emit them just after local entry ourself later. */ + if (rs6000_global_entry_point_prologue_needed_p ()) + cfun->machine->stop_patch_area_print = true; } static void rs6000_elf_file_end (void) ATTRIBUTE_UNUSED; diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index a60d7a53cfa..db6112a09e1 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -2422,6 +2422,12 @@ typedef struct GTY(()) machine_function local entry. */ bool global_entry_emitted; bool asm_redzone_clobber_seen; + /* With ELFv2 ABI dual entry points being adopted, generic framework + targetm.asm_out.print_patchable_function_entry would generate "after" + NOPs before local entry, which is wrong. This flag is to stop it from + printing patch area before local entry, it is only useful when the + function requires dual entry points. */ + bool stop_patch_area_print; } machine_function; #endif diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 77e01528960..88cf16ca581 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -300,6 +300,10 @@ mfull-toc Target Put everything in the regular TOC. +msplit-patch-nops +Target Var(TARGET_SPLIT_PATCH_NOPS) Init(0) +Emit NOPs before global and after local entry point for -fpatchable-function-entry. + mvrsave Target Var(TARGET_ALTIVEC_VRSAVE) Save Generate VRSAVE instructions when generating AltiVec code. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 26b3dd93961..7bef9bbf1c0 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -1320,6 +1320,7 @@ See RS/6000 and PowerPC Options. -mtraceback=@var{traceback_type} -maix-struct-return -msvr4-struct-return -mabi=@var{abi-type} -msecure-plt -mbss-plt +-msplit-patch-nops -mlongcall -mno-longcall -mpltseq -mno-pltseq -mblock-move-inline-limit=@var{num} -mblock-compare-inline-limit=@var{num} @@ -18805,11 +18806,12 @@ If @code{N=0}, no pad location is recorded. The NOP instructions are inserted at---and maybe before, depending on @var{M}---the function entry address, even before the prologue. On PowerPC with the ELFv2 ABI, for a function with dual entry points, -the local entry point is this function entry address. +the local entry point is this function entry address by default. See +the @option{-msplit-patch-nops} option to change this. The maximum value of @var{N} and @var{M} is 65535. On PowerPC with the ELFv2 ABI, for a function with dual entry points, the supported values -for @var{M} are 0, 2, 6 and 14. +for @var{M} are 0, 2, 6 and 14 when not using @option{-msplit-patch-nops}. @end table @@ -31849,6 +31851,17 @@ requires @code{.plt} and @code{.got} sections that are both writable and executable. This is a PowerPC 32-bit SYSV ABI option. +@opindex msplit-patch-nops +@item -msplit-patch-nops +When adding NOPs for a patchable area via the +@option{-fpatchable-function-entry} option emit the ``before'' NOPs in front +of the global entry point and the ``after'' NOPs after the local entry point. +This makes the sequence of NOPs not consecutive when a global entry point +is generated. Without this option the NOPs are emitted directly before and +after the local entry point, making them consecutive but moving global and +local entry point further apart. If only a single entry point is generated +this option has no effect. + @opindex misel @opindex mno-isel @item -misel