aarch64: emit .variant_pcs for aarch64_vector_pcs symbol references
authorSzabolcs Nagy <szabolcs.nagy@arm.com>
Mon, 3 Jun 2019 13:50:53 +0000 (13:50 +0000)
committerSzabolcs Nagy <nsz@gcc.gnu.org>
Mon, 3 Jun 2019 13:50:53 +0000 (13:50 +0000)
A dynamic linker with lazy binding support may need to handle vector PCS
function symbols specially, so an ELF symbol table marking was
introduced for such symbols.

Function symbol references and definitions that follow the vector PCS
are marked in the generated assembly with .variant_pcs and then the
STO_AARCH64_VARIANT_PCS st_other flag is set on the symbol in the object
file.  The marking is propagated to the dynamic symbol table by the
static linker so a dynamic linker can handle such symbols specially.

For this to work, the assembler, the static linker and the dynamic
linker has to be updated on a system.  Old assembler does not support
the new .variant_pcs directive, so a toolchain with old binutils won't
be able to compile code that references vector PCS symbols.

gcc/ChangeLog:

* config/aarch64/aarch64-protos.h (aarch64_asm_output_alias): Declare.
(aarch64_asm_output_external): Declare.
* config/aarch64/aarch64.c (aarch64_asm_output_variant_pcs): New.
(aarch64_declare_function_name): Call aarch64_asm_output_variant_pcs.
(aarch64_asm_output_alias): New.
(aarch64_asm_output_external): New.
* config/aarch64/aarch64.h (ASM_OUTPUT_DEF_FROM_DECLS): Define.
(ASM_OUTPUT_EXTERNAL): Define.

gcc/testsuite/ChangeLog:

* gcc.target/aarch64/pcs_attribute-2.c: New test.
* gcc.target/aarch64/torture/simd-abi-4.c: Check .variant_pcs support.
* lib/target-supports.exp (check_effective_target_aarch64_variant_pcs):
New.

From-SVN: r271869

gcc/ChangeLog
gcc/config/aarch64/aarch64-protos.h
gcc/config/aarch64/aarch64.c
gcc/config/aarch64/aarch64.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/aarch64/pcs_attribute-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/torture/simd-abi-4.c
gcc/testsuite/lib/target-supports.exp

index b4c38d6ea9546a0da1ec0048c146e424c2c4cc1b..5833d7fc8ff1151dac85c0551666f62eae024dfa 100644 (file)
@@ -1,3 +1,14 @@
+2019-06-03  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+       * config/aarch64/aarch64-protos.h (aarch64_asm_output_alias): Declare.
+       (aarch64_asm_output_external): Declare.
+       * config/aarch64/aarch64.c (aarch64_asm_output_variant_pcs): New.
+       (aarch64_declare_function_name): Call aarch64_asm_output_variant_pcs.
+       (aarch64_asm_output_alias): New.
+       (aarch64_asm_output_external): New.
+       * config/aarch64/aarch64.h (ASM_OUTPUT_DEF_FROM_DECLS): Define.
+       (ASM_OUTPUT_EXTERNAL): Define.
+
 2019-06-03  Aldy Hernandez  <aldyh@redhat.com>
        * tree-vrp.h (value_range_base::nonzero_p): New.
        (value_range_base::set_nonnull): Rename to...
index a42d352ac11d811a37c1a1f4c0d30925925bcaf7..6dccabc8cf79dfa000c062a5c6a2ad141615efa9 100644 (file)
@@ -436,6 +436,8 @@ bool aarch64_is_long_call_p (rtx);
 bool aarch64_is_noplt_call_p (rtx);
 bool aarch64_label_mentioned_p (rtx);
 void aarch64_declare_function_name (FILE *, const char*, tree);
+void aarch64_asm_output_alias (FILE *, const tree, const tree);
+void aarch64_asm_output_external (FILE *, const tree, const char*);
 bool aarch64_legitimate_pic_operand_p (rtx);
 bool aarch64_mask_and_shift_for_ubfiz_p (scalar_int_mode, rtx, rtx);
 bool aarch64_masks_and_shift_for_bfi_p (scalar_int_mode, unsigned HOST_WIDE_INT,
index db0249b4607bef789ceab8ec844d37dfc2899de9..263ed21442c4e028f2b6c77950dbc726cb380cd4 100644 (file)
@@ -15566,6 +15566,19 @@ aarch64_asm_preferred_eh_data_format (int code ATTRIBUTE_UNUSED, int global)
    return (global ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | type;
 }
 
+/* Output .variant_pcs for aarch64_vector_pcs function symbols.  */
+
+static void
+aarch64_asm_output_variant_pcs (FILE *stream, const tree decl, const char* name)
+{
+  if (aarch64_simd_decl_p (decl))
+    {
+      fprintf (stream, "\t.variant_pcs\t");
+      assemble_name (stream, name);
+      fprintf (stream, "\n");
+    }
+}
+
 /* The last .arch and .tune assembly strings that we printed.  */
 static std::string aarch64_last_printed_arch_string;
 static std::string aarch64_last_printed_tune_string;
@@ -15615,11 +15628,33 @@ aarch64_declare_function_name (FILE *stream, const char* name,
       aarch64_last_printed_tune_string = this_tune->name;
     }
 
+  aarch64_asm_output_variant_pcs (stream, fndecl, name);
+
   /* Don't forget the type directive for ELF.  */
   ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function");
   ASM_OUTPUT_LABEL (stream, name);
 }
 
+/* Implement ASM_OUTPUT_DEF_FROM_DECLS.  Output .variant_pcs for aliases.  */
+
+void
+aarch64_asm_output_alias (FILE *stream, const tree decl, const tree target)
+{
+  const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+  const char *value = IDENTIFIER_POINTER (target);
+  aarch64_asm_output_variant_pcs (stream, decl, name);
+  ASM_OUTPUT_DEF (stream, name, value);
+}
+
+/* Implement ASM_OUTPUT_EXTERNAL.  Output .variant_pcs for undefined
+   function symbol references.  */
+
+void
+aarch64_asm_output_external (FILE *stream, const tree decl, const char* name)
+{
+  aarch64_asm_output_variant_pcs (stream, decl, name);
+}
+
 /* Triggered after a .cfi_startproc directive is emitted into the assembly file.
    Used to output the .cfi_b_key_frame directive when signing the current
    function with the B key.  */
index 516f63689c4fe17ffcdde57f19dd101b8e34fb71..bf06caa06ee65c5216493deb030784630b7ed2db 100644 (file)
@@ -516,6 +516,15 @@ extern unsigned aarch64_architecture_version;
 #define ASM_DECLARE_FUNCTION_NAME(STR, NAME, DECL)     \
   aarch64_declare_function_name (STR, NAME, DECL)
 
+/* Output assembly strings for alias definition.  */
+#define ASM_OUTPUT_DEF_FROM_DECLS(STR, DECL, TARGET) \
+  aarch64_asm_output_alias (STR, DECL, TARGET)
+
+/* Output assembly strings for undefined extern symbols.  */
+#undef ASM_OUTPUT_EXTERNAL
+#define ASM_OUTPUT_EXTERNAL(STR, DECL, NAME) \
+  aarch64_asm_output_external (STR, DECL, NAME)
+
 /* Output assembly strings after .cfi_startproc is emitted.  */
 #define ASM_POST_CFI_STARTPROC  aarch64_post_cfi_startproc
 
index 112cf11f58ed48737696ec09836181462af4d848..6ed70b44cd501190def399af8934e4413e2d696f 100644 (file)
@@ -1,3 +1,10 @@
+2019-06-03  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+       * gcc.target/aarch64/pcs_attribute-2.c: New test.
+       * gcc.target/aarch64/torture/simd-abi-4.c: Check .variant_pcs support.
+       * lib/target-supports.exp (check_effective_target_aarch64_variant_pcs):
+       New.
+
 2019-06-03  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
 
        * gcc.target/aarch64/ssadv16qi.c: Add +nodotprod to pragma.
diff --git a/gcc/testsuite/gcc.target/aarch64/pcs_attribute-2.c b/gcc/testsuite/gcc.target/aarch64/pcs_attribute-2.c
new file mode 100644 (file)
index 0000000..d997f52
--- /dev/null
@@ -0,0 +1,114 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target aarch64_variant_pcs } */
+
+/* Test that .variant_pcs is emitted for vector PCS symbol references.  */
+
+#define ATTR __attribute__ ((aarch64_vector_pcs))
+
+void f_undef_basepcs (void);
+
+void f_def_basepcs (void)
+{
+}
+
+ATTR void f_undef_vpcs (void);
+
+ATTR void f_def_vpcs (void)
+{
+}
+
+__attribute__ ((alias ("f_def_vpcs")))
+ATTR void f_alias_vpcs (void);
+
+__attribute__ ((weak, alias ("f_def_vpcs")))
+ATTR void f_weak_alias_vpcs (void);
+
+__attribute__ ((weak))
+ATTR void f_weak_undef_vpcs (void);
+
+__attribute__ ((visibility ("protected")))
+ATTR void f_protected_vpcs (void)
+{
+}
+
+__attribute__ ((visibility ("hidden")))
+ATTR void f_hidden_vpcs (void)
+{
+}
+
+ATTR static void f_local_vpcs (void)
+{
+}
+
+__attribute__((weakref ("f_undef_vpcs")))
+ATTR static void f_local_weakref_undef_vpcs (void);
+
+__attribute__((weakref ("f_hidden_vpcs")))
+ATTR static void f_local_weakref_def_vpcs (void);
+
+ATTR void bar_undef_vpcs (void) __asm__ ("f_undef_renamed_vpcs");
+
+ATTR void bar_def_vpcs (void) __asm__ ("f_def_renamed_vpcs");
+ATTR void bar_def_vpcs (void)
+{
+}
+
+static void (*f_ifunc_resolver ()) (void)
+{
+  return (void (*)(void))f_local_vpcs;
+}
+
+__attribute__ ((ifunc ("f_ifunc_resolver")))
+ATTR void f_ifunc_vpcs (void);
+
+__attribute__ ((visibility ("hidden")))
+__attribute__ ((ifunc ("f_ifunc_resolver")))
+ATTR void f_hidden_ifunc_vpcs (void);
+
+__attribute__ ((ifunc ("f_ifunc_resolver")))
+ATTR static void f_local_ifunc_vpcs (void);
+
+void (*refs_basepcs[]) (void) = {
+       f_undef_basepcs,
+       f_def_basepcs,
+};
+
+void (*ATTR refs_vpcs[]) (void) = {
+       f_undef_vpcs,
+       f_def_vpcs,
+       f_alias_vpcs,
+       f_weak_alias_vpcs,
+       f_weak_undef_vpcs,
+       f_protected_vpcs,
+       f_hidden_vpcs,
+       f_local_vpcs,
+       f_local_weakref_undef_vpcs,
+       f_local_weakref_def_vpcs,
+       bar_undef_vpcs,
+       bar_def_vpcs,
+       f_ifunc_vpcs,
+       f_hidden_ifunc_vpcs,
+       f_local_ifunc_vpcs,
+};
+
+/* Note: local symbols don't need .variant_pcs, but gcc generates it, so
+   we check them here.  An undefined weakref does not show up in the
+   symbol table, only the target symbol, so it does not need .variant_pcs.  */
+
+/* { dg-final { scan-assembler-not {\.variant_pcs\tf_undef_basepcs} } } */
+/* { dg-final { scan-assembler-not {\.variant_pcs\tf_def_basepcs} } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_undef_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_def_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_alias_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_weak_alias_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_weak_undef_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_protected_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_hidden_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_local_vpcs} 1 } } */
+/* { dg-final { scan-assembler-not {\.variant_pcs\tf_local_weakref_undef_vpcs} } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_local_weakref_def_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_undef_renamed_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_def_renamed_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_ifunc_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_hidden_ifunc_vpcs} 1 } } */
+/* { dg-final { scan-assembler-times {\.variant_pcs\tf_local_ifunc_vpcs} 1 } } */
index e399690f364987bbe028cd97dfb28edbcc9db0d1..b8d7ce09b74f08940ae0cdb687313c7921536542 100644 (file)
@@ -1,4 +1,5 @@
-/* dg-do run */
+/* { dg-do run } */
+/* { dg-require-effective-target aarch64_variant_pcs } */
 /* { dg-additional-options "-std=c99" }  */
 
 
index 0d3d9f452957adc249f0c0063319a466cc2a8fd8..916be2b607a328d60518df575d297df869082a10 100644 (file)
@@ -8669,6 +8669,17 @@ proc check_effective_target_aarch64_large { } {
     }
 }
 
+# Return 1 if the assembler accepts the aarch64 .variant_pcs directive.
+
+proc check_effective_target_aarch64_variant_pcs { } {
+    if { [istarget aarch64*-*-*] } {
+       return [check_no_compiler_messages aarch64_variant_pcs object {
+           __asm__ (".variant_pcs foo");
+       }]
+    } else {
+       return 0
+    }
+}
 
 # Return 1 if this is a reduced AVR Tiny core.  Such cores have different
 # register set, instruction set, addressing capabilities and ABI.