Skip to content

Commit 1088643

Browse files
committed
[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
1 parent 5e537ea commit 1088643

File tree

8 files changed

+136
-1
lines changed

8 files changed

+136
-1
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,15 @@ def Alias : Attr {
642642
let Documentation = [Undocumented];
643643
}
644644

645+
def BuiltinAlias : Attr {
646+
let Spellings = [CXX11<"clang", "builtin_alias">,
647+
C2x<"clang", "builtin_alias">,
648+
GNU<"clang_builtin_alias">];
649+
let Args = [IdentifierArgument<"BuiltinName">];
650+
let Subjects = SubjectList<[Function], ErrorDiag>;
651+
let Documentation = [BuiltinAliasDocs];
652+
}
653+
645654
def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
646655
let Spellings = [Clang<"__clang_arm_builtin_alias">];
647656
let Args = [IdentifierArgument<"BuiltinName">];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4699,6 +4699,25 @@ the old mangled name and the new code will use the new mangled name with tags.
46994699
}];
47004700
}
47014701

4702+
def BuiltinAliasDocs : Documentation {
4703+
let Category = DocCatFunction;
4704+
let Content = [{
4705+
This attribute is used in the implementation of the C intrinsics.
4706+
It allows the C intrinsic functions to be declared using the names defined
4707+
in target builtins, and still be recognized as clang builtins equivalent to the
4708+
underlying name. For example, ``riscv_vector.h`` declares the function ``vadd``
4709+
with ``__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1)))``.
4710+
This ensures that both functions are recognized as that clang builtin,
4711+
and in the latter case, the choice of which builtin to identify the
4712+
function as can be deferred until after overload resolution.
4713+
4714+
This attribute can only be used to set up the aliases for certain ARM/RISC-V
4715+
C intrinsic functions; it is intended for use only inside ``arm_*.h`` and
4716+
``riscv_*.h`` and is not a general mechanism for declaring arbitrary aliases
4717+
for clang builtin functions.
4718+
}];
4719+
}
4720+
47024721
def PreferredNameDocs : Documentation {
47034722
let Category = DocCatDecl;
47044723
let Content = [{
@@ -5693,6 +5712,10 @@ This attribute can only be used to set up the aliases for certain Arm
56935712
intrinsic functions; it is intended for use only inside ``arm_*.h``
56945713
and is not a general mechanism for declaring arbitrary aliases for
56955714
clang builtin functions.
5715+
5716+
In order to avoid duplicating the attribute definitions for similar
5717+
purpose for other architecture, there is a general form for the
5718+
attribute `clang_builtin_alias`.
56965719
}];
56975720
}
56985721

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4026,6 +4026,8 @@ def note_protocol_decl_undefined : Note<
40264026
def err_attribute_preferred_name_arg_invalid : Error<
40274027
"argument %0 to 'preferred_name' attribute is not a typedef for "
40284028
"a specialization of %1">;
4029+
def err_attribute_builtin_alias : Error<
4030+
"%0 attribute can only be applied to a ARM or RISC-V builtin">;
40294031

40304032
// called-once attribute diagnostics.
40314033
def err_called_once_attribute_wrong_type : Error<

clang/lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3265,6 +3265,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
32653265

32663266
if (const auto *ABAA = getAttr<ArmBuiltinAliasAttr>()) {
32673267
BuiltinID = ABAA->getBuiltinName()->getBuiltinID();
3268+
} else if (const auto *BAA = getAttr<BuiltinAliasAttr>()) {
3269+
BuiltinID = BAA->getBuiltinName()->getBuiltinID();
32683270
} else if (const auto *A = getAttr<BuiltinAttr>()) {
32693271
BuiltinID = A->getID();
32703272
}
@@ -3275,7 +3277,7 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
32753277
// If the function is marked "overloadable", it has a different mangled name
32763278
// and is not the C library function.
32773279
if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() &&
3278-
!hasAttr<ArmBuiltinAliasAttr>())
3280+
(!hasAttr<ArmBuiltinAliasAttr>() && !hasAttr<BuiltinAliasAttr>()))
32793281
return 0;
32803282

32813283
ASTContext &Context = getASTContext();

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5120,6 +5120,7 @@ static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) {
51205120
#define GET_SVE_BUILTINS
51215121
#define BUILTIN(name, types, attr) case SVE::BI##name:
51225122
#include "clang/Basic/arm_sve_builtins.inc"
5123+
#undef BUILTIN
51235124
return true;
51245125
}
51255126
}
@@ -5146,6 +5147,44 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
51465147
D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident));
51475148
}
51485149

5150+
static bool RISCVAliasValid(unsigned BuiltinID, StringRef AliasName) {
5151+
switch (BuiltinID) {
5152+
default:
5153+
return false;
5154+
#define BUILTIN(ID, TYPE, ATTRS) case RISCV::BI##ID:
5155+
#include "clang/Basic/BuiltinsRISCV.def"
5156+
#undef BUILTIN
5157+
return true;
5158+
}
5159+
}
5160+
5161+
static void handleBuiltinAliasAttr(Sema &S, Decl *D,
5162+
const ParsedAttr &AL) {
5163+
if (!AL.isArgIdent(0)) {
5164+
S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
5165+
<< AL << 1 << AANT_ArgumentIdentifier;
5166+
return;
5167+
}
5168+
5169+
IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident;
5170+
unsigned BuiltinID = Ident->getBuiltinID();
5171+
StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName();
5172+
5173+
bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64();
5174+
bool IsARM = S.Context.getTargetInfo().getTriple().isARM();
5175+
bool IsRISCV = S.Context.getTargetInfo().getTriple().isRISCV();
5176+
if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) ||
5177+
(IsARM && !ArmMveAliasValid(BuiltinID, AliasName) &&
5178+
!ArmCdeAliasValid(BuiltinID, AliasName)) ||
5179+
(IsRISCV && !RISCVAliasValid(BuiltinID, AliasName)) ||
5180+
(!IsAArch64 && !IsARM && !IsRISCV)) {
5181+
S.Diag(AL.getLoc(), diag::err_attribute_builtin_alias) << AL;
5182+
return;
5183+
}
5184+
5185+
D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident));
5186+
}
5187+
51495188
//===----------------------------------------------------------------------===//
51505189
// Checker-specific attribute handlers.
51515190
//===----------------------------------------------------------------------===//
@@ -8243,6 +8282,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
82438282
case ParsedAttr::AT_EnforceTCBLeaf:
82448283
handleEnforceTCBAttr<EnforceTCBLeafAttr, EnforceTCBAttr>(S, D, AL);
82458284
break;
8285+
8286+
case ParsedAttr::AT_BuiltinAlias:
8287+
handleBuiltinAliasAttr(S, D, AL);
8288+
break;
82468289
}
82478290
}
82488291

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// REQUIRES: riscv-registered-target
2+
// RUN: not %clang_cc1 -triple riscv64 -fsyntax-only -verify \
3+
// RUN: -target-feature +experimental-v %s 2>&1 \
4+
// RUN: | FileCheck %s
5+
6+
#include <riscv_vector.h>
7+
8+
#define __rvv_generic \
9+
static inline __attribute__((__always_inline__, __nodebug__))
10+
11+
__rvv_generic
12+
__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1)))
13+
vint8m1_t vadd_generic (vint8m1_t op0, vint8m1_t op1, size_t op2);
14+
15+
// CHECK: passing 'vint8m2_t' (aka '__rvv_int8m2_t') to parameter of incompatible type 'vint8m1_t'
16+
vint8m2_t test(vint8m2_t op0, vint8m2_t op1, size_t vl) {
17+
vint8m2_t ret = vadd_generic(op0, op1, vl);
18+
return ret;
19+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// REQUIRES: riscv-registered-target
3+
// RUN: %clang_cc1 -triple riscv64 -emit-llvm -target-feature +experimental-v \
4+
// RUN: %s -o - \
5+
// RUN: | FileCheck %s
6+
7+
#include <riscv_vector.h>
8+
9+
#define __rvv_generic \
10+
static inline __attribute__((__always_inline__, __nodebug__))
11+
12+
__rvv_generic
13+
__attribute__((clang_builtin_alias(__builtin_rvv_vadd_vv_i8m1)))
14+
vint8m1_t vadd_generic (vint8m1_t op0, vint8m1_t op1, size_t op2);
15+
16+
// CHECK-LABEL: @test(
17+
// CHECK-NEXT: entry:
18+
// CHECK-NEXT: [[OP0_ADDR:%.*]] = alloca <vscale x 8 x i8>, align 1
19+
// CHECK-NEXT: [[OP1_ADDR:%.*]] = alloca <vscale x 8 x i8>, align 1
20+
// CHECK-NEXT: [[VL_ADDR:%.*]] = alloca i64, align 8
21+
// CHECK-NEXT: [[RET:%.*]] = alloca <vscale x 8 x i8>, align 1
22+
// CHECK-NEXT: store <vscale x 8 x i8> [[OP0:%.*]], <vscale x 8 x i8>* [[OP0_ADDR]], align 1
23+
// CHECK-NEXT: store <vscale x 8 x i8> [[OP1:%.*]], <vscale x 8 x i8>* [[OP1_ADDR]], align 1
24+
// CHECK-NEXT: store i64 [[VL:%.*]], i64* [[VL_ADDR]], align 8
25+
// CHECK-NEXT: [[TMP0:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[OP0_ADDR]], align 1
26+
// CHECK-NEXT: [[TMP1:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[OP1_ADDR]], align 1
27+
// CHECK-NEXT: [[TMP2:%.*]] = load i64, i64* [[VL_ADDR]], align 8
28+
// 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]])
29+
// CHECK-NEXT: store <vscale x 8 x i8> [[TMP3]], <vscale x 8 x i8>* [[RET]], align 1
30+
// CHECK-NEXT: [[TMP4:%.*]] = load <vscale x 8 x i8>, <vscale x 8 x i8>* [[RET]], align 1
31+
// CHECK-NEXT: ret <vscale x 8 x i8> [[TMP4]]
32+
//
33+
vint8m1_t test(vint8m1_t op0, vint8m1_t op1, size_t vl) {
34+
vint8m1_t ret = vadd_generic(op0, op1, vl);
35+
return ret;
36+
}

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method)
2323
// 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))
2424
// CHECK-NEXT: BPFPreserveAccessIndex (SubjectMatchRule_record)
25+
// CHECK-NEXT: BuiltinAlias (SubjectMatchRule_function)
2526
// CHECK-NEXT: CFAuditedTransfer (SubjectMatchRule_function)
2627
// CHECK-NEXT: CFConsumed (SubjectMatchRule_variable_is_parameter)
2728
// CHECK-NEXT: CFICanonicalJumpTable (SubjectMatchRule_function)

0 commit comments

Comments
 (0)