Skip to content

Reland "[Clang][LoongArch] Support target attribute for function" #142546

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 3, 2025

Conversation

Ami-zhang
Copy link
Contributor

This relands #140700. I have updated the test case('targetattr.c') to resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173 https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to #140700.

This relands llvm#140700. I have updated the test case('targetattr.c')
to resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173
https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to llvm#140700.
@Ami-zhang Ami-zhang requested review from wangleiat and SixWeining June 3, 2025 06:21
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" backend:loongarch labels Jun 3, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 3, 2025

@llvm/pr-subscribers-backend-loongarch

@llvm/pr-subscribers-clang

Author: None (Ami-zhang)

Changes

This relands #140700. I have updated the test case('targetattr.c') to resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173 https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to #140700.


Full diff: https://github.com/llvm/llvm-project/pull/142546.diff

7 Files Affected:

  • (modified) clang/lib/Basic/Targets/LoongArch.cpp (+71)
  • (modified) clang/lib/Basic/Targets/LoongArch.h (+4)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+11)
  • (added) clang/test/CodeGen/LoongArch/targetattr.c (+89)
  • (added) clang/test/Sema/attr-target-loongarch.c (+25)
  • (modified) llvm/include/llvm/TargetParser/LoongArchTargetParser.h (+1)
  • (modified) llvm/lib/TargetParser/LoongArchTargetParser.cpp (+12)
diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp
index 67476ee651c2b..5312767498d96 100644
--- a/clang/lib/Basic/Targets/LoongArch.cpp
+++ b/clang/lib/Basic/Targets/LoongArch.cpp
@@ -392,6 +392,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);
 }
@@ -400,3 +467,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 aba989f1029b9..a8e4023fb02ba 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3195,6 +3195,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..91156e6006e75
--- /dev/null
+++ b/clang/test/CodeGen/LoongArch/targetattr.c
@@ -0,0 +1,89 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --version 5
+// RUN: %clang_cc1 -triple loongarch64 -emit-llvm %s -o - | 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: ) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+//
+void testLa64v10() {}
+
+__attribute__((target("arch=la64v1.1")))
+// CHECK-LABEL: define dso_local void @testLa64v11(
+// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+//
+void testLa64v11() {}
+
+__attribute__((target("arch=la464")))
+// CHECK-LABEL: define dso_local void @testLa464(
+// CHECK-SAME: ) #[[ATTR4:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+//
+void testLa464() {}
+
+__attribute__((target("arch=la664")))
+// CHECK-LABEL: define dso_local void @testLa664(
+// CHECK-SAME: ) #[[ATTR5:[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: ) #[[ATTR6:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+//
+void la664Nodiv32() {}
+
+__attribute__((target("tune=la464")))
+// CHECK-LABEL: define dso_local void @tuneLa464(
+// CHECK-SAME: ) #[[ATTR7:[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: ) #[[ATTR8:[0-9]+]] {
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    ret void
+//
+void archLa464tuneLa664() {}
+
+//.
+// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit,+div32" }
+// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+f,+ual" }
+// CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+lsx,+ual" }
+// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="loongarch64" "target-features"="+64bit,+d,+div32,+frecipe,+lam-bh,+lamcas,+ld-seq-sa,+lsx,+scq,+ual" }
+// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="la464" "target-features"="+64bit,+d,+f,+lasx,+lsx,+ual" }
+// CHECK: attributes #[[ATTR5]] = { noinline nounwind optnone "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 #[[ATTR6]] = { noinline nounwind optnone "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 #[[ATTR7]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+64bit" "tune-cpu"="la464" }
+// CHECK: attributes #[[ATTR8]] = { noinline nounwind optnone "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]+]] = !{!"{{.*}}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@+1 {{function multiversioning is not supported on the current target}}
+void __attribute__((target("default"))) bar(void) {}
+
+// expected-error@+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@+1 {{unsupported '+div32' in the 'target' attribute string; 'target' attribute ignored}}
+void __attribute__((target("+div32"))) plusfeature(void) {}
+
+// expected-warning@+1 {{unsupported '-div32' in the 'target' attribute string; 'target' attribute ignored}}
+void __attribute__((target("-div32"))) minusfeature(void) {}
+
+// expected-warning@+1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("aaa"))) test_feature(void) { return 4; }
+
+// expected-warning@+1 {{unsupported 'aaa' in the 'target' attribute string; 'target' attribute ignored}}
+int __attribute__((target("no-aaa"))) test_nofeature(void) { return 4; }
+
+// expected-warning@+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@+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) {

@Ami-zhang Ami-zhang merged commit 06f779b into llvm:main Jun 3, 2025
15 checks passed
sallto pushed a commit to sallto/llvm-project that referenced this pull request Jun 3, 2025
…vm#142546)

This relands llvm#140700. I have updated the test case('targetattr.c') to
resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173
https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to llvm#140700.
rorth pushed a commit to rorth/llvm-project that referenced this pull request Jun 11, 2025
…vm#142546)

This relands llvm#140700. I have updated the test case('targetattr.c') to
resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173
https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to llvm#140700.
DhruvSrivastavaX pushed a commit to DhruvSrivastavaX/lldb-for-aix that referenced this pull request Jun 12, 2025
…vm#142546)

This relands llvm#140700. I have updated the test case('targetattr.c') to
resolve the test failure.

Original PR resulted in test fail:
https://lab.llvm.org/buildbot/#/builders/11/builds/16173
https://lab.llvm.org/buildbot/#/builders/202/builds/1531

Original description:
Followup to llvm#140700.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:loongarch clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants