Skip to content

Recommit "[RISCV][FMV] Support target_version" (#111096)" #111333

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 2 commits into from
Oct 8, 2024

Conversation

BeMg
Copy link
Contributor

@BeMg BeMg commented Oct 7, 2024

Fix the buildbot failure caused by heap use-after-free error.

Origin message:

This patch enable `target_version` attribute for RISC-V target.

The proposal of `target_version` syntax can be found at the
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/48 (which has
landed), as modified by the proposed
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/85 (which adds the
priority syntax).

`target_version` attribute will trigger the function multi-versioning
feature and act like `target_clones` attribute. See
https://github.com/llvm/llvm-project/pull/85786 for the implementation
of `target_clones`.

@BeMg BeMg requested review from preames, kito-cheng and topperc October 7, 2024 03:33
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. labels Oct 7, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2024

@llvm/pr-subscribers-backend-risc-v

@llvm/pr-subscribers-clang-codegen

Author: Piyou Chen (BeMg)

Changes

Fix the buildbot failure caused by heap use-after-free error.

Origin message:

This patch enable `target_version` attribute for RISC-V target.

The proposal of `target_version` syntax can be found at the
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/48 (which has
landed), as modified by the proposed
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/85 (which adds the
priority syntax).

`target_version` attribute will trigger the function multi-versioning
feature and act like `target_clones` attribute. See
https://github.com/llvm/llvm-project/pull/85786 for the implementation
of `target_clones`.

Patch is 57.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111333.diff

8 Files Affected:

  • (modified) clang/lib/AST/ASTContext.cpp (+11-3)
  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+6-1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+16-4)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+48)
  • (added) clang/test/CodeGen/attr-target-version-riscv-invalid.c (+13)
  • (added) clang/test/CodeGen/attr-target-version-riscv.c (+443)
  • (added) clang/test/CodeGenCXX/attr-target-version-riscv.cpp (+432)
  • (added) clang/test/SemaCXX/attr-target-version-riscv.cpp (+113)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a81429ad6a2380..034fbbe0bc7829 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -14325,9 +14325,17 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
       Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
     }
   } else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
-    llvm::SmallVector<StringRef, 8> Feats;
-    TV->getFeatures(Feats);
-    std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
+    std::vector<std::string> Features;
+    if (Target->getTriple().isRISCV()) {
+      ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TV->getName());
+      Features.insert(Features.begin(), ParsedAttr.Features.begin(),
+                      ParsedAttr.Features.end());
+    } else {
+      assert(Target->getTriple().isAArch64());
+      llvm::SmallVector<StringRef, 8> Feats;
+      TV->getFeatures(Feats);
+      Features = getFMVBackendFeaturesFor(Feats);
+    }
     Features.insert(Features.begin(),
                     Target->getTargetOpts().FeaturesAsWritten.begin(),
                     Target->getTargetOpts().FeaturesAsWritten.end());
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 25c1c496a4f27f..5ba098144a74e7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4287,8 +4287,13 @@ void CodeGenModule::emitMultiVersionFunctions() {
           } else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
             if (TVA->isDefaultVersion() && IsDefined)
               ShouldEmitResolver = true;
-            TVA->getFeatures(Feats);
             llvm::Function *Func = createFunction(CurFD);
+            if (getTarget().getTriple().isRISCV()) {
+              Feats.push_back(TVA->getName());
+            } else {
+              assert(getTarget().getTriple().isAArch64());
+              TVA->getFeatures(Feats);
+            }
             Options.emplace_back(Func, /*Architecture*/ "", Feats);
           } else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
             if (IsDefined)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2bf610746bc317..5c4e0562152c5b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10329,7 +10329,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   // Handle attributes.
   ProcessDeclAttributes(S, NewFD, D);
   const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
-  if (NewTVA && !NewTVA->isDefaultVersion() &&
+  if (Context.getTargetInfo().getTriple().isAArch64() && NewTVA &&
+      !NewTVA->isDefaultVersion() &&
       !Context.getTargetInfo().hasFeature("fmv")) {
     // Don't add to scope fmv functions declarations if fmv disabled
     AddToScope = false;
@@ -11038,7 +11039,16 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
 
   if (TVA) {
     llvm::SmallVector<StringRef, 8> Feats;
-    TVA->getFeatures(Feats);
+    ParsedTargetAttr ParseInfo;
+    if (S.getASTContext().getTargetInfo().getTriple().isRISCV()) {
+      ParseInfo =
+          S.getASTContext().getTargetInfo().parseTargetAttr(TVA->getName());
+      for (auto &Feat : ParseInfo.Features)
+        Feats.push_back(StringRef{Feat}.substr(1));
+    } else {
+      assert(S.getASTContext().getTargetInfo().getTriple().isAArch64());
+      TVA->getFeatures(Feats);
+    }
     for (const auto &Feat : Feats) {
       if (!TargetInfo.validateCpuSupports(Feat)) {
         S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
@@ -11324,7 +11334,8 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
 }
 
 static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {
-  if (!From->getASTContext().getTargetInfo().getTriple().isAArch64())
+  if (!From->getASTContext().getTargetInfo().getTriple().isAArch64() &&
+      !From->getASTContext().getTargetInfo().getTriple().isRISCV())
     return;
 
   MultiVersionKind MVKindFrom = From->getMultiVersionKind();
@@ -15511,7 +15522,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     FD->setInvalidDecl();
   }
   if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
-    if (!Context.getTargetInfo().hasFeature("fmv") &&
+    if (Context.getTargetInfo().getTriple().isAArch64() &&
+        !Context.getTargetInfo().hasFeature("fmv") &&
         !Attr->isDefaultVersion()) {
       // If function multi versioning disabled skip parsing function body
       // defined with non-default target_version attribute
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c9b9f3a0007daa..af983349a89b58 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3040,6 +3040,54 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
   enum SecondParam { None };
   enum ThirdParam { Target, TargetClones, TargetVersion };
   llvm::SmallVector<StringRef, 8> Features;
+  if (Context.getTargetInfo().getTriple().isRISCV()) {
+    llvm::SmallVector<StringRef, 8> AttrStrs;
+    AttrStr.split(AttrStrs, ';');
+
+    bool HasArch = false;
+    bool HasPriority = false;
+    bool HasDefault = false;
+    bool DuplicateAttr = false;
+    for (auto &AttrStr : AttrStrs) {
+      // Only support arch=+ext,... syntax.
+      if (AttrStr.starts_with("arch=+")) {
+        if (HasArch)
+          DuplicateAttr = true;
+        HasArch = true;
+        ParsedTargetAttr TargetAttr =
+            Context.getTargetInfo().parseTargetAttr(AttrStr);
+
+        if (TargetAttr.Features.empty() ||
+            llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) {
+              return !RISCV().isValidFMVExtension(Ext);
+            }))
+          return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+                 << Unsupported << None << AttrStr << TargetVersion;
+      } else if (AttrStr.starts_with("default")) {
+        if (HasDefault)
+          DuplicateAttr = true;
+        HasDefault = true;
+      } else if (AttrStr.consume_front("priority=")) {
+        if (HasPriority)
+          DuplicateAttr = true;
+        HasPriority = true;
+        int Digit;
+        if (AttrStr.getAsInteger(0, Digit))
+          return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+                 << Unsupported << None << AttrStr << TargetVersion;
+      } else {
+        return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+               << Unsupported << None << AttrStr << TargetVersion;
+      }
+    }
+
+    if (((HasPriority || HasArch) && HasDefault) || DuplicateAttr ||
+        (HasPriority && !HasArch))
+      return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+             << Unsupported << None << AttrStr << TargetVersion;
+
+    return false;
+  }
   AttrStr.split(Features, "+");
   for (auto &CurFeature : Features) {
     CurFeature = CurFeature.trim();
diff --git a/clang/test/CodeGen/attr-target-version-riscv-invalid.c b/clang/test/CodeGen/attr-target-version-riscv-invalid.c
new file mode 100644
index 00000000000000..0948b3bfd9ef32
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-riscv-invalid.c
@@ -0,0 +1,13 @@
+// RUN: not %clang_cc1 -triple riscv64 -target-feature +i -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORT-OS
+
+// CHECK-UNSUPPORT-OS: error: function multiversioning is currently only supported on Linux
+__attribute__((target_version("default"))) int foo(void) {
+  return 2;
+}
+
+__attribute__((target_version("arch=+c"))) int foo(void) {
+  return 2;
+}
+
+
+int bar() { return foo(); }
diff --git a/clang/test/CodeGen/attr-target-version-riscv.c b/clang/test/CodeGen/attr-target-version-riscv.c
new file mode 100644
index 00000000000000..7d0e61e61542f2
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-riscv.c
@@ -0,0 +1,443 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 4
+// RUN: %clang_cc1 -triple riscv64-linux-gnu -target-feature +i -emit-llvm -o - %s | FileCheck %s
+
+__attribute__((target_version("arch=+v"))) int foo1(void) { return 1; }
+__attribute__((target_version("default"))) int foo1(void) { return 1; }
+
+__attribute__((target_version("arch=+zbb"))) int foo2(void) { return 1; }
+__attribute__((target_version("arch=+m"))) int foo2(void) { return 1; }
+__attribute__((target_version("default"))) int foo2(void) { return 1; }
+
+__attribute__((target_version("arch=+zbb,+c"))) int foo3(void) { return 1; }
+__attribute__((target_version("arch=+m"))) int foo3(void) { return 1; }
+__attribute__((target_version("default"))) int foo3(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo4(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo4(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba"))) int foo4(void) { return 1; }
+__attribute__((target_version("default"))) int foo4(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo5(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba"))) int foo5(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo5(void) { return 1; }
+__attribute__((target_version("default"))) int foo5(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo6(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo6(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=10"))) int foo6(void) { return 1; }
+__attribute__((target_version("default"))) int foo6(void) { return 1; }
+
+__attribute__((target_version("priority=8;arch=+zba"))) int foo7(void) { return 1; }
+__attribute__((target_version("arch=+zbb;priority=9"))) int foo7(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=10"))) int foo7(void) { return 1; }
+__attribute__((target_version("default"))) int foo7(void) { return 1; }
+
+__attribute__((target_version("priority=-1;arch=+zba"))) int foo8(void) { return 1; }
+__attribute__((target_version("arch=+zbb;priority=-2"))) int foo8(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=3"))) int foo8(void) { return 1; }
+__attribute__((target_version("default"))) int foo8(void) { return 1; }
+
+int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() + foo8(); }
+//.
+// CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] }
+// CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver
+// CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver
+// CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver
+// CHECK: @foo4 = weak_odr ifunc i32 (), ptr @foo4.resolver
+// CHECK: @foo5 = weak_odr ifunc i32 (), ptr @foo5.resolver
+// CHECK: @foo6 = weak_odr ifunc i32 (), ptr @foo6.resolver
+// CHECK: @foo7 = weak_odr ifunc i32 (), ptr @foo7.resolver
+// CHECK: @foo8 = weak_odr ifunc i32 (), ptr @foo8.resolver
+//.
+// CHECK-LABEL: define dso_local signext i32 @foo1._v(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo1.default(
+// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2._zbb(
+// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2._m(
+// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3._c_zbb(
+// CHECK-SAME: ) #[[ATTR4:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3._m(
+// CHECK-SAME: ) #[[ATTR3]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zba(
+// CHECK-SAME: ) #[[ATTR5:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @bar(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CALL:%.*]] = call signext i32 @foo1()
+// CHECK-NEXT:    [[CALL1:%.*]] = call signext i32 @foo2()
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]]
+// CHECK-NEXT:    [[CALL2:%.*]] = call signext i32 @foo3()
+// CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]]
+// CHECK-NEXT:    [[CALL4:%.*]] = call signext i32 @foo4()
+// CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]]
+// CHECK-NEXT:    [[CALL6:%.*]] = call signext i32 @foo5()
+// CHECK-NEXT:    [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]]
+// CHECK-NEXT:    [[CALL8:%.*]] = call signext i32 @foo6()
+// CHECK-NEXT:    [[ADD9:%.*]] = add nsw i32 [[ADD7]], [[CALL8]]
+// CHECK-NEXT:    [[CALL10:%.*]] = call signext i32 @foo7()
+// CHECK-NEXT:    [[ADD11:%.*]] = add nsw i32 [[ADD9]], [[CALL10]]
+// CHECK-NEXT:    [[CALL12:%.*]] = call signext i32 @foo8()
+// CHECK-NEXT:    [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]]
+// CHECK-NEXT:    ret i32 [[ADD13]]
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo1.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 2097152
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2097152
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo1._v
+// CHECK:       resolver_else:
+// CHECK-NEXT:    ret ptr @foo1.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo2.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 268435456
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo2._zbb
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4096
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]]
+// CHECK:       resolver_return1:
+// CHECK-NEXT:    ret ptr @foo2._m
+// CHECK:       resolver_else2:
+// CHECK-NEXT:    ret ptr @foo2.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo3.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 268435460
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435460
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo3._c_zbb
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4096
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]]
+// CHECK:       resolver_return1:
+// CHECK-NEXT:    ret ptr @foo3._m
+// CHECK:       resolver_else2:
+// CHECK-NEXT:    ret ptr @foo3.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo4.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 134217728
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 134217728
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo4._zba
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 268435456
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RES...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2024

@llvm/pr-subscribers-clang

Author: Piyou Chen (BeMg)

Changes

Fix the buildbot failure caused by heap use-after-free error.

Origin message:

This patch enable `target_version` attribute for RISC-V target.

The proposal of `target_version` syntax can be found at the
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/48 (which has
landed), as modified by the proposed
https://github.com/riscv-non-isa/riscv-c-api-doc/pull/85 (which adds the
priority syntax).

`target_version` attribute will trigger the function multi-versioning
feature and act like `target_clones` attribute. See
https://github.com/llvm/llvm-project/pull/85786 for the implementation
of `target_clones`.

Patch is 57.55 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/111333.diff

8 Files Affected:

  • (modified) clang/lib/AST/ASTContext.cpp (+11-3)
  • (modified) clang/lib/CodeGen/CodeGenModule.cpp (+6-1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+16-4)
  • (modified) clang/lib/Sema/SemaDeclAttr.cpp (+48)
  • (added) clang/test/CodeGen/attr-target-version-riscv-invalid.c (+13)
  • (added) clang/test/CodeGen/attr-target-version-riscv.c (+443)
  • (added) clang/test/CodeGenCXX/attr-target-version-riscv.cpp (+432)
  • (added) clang/test/SemaCXX/attr-target-version-riscv.cpp (+113)
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a81429ad6a2380..034fbbe0bc7829 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -14325,9 +14325,17 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
       Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
     }
   } else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
-    llvm::SmallVector<StringRef, 8> Feats;
-    TV->getFeatures(Feats);
-    std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
+    std::vector<std::string> Features;
+    if (Target->getTriple().isRISCV()) {
+      ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TV->getName());
+      Features.insert(Features.begin(), ParsedAttr.Features.begin(),
+                      ParsedAttr.Features.end());
+    } else {
+      assert(Target->getTriple().isAArch64());
+      llvm::SmallVector<StringRef, 8> Feats;
+      TV->getFeatures(Feats);
+      Features = getFMVBackendFeaturesFor(Feats);
+    }
     Features.insert(Features.begin(),
                     Target->getTargetOpts().FeaturesAsWritten.begin(),
                     Target->getTargetOpts().FeaturesAsWritten.end());
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 25c1c496a4f27f..5ba098144a74e7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4287,8 +4287,13 @@ void CodeGenModule::emitMultiVersionFunctions() {
           } else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
             if (TVA->isDefaultVersion() && IsDefined)
               ShouldEmitResolver = true;
-            TVA->getFeatures(Feats);
             llvm::Function *Func = createFunction(CurFD);
+            if (getTarget().getTriple().isRISCV()) {
+              Feats.push_back(TVA->getName());
+            } else {
+              assert(getTarget().getTriple().isAArch64());
+              TVA->getFeatures(Feats);
+            }
             Options.emplace_back(Func, /*Architecture*/ "", Feats);
           } else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
             if (IsDefined)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2bf610746bc317..5c4e0562152c5b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10329,7 +10329,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   // Handle attributes.
   ProcessDeclAttributes(S, NewFD, D);
   const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>();
-  if (NewTVA && !NewTVA->isDefaultVersion() &&
+  if (Context.getTargetInfo().getTriple().isAArch64() && NewTVA &&
+      !NewTVA->isDefaultVersion() &&
       !Context.getTargetInfo().hasFeature("fmv")) {
     // Don't add to scope fmv functions declarations if fmv disabled
     AddToScope = false;
@@ -11038,7 +11039,16 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
 
   if (TVA) {
     llvm::SmallVector<StringRef, 8> Feats;
-    TVA->getFeatures(Feats);
+    ParsedTargetAttr ParseInfo;
+    if (S.getASTContext().getTargetInfo().getTriple().isRISCV()) {
+      ParseInfo =
+          S.getASTContext().getTargetInfo().parseTargetAttr(TVA->getName());
+      for (auto &Feat : ParseInfo.Features)
+        Feats.push_back(StringRef{Feat}.substr(1));
+    } else {
+      assert(S.getASTContext().getTargetInfo().getTriple().isAArch64());
+      TVA->getFeatures(Feats);
+    }
     for (const auto &Feat : Feats) {
       if (!TargetInfo.validateCpuSupports(Feat)) {
         S.Diag(FD->getLocation(), diag::err_bad_multiversion_option)
@@ -11324,7 +11334,8 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) {
 }
 
 static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) {
-  if (!From->getASTContext().getTargetInfo().getTriple().isAArch64())
+  if (!From->getASTContext().getTargetInfo().getTriple().isAArch64() &&
+      !From->getASTContext().getTargetInfo().getTriple().isRISCV())
     return;
 
   MultiVersionKind MVKindFrom = From->getMultiVersionKind();
@@ -15511,7 +15522,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
     FD->setInvalidDecl();
   }
   if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) {
-    if (!Context.getTargetInfo().hasFeature("fmv") &&
+    if (Context.getTargetInfo().getTriple().isAArch64() &&
+        !Context.getTargetInfo().hasFeature("fmv") &&
         !Attr->isDefaultVersion()) {
       // If function multi versioning disabled skip parsing function body
       // defined with non-default target_version attribute
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index c9b9f3a0007daa..af983349a89b58 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3040,6 +3040,54 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D,
   enum SecondParam { None };
   enum ThirdParam { Target, TargetClones, TargetVersion };
   llvm::SmallVector<StringRef, 8> Features;
+  if (Context.getTargetInfo().getTriple().isRISCV()) {
+    llvm::SmallVector<StringRef, 8> AttrStrs;
+    AttrStr.split(AttrStrs, ';');
+
+    bool HasArch = false;
+    bool HasPriority = false;
+    bool HasDefault = false;
+    bool DuplicateAttr = false;
+    for (auto &AttrStr : AttrStrs) {
+      // Only support arch=+ext,... syntax.
+      if (AttrStr.starts_with("arch=+")) {
+        if (HasArch)
+          DuplicateAttr = true;
+        HasArch = true;
+        ParsedTargetAttr TargetAttr =
+            Context.getTargetInfo().parseTargetAttr(AttrStr);
+
+        if (TargetAttr.Features.empty() ||
+            llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) {
+              return !RISCV().isValidFMVExtension(Ext);
+            }))
+          return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+                 << Unsupported << None << AttrStr << TargetVersion;
+      } else if (AttrStr.starts_with("default")) {
+        if (HasDefault)
+          DuplicateAttr = true;
+        HasDefault = true;
+      } else if (AttrStr.consume_front("priority=")) {
+        if (HasPriority)
+          DuplicateAttr = true;
+        HasPriority = true;
+        int Digit;
+        if (AttrStr.getAsInteger(0, Digit))
+          return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+                 << Unsupported << None << AttrStr << TargetVersion;
+      } else {
+        return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+               << Unsupported << None << AttrStr << TargetVersion;
+      }
+    }
+
+    if (((HasPriority || HasArch) && HasDefault) || DuplicateAttr ||
+        (HasPriority && !HasArch))
+      return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
+             << Unsupported << None << AttrStr << TargetVersion;
+
+    return false;
+  }
   AttrStr.split(Features, "+");
   for (auto &CurFeature : Features) {
     CurFeature = CurFeature.trim();
diff --git a/clang/test/CodeGen/attr-target-version-riscv-invalid.c b/clang/test/CodeGen/attr-target-version-riscv-invalid.c
new file mode 100644
index 00000000000000..0948b3bfd9ef32
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-riscv-invalid.c
@@ -0,0 +1,13 @@
+// RUN: not %clang_cc1 -triple riscv64 -target-feature +i -emit-llvm -o - %s 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORT-OS
+
+// CHECK-UNSUPPORT-OS: error: function multiversioning is currently only supported on Linux
+__attribute__((target_version("default"))) int foo(void) {
+  return 2;
+}
+
+__attribute__((target_version("arch=+c"))) int foo(void) {
+  return 2;
+}
+
+
+int bar() { return foo(); }
diff --git a/clang/test/CodeGen/attr-target-version-riscv.c b/clang/test/CodeGen/attr-target-version-riscv.c
new file mode 100644
index 00000000000000..7d0e61e61542f2
--- /dev/null
+++ b/clang/test/CodeGen/attr-target-version-riscv.c
@@ -0,0 +1,443 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-globals all --include-generated-funcs --version 4
+// RUN: %clang_cc1 -triple riscv64-linux-gnu -target-feature +i -emit-llvm -o - %s | FileCheck %s
+
+__attribute__((target_version("arch=+v"))) int foo1(void) { return 1; }
+__attribute__((target_version("default"))) int foo1(void) { return 1; }
+
+__attribute__((target_version("arch=+zbb"))) int foo2(void) { return 1; }
+__attribute__((target_version("arch=+m"))) int foo2(void) { return 1; }
+__attribute__((target_version("default"))) int foo2(void) { return 1; }
+
+__attribute__((target_version("arch=+zbb,+c"))) int foo3(void) { return 1; }
+__attribute__((target_version("arch=+m"))) int foo3(void) { return 1; }
+__attribute__((target_version("default"))) int foo3(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo4(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo4(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba"))) int foo4(void) { return 1; }
+__attribute__((target_version("default"))) int foo4(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo5(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba"))) int foo5(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo5(void) { return 1; }
+__attribute__((target_version("default"))) int foo5(void) { return 1; }
+
+__attribute__((target_version("arch=+zba"))) int foo6(void) { return 1; }
+__attribute__((target_version("arch=+zbb"))) int foo6(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=10"))) int foo6(void) { return 1; }
+__attribute__((target_version("default"))) int foo6(void) { return 1; }
+
+__attribute__((target_version("priority=8;arch=+zba"))) int foo7(void) { return 1; }
+__attribute__((target_version("arch=+zbb;priority=9"))) int foo7(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=10"))) int foo7(void) { return 1; }
+__attribute__((target_version("default"))) int foo7(void) { return 1; }
+
+__attribute__((target_version("priority=-1;arch=+zba"))) int foo8(void) { return 1; }
+__attribute__((target_version("arch=+zbb;priority=-2"))) int foo8(void) { return 1; }
+__attribute__((target_version("arch=+zbb,+zba;priority=3"))) int foo8(void) { return 1; }
+__attribute__((target_version("default"))) int foo8(void) { return 1; }
+
+int bar() { return foo1() + foo2() + foo3() + foo4() + foo5() + foo6() + foo7() + foo8(); }
+//.
+// CHECK: @__riscv_feature_bits = external dso_local global { i32, [2 x i64] }
+// CHECK: @foo1 = weak_odr ifunc i32 (), ptr @foo1.resolver
+// CHECK: @foo2 = weak_odr ifunc i32 (), ptr @foo2.resolver
+// CHECK: @foo3 = weak_odr ifunc i32 (), ptr @foo3.resolver
+// CHECK: @foo4 = weak_odr ifunc i32 (), ptr @foo4.resolver
+// CHECK: @foo5 = weak_odr ifunc i32 (), ptr @foo5.resolver
+// CHECK: @foo6 = weak_odr ifunc i32 (), ptr @foo6.resolver
+// CHECK: @foo7 = weak_odr ifunc i32 (), ptr @foo7.resolver
+// CHECK: @foo8 = weak_odr ifunc i32 (), ptr @foo8.resolver
+//.
+// CHECK-LABEL: define dso_local signext i32 @foo1._v(
+// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo1.default(
+// CHECK-SAME: ) #[[ATTR1:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2._zbb(
+// CHECK-SAME: ) #[[ATTR2:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2._m(
+// CHECK-SAME: ) #[[ATTR3:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo2.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3._c_zbb(
+// CHECK-SAME: ) #[[ATTR4:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3._m(
+// CHECK-SAME: ) #[[ATTR3]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo3.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zba(
+// CHECK-SAME: ) #[[ATTR5:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6:[0-9]+]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo4.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo5.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo6.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo7.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zba(
+// CHECK-SAME: ) #[[ATTR5]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zbb(
+// CHECK-SAME: ) #[[ATTR2]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8._zba_zbb(
+// CHECK-SAME: ) #[[ATTR6]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @foo8.default(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    ret i32 1
+//
+//
+// CHECK-LABEL: define dso_local signext i32 @bar(
+// CHECK-SAME: ) #[[ATTR1]] {
+// CHECK-NEXT:  entry:
+// CHECK-NEXT:    [[CALL:%.*]] = call signext i32 @foo1()
+// CHECK-NEXT:    [[CALL1:%.*]] = call signext i32 @foo2()
+// CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]]
+// CHECK-NEXT:    [[CALL2:%.*]] = call signext i32 @foo3()
+// CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]]
+// CHECK-NEXT:    [[CALL4:%.*]] = call signext i32 @foo4()
+// CHECK-NEXT:    [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]]
+// CHECK-NEXT:    [[CALL6:%.*]] = call signext i32 @foo5()
+// CHECK-NEXT:    [[ADD7:%.*]] = add nsw i32 [[ADD5]], [[CALL6]]
+// CHECK-NEXT:    [[CALL8:%.*]] = call signext i32 @foo6()
+// CHECK-NEXT:    [[ADD9:%.*]] = add nsw i32 [[ADD7]], [[CALL8]]
+// CHECK-NEXT:    [[CALL10:%.*]] = call signext i32 @foo7()
+// CHECK-NEXT:    [[ADD11:%.*]] = add nsw i32 [[ADD9]], [[CALL10]]
+// CHECK-NEXT:    [[CALL12:%.*]] = call signext i32 @foo8()
+// CHECK-NEXT:    [[ADD13:%.*]] = add nsw i32 [[ADD11]], [[CALL12]]
+// CHECK-NEXT:    ret i32 [[ADD13]]
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo1.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 2097152
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2097152
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo1._v
+// CHECK:       resolver_else:
+// CHECK-NEXT:    ret ptr @foo1.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo2.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 268435456
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435456
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo2._zbb
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4096
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]]
+// CHECK:       resolver_return1:
+// CHECK-NEXT:    ret ptr @foo2._m
+// CHECK:       resolver_else2:
+// CHECK-NEXT:    ret ptr @foo2.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo3.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 268435460
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 268435460
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo3._c_zbb
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 4096
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4096
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]]
+// CHECK:       resolver_return1:
+// CHECK-NEXT:    ret ptr @foo3._m
+// CHECK:       resolver_else2:
+// CHECK-NEXT:    ret ptr @foo3.default
+//
+//
+// CHECK-LABEL: define weak_odr ptr @foo4.resolver() comdat {
+// CHECK-NEXT:  resolver_entry:
+// CHECK-NEXT:    call void @__init_riscv_feature_bits(ptr null)
+// CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 134217728
+// CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 134217728
+// CHECK-NEXT:    br i1 [[TMP2]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]]
+// CHECK:       resolver_return:
+// CHECK-NEXT:    ret ptr @foo4._zba
+// CHECK:       resolver_else:
+// CHECK-NEXT:    [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8
+// CHECK-NEXT:    [[TMP4:%.*]] = and i64 [[TMP3]], 268435456
+// CHECK-NEXT:    [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 268435456
+// CHECK-NEXT:    br i1 [[TMP5]], label [[RES...
[truncated]

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@BeMg BeMg merged commit f658c1b into llvm:main Oct 8, 2024
13 checks passed
@shafik
Copy link
Collaborator

shafik commented Nov 7, 2024

It looks like this change caused a regression: #115000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. 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.

4 participants