llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Akash Manna (akash-manna-sky) <details> <summary>Changes</summary> Fixes #<!-- -->149372 A `target_clones` definition, a bare redeclaration and then one repeating the attribute asserted with `Default or Generic case must be last` in the `x86` resolver. Sema did not link the bare redeclaration to the definition, so CodeGen saw two functions named `f` and collected every version twice. #<!-- -->169259 fixed the `Sema` side, so the attribute is inherited and each version is collected once. This adds the shape from the report. Assisted-by : LLM tools. --- Full diff: https://github.com/llvm/llvm-project/pull/237830.diff 4 Files Affected: - (modified) clang/test/CodeGen/attr-target-clones.c (+25) - (added) clang/test/CodeGenCXX/attr-target-clones-redecl.cpp (+90) - (modified) clang/test/Sema/attr-target-clones.c (+18) - (modified) clang/test/SemaCXX/attr-target-clones.cpp (+31) ``````````diff diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c index ccf9b5615bde46..4c050870d9811f 100644 --- a/clang/test/CodeGen/attr-target-clones.c +++ b/clang/test/CodeGen/attr-target-clones.c @@ -155,6 +155,31 @@ int test_inherited(void) { // WINDOWS: call i32 @inherited() } +// GH149372 +int __attribute__((target_clones("default,avx"))) redecl(int x) { return x; } +int redecl(int); +int __attribute__((target_clones("default,avx"))) redecl(int); +// LINUX: define {{.*}}i32 @redecl.default.1( +// LINUX: define {{.*}}i32 @redecl.avx.0( +// LINUX: define weak_odr ptr @redecl.resolver() #[[ATTR_RESOLVER]] comdat +// LINUX: ret ptr @redecl.avx.0 +// LINUX-NOT: ret ptr @redecl.avx.0 +// LINUX: ret ptr @redecl.default.1 + +// DARWIN: define {{.*}}i32 @redecl.default.1( +// DARWIN: define {{.*}}i32 @redecl.avx.0( +// DARWIN: define weak_odr ptr @redecl.resolver() #[[ATTR_RESOLVER]] { +// DARWIN: ret ptr @redecl.avx.0 +// DARWIN-NOT: ret ptr @redecl.avx.0 +// DARWIN: ret ptr @redecl.default.1 + +// WINDOWS: define dso_local i32 @redecl.default.1( +// WINDOWS: define dso_local i32 @redecl.avx.0( +// WINDOWS: define weak_odr dso_local i32 @redecl(i32{{.*}}) #[[ATTR_RESOLVER]] comdat +// WINDOWS: musttail call i32 @redecl.avx.0 +// WINDOWS-NOT: musttail call i32 @redecl.avx.0 +// WINDOWS: musttail call i32 @redecl.default.1 + inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2"))) foo_inline(void) { return 0; } inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2"))) diff --git a/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp b/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp new file mode 100644 index 00000000000000..c72beb1e11ccb9 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-target-clones-redecl.cpp @@ -0,0 +1,90 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -O2 -emit-llvm-only %s + +// GH149372: redeclarations must not duplicate the versions in the resolver. + +// CHECK: @_Z1ci.ifunc = weak_odr alias i32 (i32), ptr @_Z1ci +// CHECK: @_Z1fi.ifunc = weak_odr alias i32 (i32), ptr @_Z1fi +// CHECK: @_ZN2ns1gEi.ifunc = weak_odr alias i32 (i32), ptr @_ZN2ns1gEi +// CHECK: @h.ifunc = weak_odr alias i32 (i32), ptr @h +// CHECK: @_ZL1si.ifunc = internal alias i32 (i32), ptr @_ZL1si +// CHECK: @_Z1di.ifunc = weak_odr alias i32 (i32), ptr @_Z1di +// CHECK: @_Z1ci = weak_odr ifunc i32 (i32), ptr @_Z1ci.resolver +// CHECK: @_Z1fi = weak_odr ifunc i32 (i32), ptr @_Z1fi.resolver +// CHECK: @_ZN2ns1gEi = weak_odr ifunc i32 (i32), ptr @_ZN2ns1gEi.resolver +// CHECK: @h = weak_odr ifunc i32 (i32), ptr @h.resolver +// CHECK: @_ZL1si = internal ifunc i32 (i32), ptr @_ZL1si.resolver +// CHECK: @_Z1di = weak_odr ifunc i32 (i32), ptr @_Z1di.resolver + +int __attribute__((target_clones("default,avx"))) c(int x) { return x; } +// CHECK: define {{.*}}i32 @_Z1ci.default.1( +// CHECK: define {{.*}}i32 @_Z1ci.avx.0( +// CHECK: define weak_odr ptr @_Z1ci.resolver() #[[ATTR_RESOLVER:[0-9]+]] comdat +// CHECK: ret ptr @_Z1ci.avx.0 +// CHECK: ret ptr @_Z1ci.default.1 + +enum { VALUE = 3 }; + +extern int glob_x; + +int __attribute__((target_clones("default,avx"))) f(int x) { return x + glob_x + VALUE; } + +int f(int); +int __attribute__((target_clones("default,avx"))) f(int); +// CHECK: define {{.*}}i32 @_Z1fi.default.1( +// CHECK: define {{.*}}i32 @_Z1fi.avx.0( +// CHECK: define weak_odr ptr @_Z1fi.resolver() #[[ATTR_RESOLVER]] comdat +// CHECK: ret ptr @_Z1fi.avx.0 +// CHECK-NOT: ret ptr @_Z1fi.avx.0 +// CHECK: ret ptr @_Z1fi.default.1 + +namespace ns { +int __attribute__((target_clones("default,avx"))) g(int x) { return x; } +int g(int); +int __attribute__((target_clones("default,avx"))) g(int); +} +// CHECK: define {{.*}}i32 @_ZN2ns1gEi.default.1( +// CHECK: define {{.*}}i32 @_ZN2ns1gEi.avx.0( +// CHECK: define weak_odr ptr @_ZN2ns1gEi.resolver() #[[ATTR_RESOLVER]] comdat +// CHECK: ret ptr @_ZN2ns1gEi.avx.0 +// CHECK-NOT: ret ptr @_ZN2ns1gEi.avx.0 +// CHECK: ret ptr @_ZN2ns1gEi.default.1 + +extern "C" int __attribute__((target_clones("default,avx"))) h(int x) { return x; } +extern "C" int h(int); +extern "C" int __attribute__((target_clones("default,avx"))) h(int); +// CHECK: define {{.*}}i32 @h.default.1( +// CHECK: define {{.*}}i32 @h.avx.0( +// CHECK: define weak_odr ptr @h.resolver() #[[ATTR_RESOLVER]] comdat +// CHECK: ret ptr @h.avx.0 +// CHECK-NOT: ret ptr @h.avx.0 +// CHECK: ret ptr @h.default.1 + +static int __attribute__((target_clones("default,avx"))) s(int x) { return x; } +static int s(int); +static int __attribute__((target_clones("default,avx"))) s(int); +int use_s(int x) { return s(x); } +// CHECK: define {{.*}}i32 @_Z5use_si( +// CHECK: call noundef i32 @_ZL1si( +// CHECK: define internal ptr @_ZL1si.resolver() #[[ATTR_RESOLVER]] { +// CHECK: ret ptr @_ZL1si.avx.0 +// CHECK-NOT: ret ptr @_ZL1si.avx.0 +// CHECK: ret ptr @_ZL1si.default.1 + +int __attribute__((target_clones("default,avx"))) d(int); +int d(int); +int __attribute__((target_clones("default,avx"))) d(int); +int d(int x) { return x; } +int d(int); +// CHECK: define {{.*}}i32 @_Z1di.default.1( +// CHECK: define {{.*}}i32 @_Z1di.avx.0( +// CHECK: define weak_odr ptr @_Z1di.resolver() #[[ATTR_RESOLVER]] comdat +// CHECK: ret ptr @_Z1di.avx.0 +// CHECK-NOT: ret ptr @_Z1di.avx.0 +// CHECK: ret ptr @_Z1di.default.1 + +// The internal function's versions are emitted at the end of the module. +// CHECK: define internal {{.*}}i32 @_ZL1si.default.1( +// CHECK: define internal {{.*}}i32 @_ZL1si.avx.0( + +// CHECK: attributes #[[ATTR_RESOLVER]] = { disable_sanitizer_instrumentation } diff --git a/clang/test/Sema/attr-target-clones.c b/clang/test/Sema/attr-target-clones.c index 7ff8a02bf53321..918f1dc1340ad4 100644 --- a/clang/test/Sema/attr-target-clones.c +++ b/clang/test/Sema/attr-target-clones.c @@ -39,6 +39,24 @@ int __attribute__((target_clones("sse4.2", "default"))) redecl7(void); // expected-note@-2 {{previous declaration is here}} int __attribute__((target("sse4.2"))) redecl7(void) { return 1; } +// GH149372 +int __attribute__((target_clones("sse4.2", "default"))) redecl8(void) { return 1; } +int redecl8(void); +int __attribute__((target_clones("sse4.2", "default"))) redecl8(void); + +int __attribute__((target_clones("sse4.2", "default"))) redecl9(void); +int redecl9(void); +int __attribute__((target_clones("sse4.2", "default"))) redecl9(void); +int redecl9(void); +int __attribute__((target_clones("sse4.2", "default"))) redecl9(void) { return 1; } +int redecl9(void); + +int __attribute__((target_clones("sse4.2", "default"))) redecl10(void) { return 1; } +int redecl10(void); +// expected-error@+2 {{'target_clones' attribute does not match previous declaration}} +// expected-note@-2 {{previous declaration is here}} +int __attribute__((target_clones("arch=atom", "default"))) redecl10(void); + int __attribute__((target("sse4.2"))) redef2(void) { return 1; } // expected-error@+2 {{multiversioning attributes cannot be combined}} // expected-note@-2 {{previous declaration is here}} diff --git a/clang/test/SemaCXX/attr-target-clones.cpp b/clang/test/SemaCXX/attr-target-clones.cpp index 68c9a4ff48ed9e..8952beeb47127a 100644 --- a/clang/test/SemaCXX/attr-target-clones.cpp +++ b/clang/test/SemaCXX/attr-target-clones.cpp @@ -9,3 +9,34 @@ void uses_lambda() { auto x = []()__attribute__((target_clones("sse4.2", "arch=ivybridge", "default"))) {}; x(); } + +// GH149372 +int __attribute__((target_clones("default,avx"))) redecl(int x) { return x; } +int redecl(int); +int __attribute__((target_clones("default,avx"))) redecl(int); + +int __attribute__((target_clones("default,avx"))) redecl2(int x) { return x; } +int redecl2(int); +// expected-error@+2 {{'target_clones' attribute does not match previous declaration}} +// expected-note@-2 {{previous declaration is here}} +int __attribute__((target_clones("default,sse4.2"))) redecl2(int); + +namespace ns { +int __attribute__((target_clones("default,avx"))) redecl3(int x) { return x; } +int redecl3(int); +int __attribute__((target_clones("default,avx"))) redecl3(int); +} + +extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int x) { return x; } +extern "C" int redecl4(int); +extern "C" int __attribute__((target_clones("default,avx"))) redecl4(int); + +static int __attribute__((target_clones("default,avx"))) redecl5(int x) { return x; } +static int redecl5(int); +static int __attribute__((target_clones("default,avx"))) redecl5(int); + +int __attribute__((target_clones("default,avx"))) redecl6(int x) { return x; } +int redecl6(int); +int __attribute__((target_clones("default,avx"))) redecl6(int); +int __attribute__((target_clones("default,avx"))) redecl6(long x) { return x; } +int redecl6(long); `````````` </details> https://github.com/llvm/llvm-project/pull/237830 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
