[clang] 92aba5a - CPUDispatch- allow out of line member definitions

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 14 06:19:54 PDT 2021


Author: Erich Keane
Date: 2021-04-14T06:19:49-07:00
New Revision: 92aba5ae49a6970c43bead0afd1e52c83fe44e6e

URL: https://github.com/llvm/llvm-project/commit/92aba5ae49a6970c43bead0afd1e52c83fe44e6e
DIFF: https://github.com/llvm/llvm-project/commit/92aba5ae49a6970c43bead0afd1e52c83fe44e6e.diff

LOG: CPUDispatch- allow out of line member definitions

ICC permits this, and after some extensive testing it looks like we can
support this with very little trouble.  We intentionally don't choose to
do this with attribute-target (despite it likely working as well!)
  because GCC does not support that, and introducing said
  incompatibility doesn't seem worth it.

Added: 
    clang/test/CodeGenCXX/attr-cpuspecific-outoflinedefs.cpp

Modified: 
    clang/lib/Sema/SemaDecl.cpp
    clang/test/SemaCXX/attr-cpuspecific.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 1d57d8e84849..73303b985f3f 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9693,6 +9693,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
             (D.getCXXScopeSpec().getScopeRep()->isDependent() ||
              (!Previous.empty() && CurContext->isDependentContext()))) {
           // ignore these
+        } else if (NewFD->isCPUDispatchMultiVersion() ||
+                   NewFD->isCPUSpecificMultiVersion()) {
+          // ignore this, we allow the redeclaration behavior here to create new
+          // versions of the function.
         } else {
           // The user tried to provide an out-of-line definition for a
           // function that is a member of a class or namespace, but there

diff  --git a/clang/test/CodeGenCXX/attr-cpuspecific-outoflinedefs.cpp b/clang/test/CodeGenCXX/attr-cpuspecific-outoflinedefs.cpp
new file mode 100644
index 000000000000..a34a0b88e281
--- /dev/null
+++ b/clang/test/CodeGenCXX/attr-cpuspecific-outoflinedefs.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX
+// RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefix=WINDOWS
+
+struct OutOfLineDefs {
+  int foo(int);
+  int foo(int, int);
+  __attribute__((cpu_specific(atom))) int foo(int, int, int) { return 1; }
+};
+
+int __attribute__((cpu_specific(atom))) OutOfLineDefs::foo(int) {
+  return 1;
+}
+int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int) {
+  return 2;
+}
+int __attribute__((cpu_dispatch(ivybridge, atom))) OutOfLineDefs::foo(int) {
+}
+
+int __attribute__((cpu_specific(atom))) OutOfLineDefs::foo(int, int) {
+  return 1;
+}
+int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int, int) {
+  return 2;
+}
+int __attribute__((cpu_dispatch(ivybridge, atom)))
+OutOfLineDefs::foo(int, int) {
+}
+
+int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int, int, int) {
+  return 2;
+}
+int __attribute__((cpu_specific(sandybridge)))
+OutOfLineDefs::foo(int, int, int) {
+  return 3;
+}
+int __attribute__((cpu_dispatch(sandybridge, ivybridge, atom)))
+OutOfLineDefs::foo(int, int, int) {
+}
+
+// IFunc definitions, Linux only.
+// LINUX: @_ZN13OutOfLineDefs3fooEi = weak_odr alias i32 (%struct.OutOfLineDefs*, i32), i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.ifunc
+// LINUX: @_ZN13OutOfLineDefs3fooEii = weak_odr alias i32 (%struct.OutOfLineDefs*, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.ifunc
+// LINUX: @_ZN13OutOfLineDefs3fooEiii = weak_odr alias i32 (%struct.OutOfLineDefs*, i32, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.ifunc
+
+// LINUX: @_ZN13OutOfLineDefs3fooEi.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32), i32 (%struct.OutOfLineDefs*, i32)* ()* @_ZN13OutOfLineDefs3fooEi.resolver
+// LINUX: @_ZN13OutOfLineDefs3fooEii.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32)* ()* @_ZN13OutOfLineDefs3fooEii.resolver
+// LINUX: @_ZN13OutOfLineDefs3fooEiii.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32, i32)* ()* @_ZN13OutOfLineDefs3fooEiii.resolver
+
+// Arity 1 version:
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEi.O
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEi.S
+// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.resolver()
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.S
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.O
+// LINUX: call void @llvm.trap
+
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHH at Z.O"
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHH at Z.S"
+// WINDOWS: define weak_odr dso_local i32 @"?foo at OutOfLineDefs@@QEAAHH at Z"(%struct.OutOfLineDefs* %0, i32 %1)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHH at Z.S"(%struct.OutOfLineDefs* %0, i32 %1)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHH at Z.O"(%struct.OutOfLineDefs* %0, i32 %1)
+// WINDOWS: call void @llvm.trap
+
+// Arity 2 version:
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEii.O
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEii.S
+// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.resolver()
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.S
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.O
+// LINUX: call void @llvm.trap
+
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHH at Z.O"
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHH at Z.S"
+// WINDOWS: define weak_odr dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHH at Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHHH at Z.S"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHHH at Z.O"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
+// WINDOWS: call void @llvm.trap
+
+// Arity 3 version:
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEiii.S
+// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEiii.R
+// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.resolver()
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.R
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.S
+// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.O
+// LINUX: call void @llvm.trap
+// LINUX: define linkonce_odr i32 @_ZN13OutOfLineDefs3fooEiii.O
+
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.S"
+// WINDOWS: define dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.R"
+// WINDOWS: define weak_odr dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.R"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.S"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
+// WINDOWS: musttail call i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.O"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
+// WINDOWS: call void @llvm.trap
+// WINDOWS: define linkonce_odr dso_local i32 @"?foo at OutOfLineDefs@@QEAAHHHH at Z.O"
+

diff  --git a/clang/test/SemaCXX/attr-cpuspecific.cpp b/clang/test/SemaCXX/attr-cpuspecific.cpp
index 7ec8c6cd0ce2..861711b46383 100644
--- a/clang/test/SemaCXX/attr-cpuspecific.cpp
+++ b/clang/test/SemaCXX/attr-cpuspecific.cpp
@@ -98,14 +98,12 @@ struct SpecialFuncs {
   SpecialFuncs& __attribute__((cpu_specific(atom))) operator=(SpecialFuncs&&) = delete;
 };
 
-struct BadOutOfLine {
+struct OutOfLine {
   int __attribute__((cpu_specific(atom, ivybridge))) foo(int);
 };
 
-int __attribute__((cpu_specific(atom, ivybridge))) BadOutOfLine::foo(int) { return 0; }
-// expected-error at +2 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
-// expected-note at -2 {{member declaration nearly matches}}
-int __attribute__((cpu_specific(sandybridge))) BadOutOfLine::foo(int) { return 1; }
+int __attribute__((cpu_specific(atom, ivybridge))) OutOfLine::foo(int) { return 0; }
+int __attribute__((cpu_specific(sandybridge))) OutOfLine::foo(int) { return 1; }
 
 // Ensure Cpp Spelling works.
 [[clang::cpu_specific(ivybridge,atom)]] int CppSpelling(){}


        


More information about the cfe-commits mailing list