Skip to content

Commit c5e14f9

Browse files
committed
[Clang][LoongArch] Support target attribute for function
This adds support under LoongArch for the target("..") attributes. The supported formats are: - "arch=<arch>" strings, that specify the architecture features for a function as per the -march=arch option. - "tune=<cpu>" strings, that specify the tune-cpu cpu for a function as per -mtune. - "<feature>", "no-<feature>" enabled/disables the specific feature.
1 parent b95ad8e commit c5e14f9

File tree

7 files changed

+187
-0
lines changed

7 files changed

+187
-0
lines changed

clang/lib/Basic/Targets/LoongArch.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,51 @@ bool LoongArchTargetInfo::handleTargetFeatures(
388388
return true;
389389
}
390390

391+
ParsedTargetAttr
392+
LoongArchTargetInfo::parseTargetAttr(StringRef Features) const {
393+
ParsedTargetAttr Ret;
394+
if (Features == "default")
395+
return Ret;
396+
SmallVector<StringRef, 1> AttrFeatures;
397+
Features.split(AttrFeatures, ",");
398+
399+
for (auto &Feature : AttrFeatures) {
400+
Feature = Feature.trim();
401+
402+
if (Feature.starts_with("arch=")) {
403+
StringRef ArchValue = Feature.split("=").second.trim();
404+
405+
if (llvm::LoongArch::isValidArchName(ArchValue) ||
406+
ArchValue == "la64v1.0" || ArchValue == "la64v1.1") {
407+
std::vector<llvm::StringRef> ArchFeatures;
408+
if (llvm::LoongArch::getArchFeatures(ArchValue, ArchFeatures)) {
409+
Ret.Features.insert(Ret.Features.end(), ArchFeatures.begin(),
410+
ArchFeatures.end());
411+
}
412+
413+
if (!Ret.CPU.empty())
414+
Ret.Duplicate = "arch=";
415+
else if (ArchValue == "la64v1.0" || ArchValue == "la64v1.1")
416+
Ret.CPU = "loongarch64";
417+
else
418+
Ret.CPU = ArchValue;
419+
} else {
420+
Ret.Features.push_back("!arch=" + ArchValue.str());
421+
}
422+
} else if (Feature.starts_with("tune=")) {
423+
if (!Ret.Tune.empty())
424+
Ret.Duplicate = "tune=";
425+
else
426+
Ret.Tune = Feature.split("=").second.trim();
427+
} else if (Feature.starts_with("no-")) {
428+
Ret.Features.push_back("-" + Feature.split("-").second.str());
429+
} else {
430+
Ret.Features.push_back("+" + Feature.str());
431+
}
432+
}
433+
return Ret;
434+
}
435+
391436
bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const {
392437
return llvm::LoongArch::isValidCPUName(Name);
393438
}
@@ -396,3 +441,7 @@ void LoongArchTargetInfo::fillValidCPUList(
396441
SmallVectorImpl<StringRef> &Values) const {
397442
llvm::LoongArch::fillValidCPUList(Values);
398443
}
444+
445+
bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const {
446+
return llvm::LoongArch::isValidFeatureName(Name);
447+
}

clang/lib/Basic/Targets/LoongArch.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
101101
bool handleTargetFeatures(std::vector<std::string> &Features,
102102
DiagnosticsEngine &Diags) override;
103103

104+
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
105+
bool supportsTargetAttributeTune() const override { return true; }
106+
104107
bool
105108
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
106109
StringRef CPU,
@@ -110,6 +113,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
110113

111114
bool isValidCPUName(StringRef Name) const override;
112115
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
116+
bool isValidFeatureName(StringRef Name) const override;
113117
};
114118

115119
class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3195,6 +3195,17 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
31953195
}
31963196
}
31973197

3198+
if (Context.getTargetInfo().getTriple().isLoongArch()) {
3199+
for (const auto &Feature : ParsedAttrs.Features) {
3200+
StringRef CurFeature = Feature;
3201+
if (CurFeature.starts_with("!arch=")) {
3202+
StringRef ArchValue = CurFeature.split("=").second.trim();
3203+
return Diag(LiteralLoc, diag::err_attribute_unsupported)
3204+
<< "target(arch=..)" << ArchValue;
3205+
}
3206+
}
3207+
}
3208+
31983209
if (ParsedAttrs.Duplicate != "")
31993210
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
32003211
<< Duplicate << None << ParsedAttrs.Duplicate << Target;
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 5
2+
// RUN: %clang --target=loongarch64-linux-gnu %s -S -emit-llvm -o - \
3+
// RUN: | FileCheck %s
4+
5+
__attribute__((target("div32")))
6+
// CHECK-LABEL: define dso_local void @testdiv32(
7+
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
8+
// CHECK-NEXT: [[ENTRY:.*:]]
9+
// CHECK-NEXT: ret void
10+
//
11+
void testdiv32() {}
12+
13+
__attribute__((target("arch=loongarch64")))
14+
// CHECK-LABEL: define dso_local void @testLoongarch64(
15+
// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
16+
// CHECK-NEXT: [[ENTRY:.*:]]
17+
// CHECK-NEXT: ret void
18+
//
19+
void testLoongarch64() {}
20+
21+
__attribute__((target("arch=la64v1.0")))
22+
// CHECK-LABEL: define dso_local void @testLa64v10(
23+
// CHECK-SAME: ) #[[ATTR1]] {
24+
// CHECK-NEXT: [[ENTRY:.*:]]
25+
// CHECK-NEXT: ret void
26+
//
27+
void testLa64v10() {}
28+
29+
__attribute__((target("arch=la64v1.1")))
30+
// CHECK-LABEL: define dso_local void @testLa64v11(
31+
// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
32+
// CHECK-NEXT: [[ENTRY:.*:]]
33+
// CHECK-NEXT: ret void
34+
//
35+
void testLa64v11() {}
36+
37+
__attribute__((target("arch=la464")))
38+
// CHECK-LABEL: define dso_local void @testLa464(
39+
// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
40+
// CHECK-NEXT: [[ENTRY:.*:]]
41+
// CHECK-NEXT: ret void
42+
//
43+
void testLa464() {}
44+
45+
__attribute__((target("arch=la664")))
46+
// CHECK-LABEL: define dso_local void @testLa664(
47+
// CHECK-SAME: ) #[[ATTR4:[0-9]+]] {
48+
// CHECK-NEXT: [[ENTRY:.*:]]
49+
// CHECK-NEXT: ret void
50+
//
51+
void testLa664() {}
52+
53+
__attribute__((target("arch=la664, no-div32")))
54+
// CHECK-LABEL: define dso_local void @la664Nodiv32(
55+
// CHECK-SAME: ) #[[ATTR5:[0-9]+]] {
56+
// CHECK-NEXT: [[ENTRY:.*:]]
57+
// CHECK-NEXT: ret void
58+
//
59+
void la664Nodiv32() {}
60+
61+
__attribute__((target("tune=la464")))
62+
// CHECK-LABEL: define dso_local void @tuneLa664(
63+
// CHECK-SAME: ) #[[ATTR6:[0-9]+]] {
64+
// CHECK-NEXT: [[ENTRY:.*:]]
65+
// CHECK-NEXT: ret void
66+
//
67+
void tuneLa664() {}
68+
69+
__attribute__((target("arch=la464, tune=la664")))
70+
// CHECK-LABEL: define dso_local void @archLa464tuneLa664(
71+
// CHECK-SAME: ) #[[ATTR7:[0-9]+]] {
72+
// CHECK-NEXT: [[ENTRY:.*:]]
73+
// CHECK-NEXT: ret void
74+
//
75+
void archLa464tuneLa664() {}
76+
77+
//.
78+
// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+div32,+f,+lsx,+ual" }
79+
// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+f,+lsx,+ual" }
80+
// CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+div32,+f,+frecipe,+lam-bh,+lamcas,+ld-seq-sa,+lsx,+scq,+ual" }
81+
// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="la464" "target-features"="+64bit,+d,+f,+lasx,+lsx,+ual" }
82+
// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="la664" "target-features"="+64bit,+d,+div32,+f,+frecipe,+lam-bh,+lamcas,+lasx,+ld-seq-sa,+lsx,+scq,+ual" }
83+
// CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="la664" "target-features"="+64bit,+d,+f,+frecipe,+lam-bh,+lamcas,+lasx,+ld-seq-sa,+lsx,+scq,+ual,-div32" }
84+
// CHECK: attributes #[[ATTR6]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+f,+lsx,+ual" "tune-cpu"="la464" }
85+
// CHECK: attributes #[[ATTR7]] = { noinline nounwind optnone "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="la464" "target-features"="+64bit,+d,+f,+lasx,+lsx,+ual" "tune-cpu"="la664" }
86+
//.
87+
// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
88+
// CHECK: [[META1:![0-9]+]] = !{i32 8, !"PIC Level", i32 2}
89+
// CHECK: [[META2:![0-9]+]] = !{i32 7, !"PIE Level", i32 2}
90+
// CHECK: [[META3:![0-9]+]] = !{i32 7, !"frame-pointer", i32 2}
91+
// CHECK: [[META4:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
92+
//.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -triple loongarch64-linux-gnu -fsyntax-only -verify %s
2+
3+
// expected-error@+1 {{function multiversioning is not supported on the current target}}
4+
void __attribute__((target("default"))) bar(void){}
5+
6+
// expected-error@+1 {{target(arch=..) attribute is not supported on targets missing invalid; specify an appropriate -march= or -mcpu=}}
7+
void __attribute__((target("arch=invalid"))) foo(void){}
8+
9+
//expected-warning@+1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
10+
int __attribute__((target("aaa"))) test_feature(void) { return 4; }
11+
12+
//expected-warning@+1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
13+
int __attribute__((target("no-aaa"))) test_nofeature(void) { return 4; }
14+
15+
//expected-warning@+1 {{duplicate 'arch=' in the 'target' attribute string; 'target' attribute ignored}}
16+
int __attribute__((target("arch=la464,arch=la664"))) test_duplarch(void) { return 4; }
17+
18+
//expected-warning@+1 {{unknown tune CPU 'la64v1.0' in the 'target' attribute string; 'target' attribute ignored}}
19+
int __attribute__((target("tune=la64v1.0"))) test_tune(void) { return 4; }

llvm/include/llvm/TargetParser/LoongArchTargetParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct ArchInfo {
8585
};
8686

8787
bool isValidArchName(StringRef Arch);
88+
bool isValidFeatureName(StringRef Arch);
8889
bool getArchFeatures(StringRef Arch, std::vector<StringRef> &Features);
8990
bool isValidCPUName(StringRef TuneCPU);
9091
void fillValidCPUList(SmallVectorImpl<StringRef> &Values);

llvm/lib/TargetParser/LoongArchTargetParser.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,17 @@ bool LoongArch::isValidArchName(StringRef Arch) {
3434
return false;
3535
}
3636

37+
bool LoongArch::isValidFeatureName(StringRef Feature) {
38+
Feature = Feature.starts_with("+") ? Feature.drop_front() : Feature;
39+
for (const auto F : AllFeatures) {
40+
StringRef CanonicalName =
41+
F.Name.starts_with("+") ? F.Name.drop_front() : F.Name;
42+
if (CanonicalName == Feature)
43+
return true;
44+
}
45+
return false;
46+
}
47+
3748
bool LoongArch::getArchFeatures(StringRef Arch,
3849
std::vector<StringRef> &Features) {
3950
for (const auto A : AllArchs) {

0 commit comments

Comments
 (0)