Skip to content

Commit 6586c67

Browse files
authored
[FMV][AArch64] Emit mangled default version if explicitly specified. (#120022)
Currently we need at least one more version other than the default to trigger FMV. However we would like a header file declaration __attribute__((target_version("default"))) void f(void); to guarantee that there will be f.default
1 parent eace826 commit 6586c67

File tree

7 files changed

+305
-46
lines changed

7 files changed

+305
-46
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4283,7 +4283,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
42834283
getContext().forEachMultiversionedFunctionVersion(
42844284
FD, [&](const FunctionDecl *CurFD) {
42854285
llvm::SmallVector<StringRef, 8> Feats;
4286-
bool IsDefined = CurFD->doesThisDeclarationHaveABody();
4286+
bool IsDefined = CurFD->getDefinition() != nullptr;
42874287

42884288
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
42894289
assert(getTarget().getTriple().isX86() && "Unsupported target");

clang/lib/Sema/SemaDecl.cpp

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11073,9 +11073,9 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) {
1107311073
static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
1107411074
const auto *TA = FD->getAttr<TargetAttr>();
1107511075
const auto *TVA = FD->getAttr<TargetVersionAttr>();
11076-
assert(
11077-
(TA || TVA) &&
11078-
"MultiVersion candidate requires a target or target_version attribute");
11076+
11077+
assert((TA || TVA) && "Expecting target or target_version attribute");
11078+
1107911079
const TargetInfo &TargetInfo = S.Context.getTargetInfo();
1108011080
enum ErrType { Feature = 0, Architecture = 1 };
1108111081

@@ -11372,10 +11372,6 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
1137211372
// otherwise it is treated as a normal function.
1137311373
if (TA && !TA->isDefaultVersion())
1137411374
return false;
11375-
// The target_version attribute only causes Multiversioning if this
11376-
// declaration is NOT the default version.
11377-
if (TVA && TVA->isDefaultVersion())
11378-
return false;
1137911375

1138011376
if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {
1138111377
FD->setInvalidDecl();
@@ -11422,26 +11418,24 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
1142211418
LookupResult &Previous) {
1142311419
assert(!OldFD->isMultiVersion() && "Unexpected MultiVersion");
1142411420

11421+
const auto *NewTA = NewFD->getAttr<TargetAttr>();
11422+
const auto *OldTA = OldFD->getAttr<TargetAttr>();
11423+
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
11424+
const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>();
11425+
11426+
assert((NewTA || NewTVA) && "Excpecting target or target_version attribute");
11427+
1142511428
// The definitions should be allowed in any order. If we have discovered
1142611429
// a new target version and the preceeding was the default, then add the
1142711430
// corresponding attribute to it.
1142811431
patchDefaultTargetVersion(NewFD, OldFD);
1142911432

11430-
const auto *NewTA = NewFD->getAttr<TargetAttr>();
11431-
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
11432-
const auto *OldTA = OldFD->getAttr<TargetAttr>();
11433-
1143411433
// If the old decl is NOT MultiVersioned yet, and we don't cause that
1143511434
// to change, this is a simple redeclaration.
1143611435
if (NewTA && !NewTA->isDefaultVersion() &&
1143711436
(!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()))
1143811437
return false;
1143911438

11440-
// The target_version attribute only causes Multiversioning if this
11441-
// declaration is NOT the default version.
11442-
if (NewTVA && NewTVA->isDefaultVersion())
11443-
return false;
11444-
1144511439
// Otherwise, this decl causes MultiVersioning.
1144611440
if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true,
1144711441
NewTVA ? MultiVersionKind::TargetVersion
@@ -11456,15 +11450,16 @@ static bool CheckDeclarationCausesMultiVersioning(Sema &S, FunctionDecl *OldFD,
1145611450
}
1145711451

1145811452
// If this is 'default', permit the forward declaration.
11459-
if (NewTA && NewTA->isDefaultVersion() && !OldTA) {
11453+
if ((NewTA && NewTA->isDefaultVersion() && !OldTA) ||
11454+
(NewTVA && NewTVA->isDefaultVersion() && !OldTVA)) {
1146011455
Redeclaration = true;
1146111456
OldDecl = OldFD;
1146211457
OldFD->setIsMultiVersion();
1146311458
NewFD->setIsMultiVersion();
1146411459
return false;
1146511460
}
1146611461

11467-
if (CheckMultiVersionValue(S, OldFD)) {
11462+
if ((OldTA || OldTVA) && CheckMultiVersionValue(S, OldFD)) {
1146811463
S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here);
1146911464
NewFD->setInvalidDecl();
1147011465
return true;
@@ -11761,9 +11756,7 @@ static bool CheckMultiVersionAdditionalDecl(
1176111756
// Else, this is simply a non-redecl case. Checking the 'value' is only
1176211757
// necessary in the Target case, since The CPUSpecific/Dispatch cases are
1176311758
// handled in the attribute adding step.
11764-
if ((NewMVKind == MultiVersionKind::TargetVersion ||
11765-
NewMVKind == MultiVersionKind::Target) &&
11766-
CheckMultiVersionValue(S, NewFD)) {
11759+
if ((NewTA || NewTVA) && CheckMultiVersionValue(S, NewFD)) {
1176711760
NewFD->setInvalidDecl();
1176811761
return true;
1176911762
}
@@ -11799,6 +11792,12 @@ static bool CheckMultiVersionAdditionalDecl(
1179911792
static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
1180011793
bool &Redeclaration, NamedDecl *&OldDecl,
1180111794
LookupResult &Previous) {
11795+
const TargetInfo &TI = S.getASTContext().getTargetInfo();
11796+
11797+
// Check if FMV is disabled.
11798+
if (TI.getTriple().isAArch64() && !TI.hasFeature("fmv"))
11799+
return false;
11800+
1180211801
const auto *NewTA = NewFD->getAttr<TargetAttr>();
1180311802
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
1180411803
const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
@@ -11821,14 +11820,12 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
1182111820
return false;
1182211821
}
1182311822

11824-
const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple();
11825-
1182611823
// Target attribute on AArch64 is not used for multiversioning
11827-
if (NewTA && T.isAArch64())
11824+
if (NewTA && TI.getTriple().isAArch64())
1182811825
return false;
1182911826

1183011827
// Target attribute on RISCV is not used for multiversioning
11831-
if (NewTA && T.isRISCV())
11828+
if (NewTA && TI.getTriple().isRISCV())
1183211829
return false;
1183311830

1183411831
if (!OldDecl || !OldDecl->getAsFunction() ||
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fmv -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV
3+
4+
int implicit_default_decl_first(void);
5+
__attribute__((target_version("default"))) int implicit_default_decl_first(void) { return 1; }
6+
int caller1(void) { return implicit_default_decl_first(); }
7+
8+
__attribute__((target_version("default"))) int explicit_default_def_first(void) { return 2; }
9+
int explicit_default_def_first(void);
10+
int caller2(void) { return explicit_default_def_first(); }
11+
12+
int implicit_default_def_first(void) { return 3; }
13+
__attribute__((target_version("default"))) int implicit_default_def_first(void);
14+
int caller3(void) { return implicit_default_def_first(); }
15+
16+
__attribute__((target_version("default"))) int explicit_default_decl_first(void);
17+
int explicit_default_decl_first(void) { return 4; }
18+
int caller4(void) { return explicit_default_decl_first(); }
19+
20+
int no_def_implicit_default_first(void);
21+
__attribute__((target_version("default"))) int no_def_implicit_default_first(void);
22+
int caller5(void) { return no_def_implicit_default_first(); }
23+
24+
__attribute__((target_version("default"))) int no_def_explicit_default_first(void);
25+
int no_def_explicit_default_first(void);
26+
int caller6(void) { return no_def_explicit_default_first(); }
27+
//.
28+
// CHECK: @implicit_default_decl_first = weak_odr ifunc i32 (), ptr @implicit_default_decl_first.resolver
29+
// CHECK: @explicit_default_def_first = weak_odr ifunc i32 (), ptr @explicit_default_def_first.resolver
30+
// CHECK: @implicit_default_def_first = weak_odr ifunc i32 (), ptr @implicit_default_def_first.resolver
31+
// CHECK: @explicit_default_decl_first = weak_odr ifunc i32 (), ptr @explicit_default_decl_first.resolver
32+
//.
33+
// CHECK: Function Attrs: noinline nounwind optnone
34+
// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.default
35+
// CHECK-SAME: () #[[ATTR0:[0-9]+]] {
36+
// CHECK-NEXT: entry:
37+
// CHECK-NEXT: ret i32 1
38+
//
39+
//
40+
// CHECK: Function Attrs: noinline nounwind optnone
41+
// CHECK-LABEL: define {{[^@]+}}@caller1
42+
// CHECK-SAME: () #[[ATTR1:[0-9]+]] {
43+
// CHECK-NEXT: entry:
44+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first()
45+
// CHECK-NEXT: ret i32 [[CALL]]
46+
//
47+
//
48+
// CHECK: Function Attrs: noinline nounwind optnone
49+
// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.default
50+
// CHECK-SAME: () #[[ATTR0]] {
51+
// CHECK-NEXT: entry:
52+
// CHECK-NEXT: ret i32 2
53+
//
54+
//
55+
// CHECK: Function Attrs: noinline nounwind optnone
56+
// CHECK-LABEL: define {{[^@]+}}@caller2
57+
// CHECK-SAME: () #[[ATTR1]] {
58+
// CHECK-NEXT: entry:
59+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first()
60+
// CHECK-NEXT: ret i32 [[CALL]]
61+
//
62+
//
63+
// CHECK: Function Attrs: noinline nounwind optnone
64+
// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.default
65+
// CHECK-SAME: () #[[ATTR1]] {
66+
// CHECK-NEXT: entry:
67+
// CHECK-NEXT: ret i32 3
68+
//
69+
//
70+
// CHECK: Function Attrs: noinline nounwind optnone
71+
// CHECK-LABEL: define {{[^@]+}}@caller3
72+
// CHECK-SAME: () #[[ATTR1]] {
73+
// CHECK-NEXT: entry:
74+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first()
75+
// CHECK-NEXT: ret i32 [[CALL]]
76+
//
77+
//
78+
// CHECK: Function Attrs: noinline nounwind optnone
79+
// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.default
80+
// CHECK-SAME: () #[[ATTR0]] {
81+
// CHECK-NEXT: entry:
82+
// CHECK-NEXT: ret i32 4
83+
//
84+
//
85+
// CHECK: Function Attrs: noinline nounwind optnone
86+
// CHECK-LABEL: define {{[^@]+}}@caller4
87+
// CHECK-SAME: () #[[ATTR1]] {
88+
// CHECK-NEXT: entry:
89+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first()
90+
// CHECK-NEXT: ret i32 [[CALL]]
91+
//
92+
//
93+
// CHECK: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]]
94+
//
95+
//
96+
// CHECK: Function Attrs: noinline nounwind optnone
97+
// CHECK-LABEL: define {{[^@]+}}@caller5
98+
// CHECK-SAME: () #[[ATTR1]] {
99+
// CHECK-NEXT: entry:
100+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first()
101+
// CHECK-NEXT: ret i32 [[CALL]]
102+
//
103+
//
104+
// CHECK: declare i32 @no_def_explicit_default_first() #[[ATTR2]]
105+
//
106+
//
107+
// CHECK: Function Attrs: noinline nounwind optnone
108+
// CHECK-LABEL: define {{[^@]+}}@caller6
109+
// CHECK-SAME: () #[[ATTR1]] {
110+
// CHECK-NEXT: entry:
111+
// CHECK-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first()
112+
// CHECK-NEXT: ret i32 [[CALL]]
113+
//
114+
//
115+
// CHECK-LABEL: define {{[^@]+}}@implicit_default_decl_first.resolver() comdat {
116+
// CHECK-NEXT: resolver_entry:
117+
// CHECK-NEXT: ret ptr @implicit_default_decl_first.default
118+
//
119+
//
120+
// CHECK-LABEL: define {{[^@]+}}@explicit_default_def_first.resolver() comdat {
121+
// CHECK-NEXT: resolver_entry:
122+
// CHECK-NEXT: ret ptr @explicit_default_def_first.default
123+
//
124+
//
125+
// CHECK-LABEL: define {{[^@]+}}@implicit_default_def_first.resolver() comdat {
126+
// CHECK-NEXT: resolver_entry:
127+
// CHECK-NEXT: ret ptr @implicit_default_def_first.default
128+
//
129+
//
130+
// CHECK-LABEL: define {{[^@]+}}@explicit_default_decl_first.resolver() comdat {
131+
// CHECK-NEXT: resolver_entry:
132+
// CHECK-NEXT: ret ptr @explicit_default_decl_first.default
133+
//
134+
//
135+
// CHECK: declare i32 @no_def_implicit_default_first.default() #[[ATTR2]]
136+
//
137+
//
138+
// CHECK: declare i32 @no_def_explicit_default_first.default() #[[ATTR2]]
139+
//
140+
//
141+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
142+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller1
143+
// CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] {
144+
// CHECK-NOFMV-NEXT: entry:
145+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_decl_first()
146+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
147+
//
148+
//
149+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
150+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_decl_first
151+
// CHECK-NOFMV-SAME: () #[[ATTR1:[0-9]+]] {
152+
// CHECK-NOFMV-NEXT: entry:
153+
// CHECK-NOFMV-NEXT: ret i32 1
154+
//
155+
//
156+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
157+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller2
158+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
159+
// CHECK-NOFMV-NEXT: entry:
160+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_def_first()
161+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
162+
//
163+
//
164+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
165+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_def_first
166+
// CHECK-NOFMV-SAME: () #[[ATTR1]] {
167+
// CHECK-NOFMV-NEXT: entry:
168+
// CHECK-NOFMV-NEXT: ret i32 2
169+
//
170+
//
171+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
172+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default_def_first
173+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
174+
// CHECK-NOFMV-NEXT: entry:
175+
// CHECK-NOFMV-NEXT: ret i32 3
176+
//
177+
//
178+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
179+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller3
180+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
181+
// CHECK-NOFMV-NEXT: entry:
182+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default_def_first()
183+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
184+
//
185+
//
186+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
187+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller4
188+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
189+
// CHECK-NOFMV-NEXT: entry:
190+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @explicit_default_decl_first()
191+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
192+
//
193+
//
194+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
195+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@explicit_default_decl_first
196+
// CHECK-NOFMV-SAME: () #[[ATTR1]] {
197+
// CHECK-NOFMV-NEXT: entry:
198+
// CHECK-NOFMV-NEXT: ret i32 4
199+
//
200+
//
201+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
202+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller5
203+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
204+
// CHECK-NOFMV-NEXT: entry:
205+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_implicit_default_first()
206+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
207+
//
208+
//
209+
// CHECK-NOFMV: declare i32 @no_def_implicit_default_first() #[[ATTR2:[0-9]+]]
210+
//
211+
//
212+
// CHECK-NOFMV: Function Attrs: noinline nounwind optnone
213+
// CHECK-NOFMV-LABEL: define {{[^@]+}}@caller6
214+
// CHECK-NOFMV-SAME: () #[[ATTR0]] {
215+
// CHECK-NOFMV-NEXT: entry:
216+
// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @no_def_explicit_default_first()
217+
// CHECK-NOFMV-NEXT: ret i32 [[CALL]]
218+
//
219+
//
220+
// CHECK-NOFMV: declare i32 @no_def_explicit_default_first() #[[ATTR2]]
221+
//.

0 commit comments

Comments
 (0)