diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1767,6 +1767,13 @@ let Documentation = [RISCVInterruptDocs]; } +def RISCVBuiltinAlias : InheritableAttr, TargetSpecificAttr { + let Spellings = [Clang<"__clang_riscv_builtin_alias">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Args = [IdentifierArgument<"BuiltinName">]; + let Documentation = [RISCVBuiltinAliasDocs]; +} + // This is not a TargetSpecificAttr so that is silently accepted and // ignored on other targets as encouraged by the OpenCL spec. // diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2132,6 +2132,26 @@ }]; } +def RISCVBuiltinAliasDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +This attribute is used in the implementation of the RVV intrinsics. +It allows the intrinsic functions to be declared using the names defined +in RVV, and still be recognized as clang builtins equivalent to the +underlying name. For example, ``riscv_vector_overloaded.h`` declares the function +``vget`` with +``__attribute__((__clang_riscv_builtin_alias(__builtin_rvv_vget_i8mf8x2_i8mf8)))``. +This ensures that both functions are recognized as that clang builtin, +and in the latter case, the choice of which builtin to identify the +function as can be deferred until after overload resolution. + +This attribute can only be used to set up the aliases for certain RISC-V +intrinsic functions; it is intended for use only inside ``riscv_*.h`` +and is not a general mechanism for declaring arbitrary aliases for +clang builtin functions. + }]; +} + def AVRInterruptDocs : Documentation { let Category = DocCatFunction; let Heading = "interrupt (AVR)"; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11249,4 +11249,7 @@ // RISC-V builtin required extension warning def err_riscv_builtin_requires_extension : Error< "builtin requires '%0' extension support to be enabled">; +def err_attribute_riscv_builtin_alias : Error< + "'__clang_riscv_builtin_alias' attribute can only be applied to a RISC-V " + "builtin">; } // end of sema component. diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3265,6 +3265,8 @@ if (const auto *ABAA = getAttr()) { BuiltinID = ABAA->getBuiltinName()->getBuiltinID(); + } else if (const auto *RBAA = getAttr()) { + BuiltinID = RBAA->getBuiltinName()->getBuiltinID(); } else if (const auto *A = getAttr()) { BuiltinID = A->getID(); } @@ -3275,7 +3277,7 @@ // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. if (!ConsiderWrapperFunctions && hasAttr() && - !hasAttr()) + (!hasAttr() && !hasAttr())) return 0; ASTContext &Context = getASTContext(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5120,6 +5120,7 @@ #define GET_SVE_BUILTINS #define BUILTIN(name, types, attr) case SVE::BI##name: #include "clang/Basic/arm_sve_builtins.inc" +#undef BUILTIN return true; } } @@ -5146,6 +5147,37 @@ D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident)); } +static bool RISCVVAliasValid(unsigned BuiltinID, StringRef AliasName) { + switch (BuiltinID) { + default: + return false; +#define BUILTIN(ID, TYPE, ATTRS) case RISCV::BI##ID: +#include "clang/Basic/BuiltinsRISCV.def" +#undef BUILTIN + return true; + } +} + +static void handleRISCVBuiltinAliasAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; + unsigned BuiltinID = Ident->getBuiltinID(); + StringRef AliasName = cast(D)->getIdentifier()->getName(); + + if (!RISCVVAliasValid(BuiltinID, AliasName)) { + S.Diag(AL.getLoc(), diag::err_attribute_riscv_builtin_alias); + return; + } + + D->addAttr(::new (S.Context) RISCVBuiltinAliasAttr(S.Context, AL, Ident)); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -8243,6 +8275,10 @@ case ParsedAttr::AT_EnforceTCBLeaf: handleEnforceTCBAttr(S, D, AL); break; + + case ParsedAttr::AT_RISCVBuiltinAlias: + handleRISCVBuiltinAliasAttr(S, D, AL); + break; } } diff --git a/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c @@ -0,0 +1,35 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv64 -emit-llvm -target-feature +experimental-v \ +// RUN: %s -o - \ +// RUN: | FileCheck %s + +#include + +#define __rvv_generic \ +static inline __attribute__((__always_inline__, __nodebug__, __overloadable__)) + +__rvv_generic +__attribute__((__clang_riscv_builtin_alias(__builtin_rvv_vadd_vv_i8m1))) +vint8m1_t vadd_generic (vint8m1_t op0, vint8m1_t op1, size_t op2); + +// CHECK-LABEL: @test( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[OP0_ADDR:%.*]] = alloca , align 1 +// CHECK-NEXT: [[OP1_ADDR:%.*]] = alloca , align 1 +// CHECK-NEXT: [[VL_ADDR:%.*]] = alloca i64, align 8 +// CHECK-NEXT: [[RET:%.*]] = alloca , align 1 +// CHECK-NEXT: store [[OP0:%.*]], * [[OP0_ADDR]], align 1 +// CHECK-NEXT: store [[OP1:%.*]], * [[OP1_ADDR]], align 1 +// CHECK-NEXT: store i64 [[VL:%.*]], i64* [[VL_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load , * [[OP0_ADDR]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load , * [[OP1_ADDR]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64* [[VL_ADDR]], align 8 +// CHECK-NEXT: [[TMP3:%.*]] = call @llvm.riscv.vadd.nxv8i8.nxv8i8.i64( [[TMP0]], [[TMP1]], i64 [[TMP2]]) +// CHECK-NEXT: store [[TMP3]], * [[RET]], align 1 +// CHECK-NEXT: [[TMP4:%.*]] = load , * [[RET]], align 1 +// CHECK-NEXT: ret [[TMP4]] +// +vint8m1_t test(vint8m1_t op0, vint8m1_t op1, size_t vl) { + vint8m1_t ret = vadd_generic(op0, op1, vl); + return ret; +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -142,6 +142,7 @@ // CHECK-NEXT: PassObjectSize (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: PatchableFunctionEntry (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: Pointer (SubjectMatchRule_record_not_is_union) +// CHECK-NEXT: RISCVBuiltinAlias (SubjectMatchRule_function) // CHECK-NEXT: ReleaseHandle (SubjectMatchRule_variable_is_parameter) // CHECK-NEXT: RenderScriptKernel (SubjectMatchRule_function) // CHECK-NEXT: ReqdWorkGroupSize (SubjectMatchRule_function)