@@ -182,10 +182,15 @@ extern tree rs6000_fold_builtin (tree fndecl ATTRIBUTE_UNUSED,
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;
extern bool rs6000_returns_struct;
extern bool cpu_builtin_p;
+
#endif
@@ -4013,11 +4013,43 @@ rs6000_output_function_prologue (FILE *file)
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 user 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 ())
@@ -14898,8 +14898,14 @@ rs6000_print_patchable_function_entry (FILE *file,
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);
}
enum rtx_code
@@ -2439,6 +2439,10 @@ typedef struct GTY(()) machine_function
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
@@ -1,6 +1,7 @@
/* { dg-do compile { target { ! { nvptx*-*-* visium-*-* } } } } */
/* { dg-options "-O2 -fpatchable-function-entry=3,1" } */
/* { dg-additional-options "-fno-pie" { target sparc*-*-* } } */
+/* { 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*-*-* } } } */
new file mode 100644
@@ -0,0 +1,45 @@
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify no errors for different NOPs after local entry. */
+
+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;
+}
new file mode 100644
@@ -0,0 +1,45 @@
+/* { dg-require-effective-target powerpc_elfv2 } */
+
+/* Verify no errors for 2, 6 and 14 NOPs before local entry. */
+
+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;
+}
new file mode 100644
@@ -0,0 +1,12 @@
+/* { dg-require-effective-target powerpc_elfv2 } */
+/* { dg-options "-fpatchable-function-entry=1" } */
+
+/* Verify no errors, using command line option instead of function
+ attribute. */
+
+extern int a;
+
+int test (int b) {
+ return a + b;
+}
+
new file mode 100644
@@ -0,0 +1,13 @@
+/* { 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 } */
new file mode 100644
@@ -0,0 +1,13 @@
+/* { 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 NOP 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 } */
new file mode 100644
@@ -0,0 +1,14 @@
+/* { 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 NOP 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 } */