Skip to content

Commit 32e2a27

Browse files
committed
[RISCV][FMV] Support target_version
1 parent bce1117 commit 32e2a27

File tree

7 files changed

+377
-16
lines changed

7 files changed

+377
-16
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13861,9 +13861,16 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1386113861
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1386213862
}
1386313863
} else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
13864-
llvm::SmallVector<StringRef, 8> Feats;
13865-
TV->getFeatures(Feats);
13866-
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
13864+
std::vector<std::string> Features;
13865+
if (Target->getTriple().isRISCV()) {
13866+
ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TV->getName());
13867+
Features.insert(Features.begin(), ParsedAttr.Features.begin(),
13868+
ParsedAttr.Features.end());
13869+
} else {
13870+
llvm::SmallVector<StringRef, 8> Feats;
13871+
TV->getFeatures(Feats);
13872+
Features = getFMVBackendFeaturesFor(Feats);
13873+
}
1386713874
Features.insert(Features.begin(),
1386813875
Target->getTargetOpts().FeaturesAsWritten.begin(),
1386913876
Target->getTargetOpts().FeaturesAsWritten.end());

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4243,8 +4243,15 @@ void CodeGenModule::emitMultiVersionFunctions() {
42434243
CurFD->doesThisDeclarationHaveABody();
42444244
HasDefaultDecl |= TVA->isDefaultVersion();
42454245
ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
4246-
TVA->getFeatures(Feats);
42474246
llvm::Function *Func = createFunction(CurFD);
4247+
if (getTarget().getTriple().isRISCV()) {
4248+
llvm::AttrBuilder FuncAttrs(Func->getContext());
4249+
ParsedTargetAttr PTA =
4250+
getTarget().parseTargetAttr(TVA->getName());
4251+
Feats.push_back(TVA->getName());
4252+
} else {
4253+
TVA->getFeatures(Feats);
4254+
}
42484255
Options.emplace_back(Func, /*Architecture*/ "", Feats);
42494256
} else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
42504257
ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10259,8 +10259,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
1025910259
// Handle attributes.
1026010260
ProcessDeclAttributes(S, NewFD, D);
1026110261
const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
10262-
if (NewTVA && !NewTVA->isDefaultVersion() &&
10263-
!Context.getTargetInfo().hasFeature("fmv")) {
10262+
if (Context.getTargetInfo().getTriple().isRISCV()) {
10263+
// Go thought anyway.
10264+
} else if (NewTVA && !NewTVA->isDefaultVersion() &&
10265+
!Context.getTargetInfo().hasFeature("fmv")) {
1026410266
// Don't add to scope fmv functions declarations if fmv disabled
1026510267
AddToScope = false;
1026610268
return NewFD;
@@ -10967,13 +10969,27 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
1096710969
}
1096810970

1096910971
if (TVA) {
10970-
llvm::SmallVector<StringRef, 8> Feats;
10971-
TVA->getFeatures(Feats);
10972-
for (const auto &Feat : Feats) {
10973-
if (!TargetInfo.validateCpuSupports(Feat)) {
10974-
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
10975-
<< Feature << Feat;
10976-
return true;
10972+
if (S.getASTContext().getTargetInfo().getTriple().isRISCV()) {
10973+
ParsedTargetAttr ParseInfo =
10974+
S.getASTContext().getTargetInfo().parseTargetAttr(TVA->getName());
10975+
for (const auto &Feat : ParseInfo.Features) {
10976+
StringRef BareFeat = StringRef{Feat}.substr(1);
10977+
10978+
if (!TargetInfo.isValidFeatureName(BareFeat)) {
10979+
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
10980+
<< Feature << BareFeat;
10981+
return true;
10982+
}
10983+
}
10984+
} else {
10985+
llvm::SmallVector<StringRef, 8> Feats;
10986+
TVA->getFeatures(Feats);
10987+
for (const auto &Feat : Feats) {
10988+
if (!TargetInfo.validateCpuSupports(Feat)) {
10989+
S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
10990+
<< Feature << Feat;
10991+
return true;
10992+
}
1097710993
}
1097810994
}
1097910995
}
@@ -11238,7 +11254,8 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
1123811254
}
1123911255

1124011256
static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {
11241-
if (!From->getASTContext().getTargetInfo().getTriple().isAArch64())
11257+
if (!From->getASTContext().getTargetInfo().getTriple().isAArch64() &&
11258+
!From->getASTContext().getTargetInfo().getTriple().isRISCV())
1124211259
return;
1124311260

1124411261
MultiVersionKind MVKindFrom = From->getMultiVersionKind();
@@ -15418,8 +15435,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
1541815435
FD->setInvalidDecl();
1541915436
}
1542015437
if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
15421-
if (!Context.getTargetInfo().hasFeature("fmv") &&
15422-
!Attr->isDefaultVersion()) {
15438+
if (Context.getTargetInfo().getTriple().isRISCV()) {
15439+
// pass thought anyway.
15440+
} else if (!Context.getTargetInfo().hasFeature("fmv") &&
15441+
!Attr->isDefaultVersion()) {
1542315442
// If function multi versioning disabled skip parsing function body
1542415443
// defined with non-default target_version attribute
1542515444
if (SkipBody)

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3015,6 +3015,21 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
30153015
enum SecondParam { None };
30163016
enum ThirdParam { Target, TargetClones, TargetVersion };
30173017
llvm::SmallVector<StringRef, 8> Features;
3018+
if (Context.getTargetInfo().getTriple().isRISCV()) {
3019+
3020+
if (AttrStr.starts_with("default"))
3021+
return false;
3022+
3023+
ParsedTargetAttr ParsedAttrs =
3024+
Context.getTargetInfo().parseTargetAttr(AttrStr);
3025+
3026+
if (AttrStr.starts_with("arch=+") &&
3027+
(!ParsedAttrs.Features.empty() || !ParsedAttrs.Tune.empty()))
3028+
return false;
3029+
3030+
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
3031+
<< Unsupported << None << AttrStr << TargetVersion;
3032+
}
30183033
AttrStr.split(Features, "+");
30193034
for (auto &CurFeature : Features) {
30203035
CurFeature = CurFeature.trim();
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 4
2+
// RUN: %clang_cc1 -triple riscv64-linux-gnu -target-feature +i -emit-llvm -o - %s | FileCheck %s
3+
4+
__attribute__((target_version("arch=+v"))) int foo1(void) { return 1; }
5+
__attribute__((target_version("default"))) int foo1(void) { return 1; }
6+
7+
__attribute__((target_version("arch=+zbb"))) int foo2(void) { return 2; }
8+
__attribute__((target_version("arch=+m"))) int foo2(void) { return 2; }
9+
__attribute__((target_version("default"))) int foo2(void) { return 2; }
10+
11+
__attribute__((target_version("arch=+zbb,+c"))) int foo3(void) { return 3; }
12+
__attribute__((target_version("arch=+m"))) int foo3(void) { return 3; }
13+
__attribute__((target_version("default"))) int foo3(void) { return 3; }
14+
15+
int bar() { return foo1() + foo2() + foo3(); }
16+
//.
17+
// CHECK: @__riscv_feature_bits = external dso_local global { i32, [1 x i64] }
18+
// CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver
19+
// CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver
20+
// CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver
21+
//.
22+
// CHECK-LABEL: define dso_local signext i32 @foo1.default(
23+
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
24+
// CHECK-NEXT: entry:
25+
// CHECK-NEXT: ret i32 1
26+
//
27+
//
28+
// CHECK-LABEL: define dso_local signext i32 @foo2.default(
29+
// CHECK-SAME: ) #[[ATTR1]] {
30+
// CHECK-NEXT: entry:
31+
// CHECK-NEXT: ret i32 2
32+
//
33+
//
34+
// CHECK-LABEL: define dso_local signext i32 @foo3.default(
35+
// CHECK-SAME: ) #[[ATTR1]] {
36+
// CHECK-NEXT: entry:
37+
// CHECK-NEXT: ret i32 3
38+
//
39+
//
40+
// CHECK-LABEL: define dso_local signext i32 @bar(
41+
// CHECK-SAME: ) #[[ATTR1]] {
42+
// CHECK-NEXT: entry:
43+
// CHECK-NEXT: [[CALL:%.*]] = call signext i32 @foo1()
44+
// CHECK-NEXT: [[CALL1:%.*]] = call signext i32 @foo2()
45+
// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]]
46+
// CHECK-NEXT: [[CALL2:%.*]] = call signext i32 @foo3()
47+
// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]]
48+
// CHECK-NEXT: ret i32 [[ADD3]]
49+
//
50+
//
51+
// CHECK-LABEL: define weak_odr ptr @foo1.resolver() comdat {
52+
// CHECK-NEXT: resolver_entry:
53+
// CHECK-NEXT: call void @__init_riscv_features_bits()
54+
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__riscv_feature_bits, align 8
55+
// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 0, [[TMP0]]
56+
// CHECK-NEXT: br i1 [[TMP1]], label [[RESOVLER_COND:%.*]], label [[RESOLVER_ELSE:%.*]]
57+
// CHECK: resovler_cond:
58+
// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
59+
// CHECK-NEXT: [[TMP3:%.*]] = and i64 [[TMP2]], 2097152
60+
// CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], 2097152
61+
// CHECK-NEXT: [[TMP5:%.*]] = and i1 true, [[TMP4]]
62+
// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE]]
63+
// CHECK: resolver_return:
64+
// CHECK-NEXT: ret ptr @"foo1.arch=+v"
65+
// CHECK: resolver_else:
66+
// CHECK-NEXT: ret ptr @foo1.default
67+
//
68+
//
69+
// CHECK-LABEL: define weak_odr ptr @foo2.resolver() comdat {
70+
// CHECK-NEXT: resolver_entry:
71+
// CHECK-NEXT: call void @__init_riscv_features_bits()
72+
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__riscv_feature_bits, align 8
73+
// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 0, [[TMP0]]
74+
// CHECK-NEXT: br i1 [[TMP1]], label [[RESOVLER_COND:%.*]], label [[RESOLVER_ELSE:%.*]]
75+
// CHECK: resovler_cond:
76+
// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
77+
// CHECK-NEXT: [[TMP3:%.*]] = and i64 [[TMP2]], 268435456
78+
// CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], 268435456
79+
// CHECK-NEXT: [[TMP5:%.*]] = and i1 true, [[TMP4]]
80+
// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE]]
81+
// CHECK: resolver_return:
82+
// CHECK-NEXT: ret ptr @"foo2.arch=+zbb"
83+
// CHECK: resolver_else:
84+
// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr @__riscv_feature_bits, align 8
85+
// CHECK-NEXT: [[TMP7:%.*]] = icmp ult i64 0, [[TMP6]]
86+
// CHECK-NEXT: br i1 [[TMP7]], label [[RESOVLER_COND1:%.*]], label [[RESOLVER_ELSE3:%.*]]
87+
// CHECK: resovler_cond1:
88+
// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
89+
// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 4096
90+
// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 4096
91+
// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]]
92+
// CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN2:%.*]], label [[RESOLVER_ELSE3]]
93+
// CHECK: resolver_return2:
94+
// CHECK-NEXT: ret ptr @"foo2.arch=+m"
95+
// CHECK: resolver_else3:
96+
// CHECK-NEXT: ret ptr @foo2.default
97+
//
98+
//
99+
// CHECK-LABEL: define weak_odr ptr @foo3.resolver() comdat {
100+
// CHECK-NEXT: resolver_entry:
101+
// CHECK-NEXT: call void @__init_riscv_features_bits()
102+
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__riscv_feature_bits, align 8
103+
// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 0, [[TMP0]]
104+
// CHECK-NEXT: br i1 [[TMP1]], label [[RESOVLER_COND:%.*]], label [[RESOLVER_ELSE:%.*]]
105+
// CHECK: resovler_cond:
106+
// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
107+
// CHECK-NEXT: [[TMP3:%.*]] = and i64 [[TMP2]], 12
108+
// CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[TMP3]], 12
109+
// CHECK-NEXT: [[TMP5:%.*]] = and i1 true, [[TMP4]]
110+
// CHECK-NEXT: br i1 [[TMP5]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE]]
111+
// CHECK: resolver_return:
112+
// CHECK-NEXT: ret ptr @"foo3.arch=+zbb,+c"
113+
// CHECK: resolver_else:
114+
// CHECK-NEXT: [[TMP6:%.*]] = load i64, ptr @__riscv_feature_bits, align 8
115+
// CHECK-NEXT: [[TMP7:%.*]] = icmp ult i64 0, [[TMP6]]
116+
// CHECK-NEXT: br i1 [[TMP7]], label [[RESOVLER_COND1:%.*]], label [[RESOLVER_ELSE3:%.*]]
117+
// CHECK: resovler_cond1:
118+
// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
119+
// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 4096
120+
// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 4096
121+
// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]]
122+
// CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN2:%.*]], label [[RESOLVER_ELSE3]]
123+
// CHECK: resolver_return2:
124+
// CHECK-NEXT: ret ptr @"foo3.arch=+m"
125+
// CHECK: resolver_else3:
126+
// CHECK-NEXT: ret ptr @foo3.default
127+
//
128+
//.
129+
// CHECK: attributes #[[ATTR0:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+d,+f,+i,+v,+zicsr,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b" }
130+
// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i" }
131+
// CHECK: attributes #[[ATTR2:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+zbb" }
132+
// CHECK: attributes #[[ATTR3:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+i,+m,+zmmul" }
133+
// CHECK: attributes #[[ATTR4:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+c,+i,+zbb" }
134+
//.
135+
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
136+
// CHECK: [[META1:![0-9]+]] = !{i32 1, !"target-abi", !"lp64"}
137+
// CHECK: [[META2:![0-9]+]] = !{i32 6, !"riscv-isa", [[META3:![0-9]+]]}
138+
// CHECK: [[META3]] = !{!"rv64i2p1"}
139+
// CHECK: [[META4:![0-9]+]] = !{i32 8, !"SmallDataLimit", i32 0}
140+
// CHECK: [[META5:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
141+
//.

0 commit comments

Comments
 (0)