[clang] 1088643 - [Clang] Add clang attribute `clang_builtin_alias`.

Hsiangkai Wang via cfe-commits cfe-commits at lists.llvm.org
Sat Apr 24 17:49:28 PDT 2021


Author: Hsiangkai Wang
Date: 2021-04-25T08:49:19+08:00
New Revision: 108864397d26ffff39267f417cabc7f248431437

URL: https://github.com/llvm/llvm-project/commit/108864397d26ffff39267f417cabc7f248431437
DIFF: https://github.com/llvm/llvm-project/commit/108864397d26ffff39267f417cabc7f248431437.diff

LOG: [Clang] Add clang attribute `clang_builtin_alias`.

In some cases, we want to provide the alias name for the clang builtins.
For example, the arguments must be constant integers for some RISC-V builtins.
If we use wrapper functions, we could not constrain the arguments be constant
integer. This attribute is used to achieve the purpose.

Besides this, use `clang_builtin_alias` is more efficient than using
wrapper functions. We use this attribute to deal with test time issue
reported in https://bugs.llvm.org/show_bug.cgi?id=49962.

In our downstream testing, it could decrease the testing time from 6.3
seconds to 3.7 seconds for vloxei.c test.

Differential Revision: https://reviews.llvm.org/D100611

Added: 
    clang/test/CodeGen/RISCV/riscv-attr-builtin-alias-err.c
    clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/AST/Decl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Misc/pragma-attribute-supported-attributes-list.test

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 08534ec61620..19ae88757033 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -642,6 +642,15 @@ def Alias : Attr {
   let Documentation = [Undocumented];
 }
 
+def BuiltinAlias : Attr {
+  let Spellings = [CXX11<"clang", "builtin_alias">,
+                   C2x<"clang", "builtin_alias">,
+                   GNU<"clang_builtin_alias">];
+  let Args = [IdentifierArgument<"BuiltinName">];
+  let Subjects = SubjectList<[Function], ErrorDiag>;
+  let Documentation = [BuiltinAliasDocs];
+}
+
 def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
   let Spellings = [Clang<"__clang_arm_builtin_alias">];
   let Args = [IdentifierArgument<"BuiltinName">];

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 1960596f1bfb..9cc4c837cc49 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -4699,6 +4699,25 @@ the old mangled name and the new code will use the new mangled name with tags.
   }];
 }
 
+def BuiltinAliasDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+This attribute is used in the implementation of the C intrinsics.
+It allows the C intrinsic functions to be declared using the names defined
+in target builtins, and still be recognized as clang builtins equivalent to the
+underlying name. For example, ``riscv_vector.h`` declares the function ``vadd``
+with ``__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1)))``.
+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 ARM/RISC-V
+C intrinsic functions; it is intended for use only inside ``arm_*.h`` and
+``riscv_*.h`` and is not a general mechanism for declaring arbitrary aliases
+for clang builtin functions.
+  }];
+}
+
 def PreferredNameDocs : Documentation {
   let Category = DocCatDecl;
   let Content = [{
@@ -5693,6 +5712,10 @@ This attribute can only be used to set up the aliases for certain Arm
 intrinsic functions; it is intended for use only inside ``arm_*.h``
 and is not a general mechanism for declaring arbitrary aliases for
 clang builtin functions.
+
+In order to avoid duplicating the attribute definitions for similar
+purpose for other architecture, there is a general form for the
+attribute `clang_builtin_alias`.
   }];
 }
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 3a58d3dc5c4a..639565feb576 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4026,6 +4026,8 @@ def note_protocol_decl_undefined : Note<
 def err_attribute_preferred_name_arg_invalid : Error<
   "argument %0 to 'preferred_name' attribute is not a typedef for "
   "a specialization of %1">;
+def err_attribute_builtin_alias : Error<
+  "%0 attribute can only be applied to a ARM or RISC-V builtin">;
 
 // called-once attribute diagnostics.
 def err_called_once_attribute_wrong_type : Error<

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index fcda07dab604..f77acefb1781 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3265,6 +3265,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
 
   if (const auto *ABAA = getAttr<ArmBuiltinAliasAttr>()) {
     BuiltinID = ABAA->getBuiltinName()->getBuiltinID();
+  } else if (const auto *BAA = getAttr<BuiltinAliasAttr>()) {
+    BuiltinID = BAA->getBuiltinName()->getBuiltinID();
   } else if (const auto *A = getAttr<BuiltinAttr>()) {
     BuiltinID = A->getID();
   }
@@ -3275,7 +3277,7 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
   // If the function is marked "overloadable", it has a 
diff erent mangled name
   // and is not the C library function.
   if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
-      !hasAttr<ArmBuiltinAliasAttr>())
+      (!hasAttr<ArmBuiltinAliasAttr>() && !hasAttr<BuiltinAliasAttr>()))
     return 0;
 
   ASTContext &Context = getASTContext();

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 43ca644ed21e..b31f9ecb2ace 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5120,6 +5120,7 @@ static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) {
 #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,44 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident));
 }
 
+static bool RISCVAliasValid(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 handleBuiltinAliasAttr(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<FunctionDecl>(D)->getIdentifier()->getName();
+
+  bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
+  bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
+  bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
+  if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) ||
+      (IsARM && !ArmMveAliasValid(BuiltinID, AliasName) &&
+       !ArmCdeAliasValid(BuiltinID, AliasName)) ||
+      (IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) ||
+      (!IsAArch64 && !IsARM && !IsRISCV)) {
+    S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
+    return;
+  }
+
+  D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
+}
+
 //===----------------------------------------------------------------------===//
 // Checker-specific attribute handlers.
 //===----------------------------------------------------------------------===//
@@ -8243,6 +8282,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_EnforceTCBLeaf:
     handleEnforceTCBAttr<EnforceTCBLeafAttr, EnforceTCBAttr>(S, D, AL);
     break;
+
+  case ParsedAttr::AT_BuiltinAlias:
+    handleBuiltinAliasAttr(S, D, AL);
+    break;
   }
 }
 

diff  --git a/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias-err.c b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias-err.c
new file mode 100644
index 000000000000..9ee8ce68ebc5
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias-err.c
@@ -0,0 +1,19 @@
+// REQUIRES: riscv-registered-target
+// RUN: not %clang_cc1 -triple riscv64 -fsyntax-only -verify \
+// RUN:   -target-feature +experimental-v %s 2>&1 \
+// RUN: | FileCheck %s
+
+#include <riscv_vector.h>
+
+#define __rvv_generic \
+static inline __attribute__((__always_inline__, __nodebug__))
+
+__rvv_generic
+__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1)))
+vint8m1_t vadd_generic (vint8m1_t op0, vint8m1_t op1, size_t op2);
+
+// CHECK: passing 'vint8m2_t' (aka '__rvv_int8m2_t') to parameter of incompatible type 'vint8m1_t'
+vint8m2_t test(vint8m2_t op0, vint8m2_t op1, size_t vl) {
+  vint8m2_t ret = vadd_generic(op0, op1, vl);
+  return ret;
+}

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
index 000000000000..e3ff4e4d7dd5
--- /dev/null
+++ b/clang/test/CodeGen/RISCV/riscv-attr-builtin-alias.c
@@ -0,0 +1,36 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
+// REQUIRES: riscv-registered-target
+// RUN: %clang_cc1 -triple riscv64 -emit-llvm -target-feature +experimental-v \
+// RUN:   %s -o - \
+// RUN:   | FileCheck %s
+
+#include <riscv_vector.h>
+
+#define __rvv_generic \
+static inline __attribute__((__always_inline__, __nodebug__))
+
+__rvv_generic
+__attribute__((clang_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 <vscale x 8 x i8>, align 1
+// CHECK-NEXT:    [[OP1_ADDR:%.*]] = alloca <vscale x 8 x i8>, align 1
+// CHECK-NEXT:    [[VL_ADDR:%.*]] = alloca i64, align 8
+// CHECK-NEXT:    [[RET:%.*]] = alloca <vscale x 8 x i8>, align 1
+// CHECK-NEXT:    store <vscale x 8 x i8> [[OP0:%.*]], <vscale x 8 x i8>* [[OP0_ADDR]], align 1
+// CHECK-NEXT:    store <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8>* [[OP1_ADDR]], align 1
+// CHECK-NEXT:    store i64 [[VL:%.*]], i64* [[VL_ADDR]], align 8
+// CHECK-NEXT:    [[TMP0:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[OP0_ADDR]], align 1
+// CHECK-NEXT:    [[TMP1:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[OP1_ADDR]], align 1
+// CHECK-NEXT:    [[TMP2:%.*]] = load i64, i64* [[VL_ADDR]], align 8
+// CHECK-NEXT:    [[TMP3:%.*]] = call <vscale x 8 x i8> @llvm.riscv.vadd.nxv8i8.nxv8i8.i64(<vscale x 8 x i8> [[TMP0]], <vscale x 8 x i8> [[TMP1]], i64 [[TMP2]])
+// CHECK-NEXT:    store <vscale x 8 x i8> [[TMP3]], <vscale x 8 x i8>* [[RET]], align 1
+// CHECK-NEXT:    [[TMP4:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[RET]], align 1
+// CHECK-NEXT:    ret <vscale x 8 x i8> [[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
index ddc4f73f1fd7..473ac1e530fd 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -22,6 +22,7 @@
 // CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable))
 // CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
+// CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function)
 // CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function)
 // CHECK-NEXT: CFConsumed (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: CFICanonicalJumpTable (SubjectMatchRule_function)


        


More information about the cfe-commits mailing list