diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index b6c0d0a8eb6..68f0b542202 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -427,6 +427,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, diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c index 83453d03095..189d958d817 100644 --- a/gcc/config/aarch64/aarch64.c +++ b/gcc/config/aarch64/aarch64.c @@ -15276,6 +15276,22 @@ 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 (TREE_CODE (decl) == FUNCTION_DECL + && TREE_PUBLIC (decl) + && lookup_attribute ("aarch64_vector_pcs", + TYPE_ATTRIBUTES (TREE_TYPE (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; @@ -15325,11 +15341,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 symbols references. */ + +void +aarch64_asm_output_external (FILE *stream, const tree decl, const char* name) +{ + aarch64_asm_output_variant_pcs (stream, decl, name); +} + /* Implements TARGET_ASM_FILE_START. Output the assembly header. */ static void diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index be6981889ab..f0f50e081ac 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -512,6 +512,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) + /* For EH returns X4 contains the stack adjustment. */ #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, R4_REGNUM) #define EH_RETURN_HANDLER_RTX aarch64_eh_return_handler_rtx () 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 index 00000000000..c808bd45d0f --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pcs_attribute-2.c @@ -0,0 +1,101 @@ +/* { 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) +{ +} + +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, + bar_undef_vpcs, + bar_def_vpcs, + f_ifunc_vpcs, + f_hidden_ifunc_vpcs, + f_local_ifunc_vpcs, +}; + +/* Note: hidden and local symbols don't need .variant_pcs, + here we accept it on hidden symbols, but not on local ones. */ + +/* { dg-final { scan-assembler-not {\.variant_pcs\tf_undef_basepcs} } } */ +/* { dg-final { scan-assembler-not {\.variant_pcs\tf_def_basepcs} } } */ +/* { dg-final { scan-assembler-not {\.variant_pcs\tf_local_vpcs} } } */ +/* { dg-final { scan-assembler-not {\.variant_pcs\tf_local_ifunc_vpcs} } } */ +/* { 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_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 } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/pcs_attribute.c b/gcc/testsuite/gcc.target/aarch64/pcs_attribute.c index 9a99b91a6ed..8fe390f15ac 100644 --- a/gcc/testsuite/gcc.target/aarch64/pcs_attribute.c +++ b/gcc/testsuite/gcc.target/aarch64/pcs_attribute.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ /* Test that the assignment of f (with the attribute) to function pointer g (with no attribute) results in an error. */ diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-1.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-1.c index 249554e7b11..adc6134ece8 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-1.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-1.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ void __attribute__ ((aarch64_vector_pcs)) f (void) diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-3.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-3.c index 7d4f54fed97..437a2c2c0c4 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-3.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-3.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ extern void g (void); diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-4.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-4.c index e399690f364..80ebd955e10 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-4.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-4.c @@ -1,4 +1,5 @@ /* dg-do run */ +/* { dg-require-effective-target aarch64_variant_pcs } */ /* { dg-additional-options "-std=c99" } */ diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-5.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-5.c index 7d639a5e1cb..46848ce9caa 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-5.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-5.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ void __attribute__ ((aarch64_vector_pcs)) f (void) diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-6.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-6.c index dc13e1634d6..706521ce5b6 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-6.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-6.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ void __attribute__ ((aarch64_vector_pcs)) f (void) diff --git a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-7.c b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-7.c index aafd973335c..f16e041f658 100644 --- a/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-7.c +++ b/gcc/testsuite/gcc.target/aarch64/torture/simd-abi-7.c @@ -1,4 +1,5 @@ /* { dg-do compile } */ +/* { dg-require-effective-target aarch64_variant_pcs } */ void __attribute__ ((aarch64_vector_pcs)) f (void) diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index 3bd6e815715..50c05ffd1eb 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -8591,6 +8591,15 @@ proc check_effective_target_aarch64_large { } { } } +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.