tahonermann updated this revision to Diff 420587.
tahonermann added a comment.

Squashed the addition of tests originally made in D122954 
<https://reviews.llvm.org/D122954> to this review.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122958/new/

https://reviews.llvm.org/D122958

Files:
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenModule.h
  clang/test/CodeGen/attr-target-clones.c
  clang/test/CodeGenCXX/attr-target-clones.cpp

Index: clang/test/CodeGenCXX/attr-target-clones.cpp
===================================================================
--- clang/test/CodeGenCXX/attr-target-clones.cpp
+++ clang/test/CodeGenCXX/attr-target-clones.cpp
@@ -12,29 +12,29 @@
 int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return 1; }
 // LINUX: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}})
 // LINUX: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}})
-// LINUX: define i32 (i32)* @_Z10overloadedi.resolver
+// LINUX: define weak_odr i32 (i32)* @_Z10overloadedi.resolver() comdat
 // LINUX: ret i32 (i32)* @_Z10overloadedi.sse4.2.0
 // LINUX: ret i32 (i32)* @_Z10overloadedi.default.1
 
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH@Z.sse4.2.0"(i32{{.+}})
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHH@Z.default.1"(i32{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHH@Z"(i32{{.+}})
+// WINDOWS: define weak_odr dso_local i32 @"?overloaded@@YAHH@Z"(i32{{.+}}) comdat
 // WINDOWS: call i32 @"?overloaded@@YAHH@Z.sse4.2.0"
 // WINDOWS: call i32 @"?overloaded@@YAHH@Z.default.1"
 
 int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const char *) { return 2; }
 // LINUX: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(i8*{{.+}})
 // LINUX: define {{.*}}i32 @_Z10overloadedPKc.default.1(i8*{{.+}})
-// LINUX: define i32 (i8*)* @_Z10overloadedPKc.resolver
+// LINUX: define weak_odr i32 (i8*)* @_Z10overloadedPKc.resolver() comdat
 // LINUX: ret i32 (i8*)* @_Z10overloadedPKc.arch_ivybridge.0
 // LINUX: ret i32 (i8*)* @_Z10overloadedPKc.default.1
 
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD@Z.arch_ivybridge.0"(i8*{{.+}})
 // WINDOWS: define dso_local noundef i32 @"?overloaded@@YAHPEBD@Z.default.1"(i8*{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHPEBD@Z"(i8*{{.+}})
+// WINDOWS: define weak_odr dso_local i32 @"?overloaded@@YAHPEBD@Z"(i8*{{.+}}) comdat
 // WINDOWS: call i32 @"?overloaded@@YAHPEBD@Z.arch_ivybridge.0"
 // WINDOWS: call i32 @"?overloaded@@YAHPEBD@Z.default.1"
-//
+
 void use_overloaded() {
   overloaded(1);
   // LINUX: call noundef i32 @_Z10overloadedi.ifunc
@@ -81,36 +81,40 @@
   // WINDOWS: call noundef i32 @"?foo@?$C@NM@@QEAAHXZ"(%struct.C
 }
 
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
-// LINUX: define i32 (%struct.C*)* @_ZN1CIssE3fooEv.resolver
+// LINUX: define weak_odr i32 (%struct.C*)* @_ZN1CIssE3fooEv.resolver() comdat
 // LINUX: ret i32 (%struct.C*)* @_ZN1CIssE3fooEv.sse4.2.0
 // LINUX: ret i32 (%struct.C*)* @_ZN1CIssE3fooEv.default.1
+
 // WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ"(%struct.C{{.+}})
 // WINDOWS: call i32 @"?foo@?$C@FF@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C@FF@@QEAAHXZ.default.1"
 
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C@HF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
-// LINUX: define i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.resolver
+// LINUX: define weak_odr i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.resolver() comdat
 // LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.sse4.2.0
 // LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.default.1
+
 // WINDOWS: define {{.*}}i32 @"?foo@?$C@HF@@QEAAHXZ"(%struct.C{{.+}})
 // WINDOWS: call i32 @"?foo@?$C@HF@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C@HF@@QEAAHXZ.default.1"
 
-// LINUX: define i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.resolver
+// LINUX: define weak_odr i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.resolver() comdat
 // LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.sse4.2.0
 // LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.default.1
+
 // WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ"(%struct.C{{.+}})
 // WINDOWS: call i32 @"?foo@?$C@NM@@QEAAHXZ.sse4.2.0"
 // WINDOWS: call i32 @"?foo@?$C@NM@@QEAAHXZ.default.1"
 
+// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(%struct.C{{.+}})
+// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(%struct.C{{.+}})
+// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(%struct.C{{.+}})
+// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(%struct.C{{.+}})
 // LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
 // LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ.default.1"(%struct.C{{.+}})
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(%struct.C{{.+}})
+
+// WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
 // WINDOWS: define {{.*}}i32 @"?foo@?$C@FF@@QEAAHXZ.default.1"(%struct.C{{.+}})
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(%struct.C{{.+}})
+// WINDOWS: define {{.*}}i32 @"?foo@?$C@HF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
 // WINDOWS: define {{.*}}i32 @"?foo@?$C@HF@@QEAAHXZ.default.1"(%struct.C{{.+}})
+// WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
+// WINDOWS: define {{.*}}i32 @"?foo@?$C@NM@@QEAAHXZ.default.1"(%struct.C{{.+}})
Index: clang/test/CodeGen/attr-target-clones.c
===================================================================
--- clang/test/CodeGen/attr-target-clones.c
+++ clang/test/CodeGen/attr-target-clones.c
@@ -18,30 +18,31 @@
 // LINUX: @unused.ifunc = weak_odr ifunc void (), void ()* ()* @unused.resolver
 // LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline.resolver
 // LINUX: @foo_inline2.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline2.resolver
+// LINUX: @foo_used_no_defn.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_used_no_defn.resolver
 
 int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
 // LINUX: define {{.*}}i32 @foo.sse4.2.0()
 // LINUX: define {{.*}}i32 @foo.default.1()
-// LINUX: define i32 ()* @foo.resolver() comdat
+// LINUX: define weak_odr i32 ()* @foo.resolver() comdat
 // LINUX: ret i32 ()* @foo.sse4.2.0
 // LINUX: ret i32 ()* @foo.default.1
 
 // WINDOWS: define dso_local i32 @foo.sse4.2.0()
 // WINDOWS: define dso_local i32 @foo.default.1()
-// WINDOWS: define dso_local i32 @foo() comdat
+// WINDOWS: define weak_odr dso_local i32 @foo() comdat
 // WINDOWS: musttail call i32 @foo.sse4.2.0
 // WINDOWS: musttail call i32 @foo.default.1
 
 __attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {}
 // LINUX: define {{.*}}void @foo_dupes.default.1()
 // LINUX: define {{.*}}void @foo_dupes.sse4.2.0()
-// LINUX: define void ()* @foo_dupes.resolver() comdat
+// LINUX: define weak_odr void ()* @foo_dupes.resolver() comdat
 // LINUX: ret void ()* @foo_dupes.sse4.2.0
 // LINUX: ret void ()* @foo_dupes.default.1
 
 // WINDOWS: define dso_local void @foo_dupes.default.1()
 // WINDOWS: define dso_local void @foo_dupes.sse4.2.0()
-// WINDOWS: define dso_local void @foo_dupes() comdat
+// WINDOWS: define weak_odr dso_local void @foo_dupes() comdat
 // WINDOWS: musttail call void @foo_dupes.sse4.2.0
 // WINDOWS: musttail call void @foo_dupes.default.1
 
@@ -64,13 +65,13 @@
 void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
 // LINUX: define {{.*}}void @unused.default.1()
 // LINUX: define {{.*}}void @unused.arch_ivybridge.0()
-// LINUX: define void ()* @unused.resolver() comdat
+// LINUX: define weak_odr void ()* @unused.resolver() comdat
 // LINUX: ret void ()* @unused.arch_ivybridge.0
 // LINUX: ret void ()* @unused.default.1
 
 // WINDOWS: define dso_local void @unused.default.1()
 // WINDOWS: define dso_local void @unused.arch_ivybridge.0()
-// WINDOWS: define dso_local void @unused() comdat
+// WINDOWS: define weak_odr dso_local void @unused() comdat
 // WINDOWS: musttail call void @unused.arch_ivybridge.0
 // WINDOWS: musttail call void @unused.default.1
 
@@ -90,46 +91,80 @@
   // WINDOWS: call i32 @foo_inline2()
 }
 
-// Deferred emission of foo_inline, which got delayed because it is inline.
-// LINUX: define i32 ()* @foo_inline.resolver() comdat
+// LINUX: define weak_odr i32 ()* @foo_inline.resolver() comdat
 // LINUX: ret i32 ()* @foo_inline.arch_sandybridge.0
 // LINUX: ret i32 ()* @foo_inline.sse4.2.1
 // LINUX: ret i32 ()* @foo_inline.default.2
 
-// WINDOWS: define dso_local i32 @foo_inline() comdat
+// WINDOWS: define weak_odr dso_local i32 @foo_inline() comdat
 // WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0
 // WINDOWS: musttail call i32 @foo_inline.sse4.2.1
 // WINDOWS: musttail call i32 @foo_inline.default.2
 
 inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
 foo_inline2(void){ return 0; }
-// LINUX: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB:[0-9]+]]
-// LINUX: define i32 ()* @foo_inline2.resolver() comdat
+// LINUX: define weak_odr i32 ()* @foo_inline2.resolver() comdat
 // LINUX: ret i32 ()* @foo_inline2.arch_sandybridge.0
 // LINUX: ret i32 ()* @foo_inline2.sse4.2.1
 // LINUX: ret i32 ()* @foo_inline2.default.2
 
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB:[0-9]+]]
-// WINDOWS: define dso_local i32 @foo_inline2() comdat
+// WINDOWS: define weak_odr dso_local i32 @foo_inline2() comdat
 // WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0
 // WINDOWS: musttail call i32 @foo_inline2.sse4.2.1
 // WINDOWS: musttail call i32 @foo_inline2.default.2
 
-// LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB]]
-// LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF]]
+
+int __attribute__((target_clones("default", "sse4.2")))
+foo_unused_no_defn(void);
+
+int __attribute__((target_clones("default", "sse4.2")))
+foo_used_no_defn(void);
+
+int test_foo_used_no_defn(void) {
+  // LINUX: define {{.*}}i32 @test_foo_used_no_defn()
+  // WINDOWS: define dso_local i32 @test_foo_used_no_defn()
+  return foo_used_no_defn();
+  // LINUX: call i32 @foo_used_no_defn.ifunc()
+  // WINDOWS: call i32 @foo_used_no_defn()
+}
+
+
+// LINUX: define weak_odr i32 ()* @foo_used_no_defn.resolver() comdat
+// LINUX: ret i32 ()* @foo_used_no_defn.sse4.2.0
+// LINUX: ret i32 ()* @foo_used_no_defn.default.1
+
+// WINDOWS: define weak_odr dso_local i32 @foo_used_no_defn() comdat
+// WINDOWS: musttail call i32 @foo_used_no_defn.sse4.2.0
+// WINDOWS: musttail call i32 @foo_used_no_defn.default.1
+
+
+// Deferred emission of inline definitions.
+
+// LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
+// LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF:[0-9]+]]
 // LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
 
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB]]
+// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB:[0-9]+]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
 
 
+// LINUX: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
 // LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
 // LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
 
+// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]]
 // WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]]
 
+
+// LINUX: declare i32 @foo_used_no_defn.default.1()
+// LINUX: declare i32 @foo_used_no_defn.sse4.2.0()
+
+// WINDOWS: declare dso_local i32 @foo_used_no_defn.default.1()
+// WINDOWS: declare dso_local i32 @foo_used_no_defn.sse4.2.0()
+
+
 // CHECK: attributes #[[SSE42]] =
 // CHECK-SAME: "target-features"="+crc32,+cx8,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
 // CHECK: attributes #[[DEF]] =
Index: clang/lib/CodeGen/CodeGenModule.h
===================================================================
--- clang/lib/CodeGen/CodeGenModule.h
+++ clang/lib/CodeGen/CodeGenModule.h
@@ -1505,7 +1505,6 @@
   void EmitAliasDefinition(GlobalDecl GD);
   void emitIFuncDefinition(GlobalDecl GD);
   void emitCPUDispatchDefinition(GlobalDecl GD);
-  void EmitTargetClonesResolver(GlobalDecl GD);
   void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
   void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -3320,13 +3320,13 @@
     auto *Spec = FD->getAttr<CPUSpecificAttr>();
     for (unsigned I = 0; I < Spec->cpus_size(); ++I)
       EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
-    // Requires multiple emits.
   } else if (FD->isTargetClonesMultiVersion()) {
     auto *Clone = FD->getAttr<TargetClonesAttr>();
     for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I)
       if (Clone->isFirstOfVersion(I))
         EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
-    EmitTargetClonesResolver(GD);
+    // Ensure that the resolver function is also emitted.
+    GetOrCreateMultiVersionResolver(GD);
   } else
     EmitGlobalFunctionDefinition(GD, GV);
 }
@@ -3408,57 +3408,6 @@
   return llvm::GlobalValue::WeakODRLinkage;
 }
 
-void CodeGenModule::EmitTargetClonesResolver(GlobalDecl GD) {
-  const auto *FD = cast<FunctionDecl>(GD.getDecl());
-  assert(FD && "Not a FunctionDecl?");
-  const auto *TC = FD->getAttr<TargetClonesAttr>();
-  assert(TC && "Not a target_clones Function?");
-
-  llvm::Function *ResolverFunc;
-  if (getTarget().supportsIFunc()) {
-    auto *IFunc = cast<llvm::GlobalIFunc>(GetOrCreateMultiVersionResolver(GD));
-    ResolverFunc = cast<llvm::Function>(IFunc->getResolver());
-  } else
-    ResolverFunc = cast<llvm::Function>(GetOrCreateMultiVersionResolver(GD));
-
-  SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
-  for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size();
-       ++VersionIndex) {
-    if (!TC->isFirstOfVersion(VersionIndex))
-      continue;
-    StringRef Version = TC->getFeatureStr(VersionIndex);
-    StringRef MangledName =
-        getMangledName(GD.getWithMultiVersionIndex(VersionIndex));
-    llvm::Constant *Func = GetGlobalValue(MangledName);
-    assert(Func &&
-           "Should have already been created before calling resolver emit");
-
-    StringRef Architecture;
-    llvm::SmallVector<StringRef, 1> Feature;
-
-    if (Version.startswith("arch="))
-      Architecture = Version.drop_front(sizeof("arch=") - 1);
-    else if (Version != "default")
-      Feature.push_back(Version);
-
-    Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
-  }
-
-  if (supportsCOMDAT())
-    ResolverFunc->setComdat(
-        getModule().getOrInsertComdat(ResolverFunc->getName()));
-
-  const TargetInfo &TI = getTarget();
-  std::stable_sort(
-      Options.begin(), Options.end(),
-      [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
-            const CodeGenFunction::MultiVersionResolverOption &RHS) {
-        return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
-      });
-  CodeGenFunction CGF(*this);
-  CGF.EmitMultiVersionResolver(ResolverFunc, Options);
-}
-
 void CodeGenModule::emitMultiVersionFunctions() {
   std::vector<GlobalDecl> MVFuncsToEmit;
   MultiVersionFuncs.swap(MVFuncsToEmit);
@@ -3495,26 +3444,58 @@
             Options.emplace_back(cast<llvm::Function>(Func),
                                  TA->getArchitecture(), Feats);
           });
+    } else if (FD->isTargetClonesMultiVersion()) {
+      const auto *TC = FD->getAttr<TargetClonesAttr>();
+      for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size();
+           ++VersionIndex) {
+        if (!TC->isFirstOfVersion(VersionIndex))
+          continue;
+        GlobalDecl CurGD{(FD->isDefined() ? FD->getDefinition() : FD),
+                         VersionIndex};
+        StringRef Version = TC->getFeatureStr(VersionIndex);
+        StringRef MangledName = getMangledName(CurGD);
+        llvm::Constant *Func = GetGlobalValue(MangledName);
+        if (!Func) {
+          if (FD->isDefined()) {
+            EmitGlobalFunctionDefinition(CurGD, nullptr);
+            Func = GetGlobalValue(MangledName);
+          } else {
+            const CGFunctionInfo &FI =
+                getTypes().arrangeGlobalDeclaration(CurGD);
+            llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
+            Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
+                                     /*DontDefer=*/false, ForDefinition);
+          }
+          assert(Func && "This should have just been created");
+        }
+
+        StringRef Architecture;
+        llvm::SmallVector<StringRef, 1> Feature;
+
+        if (Version.startswith("arch="))
+          Architecture = Version.drop_front(sizeof("arch=") - 1);
+        else if (Version != "default")
+          Feature.push_back(Version);
+
+        Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
+      }
     } else {
-      assert(0 && "Expected a target multiversion function");
+      assert(0 && "Expected a target or target_clones multiversion function");
       continue;
     }
 
-    llvm::Function *ResolverFunc;
-    const TargetInfo &TI = getTarget();
+    llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
+    if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant))
+      ResolverConstant = IFunc->getResolver();
+    llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
 
-    if (TI.supportsIFunc() || FD->isTargetMultiVersion()) {
-      ResolverFunc = cast<llvm::Function>(
-          GetGlobalValue((getMangledName(GD) + ".resolver").str()));
-      ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
-    } else {
-      ResolverFunc = cast<llvm::Function>(GetGlobalValue(getMangledName(GD)));
-    }
+    ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
 
     if (supportsCOMDAT())
       ResolverFunc->setComdat(
           getModule().getOrInsertComdat(ResolverFunc->getName()));
 
+    const TargetInfo &TI = getTarget();
     llvm::stable_sort(
         Options, [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
                        const CodeGenFunction::MultiVersionResolverOption &RHS) {
@@ -3676,35 +3657,17 @@
   else if (FD->isTargetMultiVersion())
     ResolverName += ".resolver";
 
-  // If this already exists, just return that one.
+  // If the resolver has already been created, just return it.
   if (llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName))
     return ResolverGV;
 
   const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
   llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
 
-  // Since this is the first time we've created this IFunc, make sure
-  // that we put this multiversioned function into the list to be
-  // replaced later if necessary (target multiversioning only).
-  if (FD->isTargetMultiVersion())
+  // The resolver needs to be created. For target and target_clones, defer
+  // creation until the end of the TU.
+  if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
     MultiVersionFuncs.push_back(GD);
-  else if (FD->isTargetClonesMultiVersion()) {
-    // In target_clones multiversioning, make sure we emit this if used.
-    auto DDI =
-        DeferredDecls.find(getMangledName(GD.getWithMultiVersionIndex(0)));
-    if (DDI != DeferredDecls.end()) {
-      addDeferredDeclToEmit(GD);
-      DeferredDecls.erase(DDI);
-    } else {
-      // Emit the symbol of the 1st variant, so that the deferred decls know we
-      // need it, otherwise the only global value will be the resolver/ifunc,
-      // which end up getting broken if we search for them with GetGlobalValue'.
-      GetOrCreateLLVMFunction(
-          getMangledName(GD.getWithMultiVersionIndex(0)), DeclTy, FD,
-          /*ForVTable=*/false, /*DontDefer=*/true,
-          /*IsThunk=*/false, llvm::AttributeList(), ForDefinition);
-    }
-  }
 
   // For cpu_specific, don't create an ifunc yet because we don't know if the
   // cpu_dispatch will be emitted in this translation unit.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to