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.
This commit is contained in:
Erich Keane 2021-04-13 12:44:09 -07:00
parent 7ef2c68a3d
commit 92aba5ae49
3 changed files with 104 additions and 5 deletions

View File

@ -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

View File

@ -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@OutOfLineDefs@@QEAAHH@Z.O"
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@QEAAHH@Z.S"
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHH@Z"(%struct.OutOfLineDefs* %0, i32 %1)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHH@Z.S"(%struct.OutOfLineDefs* %0, i32 %1)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHH@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@OutOfLineDefs@@QEAAHHH@Z.O"
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHH@Z.S"
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHH@Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHHH@Z.S"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHHH@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@OutOfLineDefs@@QEAAHHHH@Z.S"
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z.R"
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z.R"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z.S"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z.O"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
// WINDOWS: call void @llvm.trap
// WINDOWS: define linkonce_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z.O"

View File

@ -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@+2 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
// expected-note@-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(){}