tree *args ATTRIBUTE_UNUSED,
bool ignore ATTRIBUTE_UNUSED);
+extern void rs6000_print_patchable_function_entry (FILE *,
+ unsigned HOST_WIDE_INT,
+ bool);
+
extern bool rs6000_passes_float;
extern bool rs6000_passes_long_double;
extern bool rs6000_passes_vector;
fprintf (file, "\tadd 2,2,12\n");
}
+ 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)
+ {
+ cfun->machine->global_entry_emitted = true;
+ /* As ELFv2 ABI shows, the allowable bytes between the global
+ and local entry points are 0, 4, 8, 16, 32 and 64 when
+ there is a local entry point. Considering there are two
+ non-prefixed instructions for global entry point prologue
+ (8 bytes), the count for patchable nops before local entry
+ point would be 2, 6 and 14. It's possible to support those
+ other counts of nops by not making a local entry point, but
+ we don't have clear use cases for them, so leave them
+ unsupported for now. */
+ if (patch_area_entry > 0)
+ {
+ if (patch_area_entry != 2
+ && patch_area_entry != 6
+ && patch_area_entry != 14)
+ error ("unsupported number of nops before function entry (%u)",
+ patch_area_entry);
+ rs6000_print_patchable_function_entry (file, patch_area_entry,
+ true);
+ patch_area_size -= patch_area_entry;
+ }
+ }
+
fputs ("\t.localentry\t", file);
assemble_name (file, name);
fputs (",.-", 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);
}
else if (rs6000_pcrel_p ())
if (!(TARGET_64BIT && DEFAULT_ABI != ABI_ELFv2)
&& HAVE_GAS_SECTION_LINK_ORDER)
flags |= SECTION_LINK_ORDER;
- default_print_patchable_function_entry_1 (file, patch_area_size, record_p,
- flags);
+ 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)
+ default_print_patchable_function_entry_1 (file, patch_area_size, record_p,
+ flags);
}
\f
enum rtx_code
bool lr_is_wrapped_separately;
bool toc_is_wrapped_separately;
bool mma_return_type_error;
+ /* Indicate global entry is emitted, only useful when the function requires
+ global entry. It helps to control the patchable area before and after
+ local entry. */
+ bool global_entry_emitted;
} machine_function;
#endif
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.
+@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 maximum value of @var{N} and @var{M} is 65535.
+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.
@end table
/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
/* { dg-options "-O2 -fpatchable-function-entry=3,1" } */
/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
+/* See PR99888, one single preceding nop isn't allowed on powerpc_elfv2,
+ so overriding with two preceding nops to make it pass there. */
+/* { dg-additional-options "-fpatchable-function-entry=3,2" { target powerpc_elfv2 } } */
/* { dg-final { scan-assembler-times "nop|NOP|SWYM" 3 { target { ! { alpha*-*-* } } } } } */
/* { dg-final { scan-assembler-times "bis" 3 { target alpha*-*-* } } } */
--- /dev/null
+/* Verify no errors for different nops after local entry on ELFv2. */
+
+extern int a;
+
+__attribute__ ((noipa, patchable_function_entry (1, 0)))
+int test1 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (2, 0)))
+int test2 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (3, 0)))
+int test3 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (4, 0)))
+int test4 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (5, 0)))
+int test5 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (6, 0)))
+int test6 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (7, 0)))
+int test7 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (8, 0)))
+int test8 (int b) {
+ return a + b;
+}
--- /dev/null
+/* Verify no errors for 2, 6 and 14 nops before local entry on ELFv2. */
+
+extern int a;
+
+__attribute__ ((noipa, patchable_function_entry (2, 2)))
+int test1 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (4, 2)))
+int test2 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (6, 6)))
+int test3 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (8, 6)))
+int test4 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (16, 6)))
+int test5 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (14, 14)))
+int test6 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (28, 14)))
+int test7 (int b) {
+ return a + b;
+}
+
+__attribute__ ((noipa, patchable_function_entry (64, 14)))
+int test8 (int b) {
+ return a + b;
+}
--- /dev/null
+/* { dg-options "-fpatchable-function-entry=1" } */
+
+/* Verify no errors on ELFv2, using command line option instead of
+ function attribute. */
+
+extern int a;
+
+int test (int b) {
+ return a + b;
+}
+
--- /dev/null
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* There is no global entry point prologue with pcrel. */
+/* { dg-options "-mno-pcrel -fpatchable-function-entry=1,1" } */
+
+/* Verify one error emitted for unexpected 1 nop before local
+ entry. */
+
+extern int a;
+
+int test (int b) {
+ return a + b;
+}
+/* { dg-error "unsupported number of nops before function entry \\(1\\)" "" { target *-*-* } .-1 } */
--- /dev/null
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* There is no global entry point prologue with pcrel. */
+/* { dg-options "-mno-pcrel -fpatchable-function-entry=7,3" } */
+
+/* Verify one error emitted for unexpected 3 nops before local
+ entry. */
+
+extern int a;
+
+int test (int b) {
+ return a + b;
+}
+/* { dg-error "unsupported number of nops before function entry \\(3\\)" "" { target *-*-* } .-1 } */
--- /dev/null
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* There is no global entry point prologue with pcrel. */
+/* { dg-options "-mno-pcrel" } */
+
+/* Verify one error emitted for unexpected 4 nops before local
+ entry. */
+
+extern int a;
+
+__attribute__ ((patchable_function_entry (20, 4)))
+int test (int b) {
+ return a + b;
+}
+/* { dg-error "unsupported number of nops before function entry \\(4\\)" "" { target *-*-* } .-1 } */