[clang] b359422 - [Clang][LoongArch] Support target attribute for function (#140700)
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 29 04:54:52 PDT 2025
Author: Ami-zhang
Date: 2025-05-29T19:54:48+08:00
New Revision: b359422eebbc61f0e0fb03c27ec1a93c818701ee
URL: https://github.com/llvm/llvm-project/commit/b359422eebbc61f0e0fb03c27ec1a93c818701ee
DIFF: https://github.com/llvm/llvm-project/commit/b359422eebbc61f0e0fb03c27ec1a93c818701ee.diff
LOG: [Clang][LoongArch] Support target attribute for function (#140700)
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.
Added:
clang/test/CodeGen/LoongArch/targetattr.c
clang/test/Sema/attr-target-loongarch.c
Modified:
clang/lib/Basic/Targets/LoongArch.cpp
clang/lib/Basic/Targets/LoongArch.h
clang/lib/Sema/SemaDeclAttr.cpp
llvm/include/llvm/TargetParser/LoongArchTargetParser.h
llvm/lib/TargetParser/LoongArchTargetParser.cpp
Removed:
################################################################################
diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
index f4bcb54bd470d..6e5e5a6d1a3e6 100644
--- a/clang/lib/Basic/Targets/LoongArch.cpp
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -393,6 +393,73 @@ bool LoongArchTargetInfo::handleTargetFeatures(
return true;
}
+enum class AttrFeatureKind { Arch, Tune, NoFeature, Feature };
+
+static std::pair<AttrFeatureKind, llvm::StringRef>
+getAttrFeatureTypeAndValue(llvm::StringRef AttrFeature) {
+ if (auto Split = AttrFeature.split("="); !Split.second.empty()) {
+ if (Split.first.trim() == "arch")
+ return {AttrFeatureKind::Arch, Split.second.trim()};
+ if (Split.first.trim() == "tune")
+ return {AttrFeatureKind::Tune, Split.second.trim()};
+ }
+ if (AttrFeature.starts_with("no-"))
+ return {AttrFeatureKind::NoFeature, AttrFeature.drop_front(3)};
+ return {AttrFeatureKind::Feature, AttrFeature};
+}
+
+ParsedTargetAttr
+LoongArchTargetInfo::parseTargetAttr(StringRef Features) const {
+ ParsedTargetAttr Ret;
+ if (Features == "default")
+ return Ret;
+ SmallVector<StringRef, 1> AttrFeatures;
+ Features.split(AttrFeatures, ",");
+
+ for (auto &Feature : AttrFeatures) {
+ auto [Kind, Value] = getAttrFeatureTypeAndValue(Feature.trim());
+
+ switch (Kind) {
+ case AttrFeatureKind::Arch: {
+ if (llvm::LoongArch::isValidArchName(Value) || Value == "la64v1.0" ||
+ Value == "la64v1.1") {
+ std::vector<llvm::StringRef> ArchFeatures;
+ if (llvm::LoongArch::getArchFeatures(Value, ArchFeatures)) {
+ Ret.Features.insert(Ret.Features.end(), ArchFeatures.begin(),
+ ArchFeatures.end());
+ }
+
+ if (!Ret.CPU.empty())
+ Ret.Duplicate = "arch=";
+ else if (Value == "la64v1.0" || Value == "la64v1.1")
+ Ret.CPU = "loongarch64";
+ else
+ Ret.CPU = Value;
+ } else {
+ Ret.Features.push_back("!arch=" + Value.str());
+ }
+ break;
+ }
+
+ case AttrFeatureKind::Tune:
+ if (!Ret.Tune.empty())
+ Ret.Duplicate = "tune=";
+ else
+ Ret.Tune = Value;
+ break;
+
+ case AttrFeatureKind::NoFeature:
+ Ret.Features.push_back("-" + Value.str());
+ break;
+
+ case AttrFeatureKind::Feature:
+ Ret.Features.push_back("+" + Value.str());
+ break;
+ }
+ }
+ return Ret;
+}
+
bool LoongArchTargetInfo::isValidCPUName(StringRef Name) const {
return llvm::LoongArch::isValidCPUName(Name);
}
@@ -401,3 +468,7 @@ void LoongArchTargetInfo::fillValidCPUList(
SmallVectorImpl<StringRef> &Values) const {
llvm::LoongArch::fillValidCPUList(Values);
}
+
+bool LoongArchTargetInfo::isValidFeatureName(StringRef Name) const {
+ return llvm::LoongArch::isValidFeatureName(Name);
+}
diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h
index 4c7b53abfef9b..a83bb925bc310 100644
--- a/clang/lib/Basic/Targets/LoongArch.h
+++ b/clang/lib/Basic/Targets/LoongArch.h
@@ -101,6 +101,9 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool handleTargetFeatures(std::vector<std::string> &Features,
DiagnosticsEngine &Diags) override;
+ ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
+ bool supportsTargetAttributeTune() const override { return true; }
+
bool
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
StringRef CPU,
@@ -110,6 +113,7 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool isValidCPUName(StringRef Name) const override;
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
+ bool isValidFeatureName(StringRef Name) const override;
};
class LLVM_LIBRARY_VISIBILITY LoongArch32TargetInfo
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 54bac40982eda..0adc04f06100e 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3194,6 +3194,17 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
}
}
+ if (Context.getTargetInfo().getTriple().isLoongArch()) {
+ for (const auto &Feature : ParsedAttrs.Features) {
+ StringRef CurFeature = Feature;
+ if (CurFeature.starts_with("!arch=")) {
+ StringRef ArchValue = CurFeature.split("=").second.trim();
+ return Diag(LiteralLoc, diag::err_attribute_unsupported)
+ << "target(arch=..)" << ArchValue;
+ }
+ }
+ }
+
if (ParsedAttrs.Duplicate != "")
return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
<< Duplicate << None << ParsedAttrs.Duplicate << Target;
diff --git a/clang/test/CodeGen/LoongArch/targetattr.c b/clang/test/CodeGen/LoongArch/targetattr.c
new file mode 100644
index 0000000000000..5546af8fc856c
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/targetattr.c
@@ -0,0 +1,92 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 5
+// RUN: %clang --target=loongarch64-linux-gnu %s -S -emit-llvm -o - \
+// RUN: | FileCheck %s
+
+__attribute__((target("div32")))
+// CHECK-LABEL: define dso_local void @testdiv32(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testdiv32() {}
+
+__attribute__((target("arch=loongarch64")))
+// CHECK-LABEL: define dso_local void @testLoongarch64(
+// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testLoongarch64() {}
+
+__attribute__((target("arch=la64v1.0")))
+// CHECK-LABEL: define dso_local void @testLa64v10(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testLa64v10() {}
+
+__attribute__((target("arch=la64v1.1")))
+// CHECK-LABEL: define dso_local void @testLa64v11(
+// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testLa64v11() {}
+
+__attribute__((target("arch=la464")))
+// CHECK-LABEL: define dso_local void @testLa464(
+// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testLa464() {}
+
+__attribute__((target("arch=la664")))
+// CHECK-LABEL: define dso_local void @testLa664(
+// CHECK-SAME: ) #[[ATTR4:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void testLa664() {}
+
+__attribute__((target("arch=la664, no-div32")))
+// CHECK-LABEL: define dso_local void @la664Nodiv32(
+// CHECK-SAME: ) #[[ATTR5:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void la664Nodiv32() {}
+
+__attribute__((target("tune=la464")))
+// CHECK-LABEL: define dso_local void @tuneLa464(
+// CHECK-SAME: ) #[[ATTR6:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void tuneLa464() {}
+
+__attribute__((target("arch=la464, tune=la664")))
+// CHECK-LABEL: define dso_local void @archLa464tuneLa664(
+// CHECK-SAME: ) #[[ATTR7:[0-9]+]] {
+// CHECK-NEXT: [[ENTRY:.*:]]
+// CHECK-NEXT: ret void
+//
+void archLa464tuneLa664() {}
+
+//.
+// 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" }
+// 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" }
+// 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" }
+// 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" }
+// 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" }
+// 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" }
+// 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" }
+// 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" }
+//.
+// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4}
+// CHECK: [[META1:![0-9]+]] = !{i32 8, !"PIC Level", i32 2}
+// CHECK: [[META2:![0-9]+]] = !{i32 7, !"PIE Level", i32 2}
+// CHECK: [[META3:![0-9]+]] = !{i32 7, !"frame-pointer", i32 2}
+// CHECK: [[META4:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"}
+//.
diff --git a/clang/test/Sema/attr-target-loongarch.c b/clang/test/Sema/attr-target-loongarch.c
new file mode 100644
index 0000000000000..10ac8334bdb0c
--- /dev/null
+++ b/clang/test/Sema/attr-target-loongarch.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple loongarch64-linux-gnu -fsyntax-only -verify %s
+
+// expected-error at +1 {{function multiversioning is not supported on the current target}}
+void __attribute__((target("default"))) bar(void) {}
+
+// expected-error at +1 {{target(arch=..) attribute is not supported on targets missing invalid; specify an appropriate -march= or -mcpu=}}
+void __attribute__((target("arch=invalid"))) foo(void) {}
+
+// expected-warning at +1 {{unsupported '+div32' in the 'target' attribute string; 'target' attribute ignored}}
+void __attribute__((target("+div32"))) plusfeature(void) {}
+
+// expected-warning at +1 {{unsupported '-div32' in the 'target' attribute string; 'target' attribute ignored}}
+void __attribute__((target("-div32"))) minusfeature(void) {}
+
+// expected-warning at +1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("aaa"))) test_feature(void) { return 4; }
+
+// expected-warning at +1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("no-aaa"))) test_nofeature(void) { return 4; }
+
+// expected-warning at +1 {{duplicate 'arch=' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("arch=la464,arch=la664"))) test_duplarch(void) { return 4; }
+
+// expected-warning at +1 {{unknown tune CPU 'la64v1.0' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("tune=la64v1.0"))) test_tune(void) { return 4; }
diff --git a/llvm/include/llvm/TargetParser/LoongArchTargetParser.h b/llvm/include/llvm/TargetParser/LoongArchTargetParser.h
index e08e7bc182e11..a28e4e9eff811 100644
--- a/llvm/include/llvm/TargetParser/LoongArchTargetParser.h
+++ b/llvm/include/llvm/TargetParser/LoongArchTargetParser.h
@@ -85,6 +85,7 @@ struct ArchInfo {
};
bool isValidArchName(StringRef Arch);
+bool isValidFeatureName(StringRef Feature);
bool getArchFeatures(StringRef Arch, std::vector<StringRef> &Features);
bool isValidCPUName(StringRef TuneCPU);
void fillValidCPUList(SmallVectorImpl<StringRef> &Values);
diff --git a/llvm/lib/TargetParser/LoongArchTargetParser.cpp b/llvm/lib/TargetParser/LoongArchTargetParser.cpp
index e394c0c15b207..db68498609b57 100644
--- a/llvm/lib/TargetParser/LoongArchTargetParser.cpp
+++ b/llvm/lib/TargetParser/LoongArchTargetParser.cpp
@@ -34,6 +34,18 @@ bool LoongArch::isValidArchName(StringRef Arch) {
return false;
}
+bool LoongArch::isValidFeatureName(StringRef Feature) {
+ if (Feature.starts_with("+") || Feature.starts_with("-"))
+ return false;
+ for (const auto &F : AllFeatures) {
+ StringRef CanonicalName =
+ F.Name.starts_with("+") ? F.Name.drop_front() : F.Name;
+ if (CanonicalName == Feature)
+ return true;
+ }
+ return false;
+}
+
bool LoongArch::getArchFeatures(StringRef Arch,
std::vector<StringRef> &Features) {
for (const auto A : AllArchs) {
More information about the cfe-commits
mailing list