Author: Tom Honermann Date: 2022-04-05T15:34:35-04:00 New Revision: 7c53fc4fe1308f5b2a7527d14ea41fabb18109b8
URL: https://github.com/llvm/llvm-project/commit/7c53fc4fe1308f5b2a7527d14ea41fabb18109b8 DIFF: https://github.com/llvm/llvm-project/commit/7c53fc4fe1308f5b2a7527d14ea41fabb18109b8.diff LOG: [clang] Emit target_clones resolver functions as COMDAT. Previously, resolver functions synthesized for target_clones multiversion functions were not emitted as COMDAT. Now fixed. Added: Modified: clang/lib/CodeGen/CodeGenModule.cpp clang/test/CodeGen/attr-target-clones.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 4d24c33f51d02..ddcf564e688fe 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3454,6 +3454,10 @@ void CodeGenModule::EmitTargetClonesResolver(GlobalDecl GD) { 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(), diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c index 2ba3fb0158044..ecb36a41bab88 100644 --- a/clang/test/CodeGen/attr-target-clones.c +++ b/clang/test/CodeGen/attr-target-clones.c @@ -1,6 +1,18 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LINUX,CHECK // RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=WINDOWS,CHECK +// LINUX: $foo.resolver = comdat any +// LINUX: $foo_dupes.resolver = comdat any +// LINUX: $unused.resolver = comdat any +// LINUX: $foo_inline.resolver = comdat any +// LINUX: $foo_inline2.resolver = comdat any + +// WINDOWS: $foo = comdat any +// WINDOWS: $foo_dupes = comdat any +// WINDOWS: $unused = comdat any +// WINDOWS: $foo_inline = comdat any +// WINDOWS: $foo_inline2 = comdat any + // LINUX: @foo.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo.resolver // LINUX: @foo_dupes.ifunc = weak_odr ifunc void (), void ()* ()* @foo_dupes.resolver // LINUX: @unused.ifunc = weak_odr ifunc void (), void ()* ()* @unused.resolver @@ -10,26 +22,26 @@ 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() +// LINUX: define 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() +// WINDOWS: define 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() +// LINUX: define 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() +// WINDOWS: define dso_local void @foo_dupes() comdat // WINDOWS: musttail call void @foo_dupes.sse4.2.0 // WINDOWS: musttail call void @foo_dupes.default.1 @@ -52,13 +64,13 @@ int bar(void) { 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() +// LINUX: define 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() +// WINDOWS: define dso_local void @unused() comdat // WINDOWS: musttail call void @unused.arch_ivybridge.0 // WINDOWS: musttail call void @unused.default.1 @@ -79,12 +91,12 @@ int bar3(void) { } // Deferred emission of foo_inline, which got delayed because it is inline. -// LINUX: define i32 ()* @foo_inline.resolver() +// LINUX: define 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() +// WINDOWS: define 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 @@ -92,13 +104,13 @@ int bar3(void) { 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() +// LINUX: define 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() +// WINDOWS: define 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits