diff options
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 4 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/attr-cpuspecific.cpp | 1 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp | 26 |
3 files changed, 18 insertions, 13 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index c085f52..648fa9f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -9734,6 +9734,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { return true; if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + // Multiversioned functions always have to be emitted, because they are used + // by the resolver. + if (FD->isMultiVersion()) + return true; // Forward declarations aren't required. if (!FD->doesThisDeclarationHaveABody()) return FD->doesDeclarationForceExternallyVisibleDefinition(); diff --git a/clang/test/CodeGenCXX/attr-cpuspecific.cpp b/clang/test/CodeGenCXX/attr-cpuspecific.cpp index ae5702f..d9b7b54 100644 --- a/clang/test/CodeGenCXX/attr-cpuspecific.cpp +++ b/clang/test/CodeGenCXX/attr-cpuspecific.cpp @@ -12,6 +12,7 @@ void foo() { s.Func(); } +// LINUX: define linkonce_odr void @_ZN1S4FuncEv.O // LINUX: define void (%struct.S*)* @_ZN1S4FuncEv.resolver // LINUX: ret void (%struct.S*)* @_ZN1S4FuncEv.S // LINUX: ret void (%struct.S*)* @_ZN1S4FuncEv.O diff --git a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp index 622b738..3d24c7a 100644 --- a/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp +++ b/clang/test/CodeGenCXX/attr-target-mv-member-funcs.cpp @@ -72,6 +72,15 @@ int templ_use() { // CHECK: @_ZN5templIiE3fooEi.ifunc = ifunc i32 (%struct.templ*, i32), i32 (%struct.templ*, i32)* ()* @_ZN5templIiE3fooEi.resolver // CHECK: @_ZN5templIdE3fooEi.ifunc = ifunc i32 (%struct.templ.0*, i32), i32 (%struct.templ.0*, i32)* ()* @_ZN5templIdE3fooEi.resolver +// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.sse4.2(%struct.S* %this, i32) +// CHECK: ret i32 0 + +// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.arch_ivybridge(%struct.S* %this, i32) +// CHECK: ret i32 1 + +// CHECK: define linkonce_odr i32 @_ZN1S3fooEi(%struct.S* %this, i32) +// CHECK: ret i32 2 + // CHECK: define i32 @_Z3barv() // CHECK: %s = alloca %struct.S, align 1 // CHECK: %s2 = alloca %struct.S, align 1 @@ -123,23 +132,14 @@ int templ_use() { // CHECK: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi.sse4.2 // CHECK: ret i32 (%struct.templ.0*, i32)* @_ZN5templIdE3fooEi -// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.sse4.2(%struct.S* %this, i32) -// CHECK: ret i32 0 - -// CHECK: declare i32 @_ZN1S3fooEi.arch_sandybridge(%struct.S*, i32) - -// CHECK: define linkonce_odr i32 @_ZN1S3fooEi.arch_ivybridge(%struct.S* %this, i32) -// CHECK: ret i32 1 - -// CHECK: define linkonce_odr i32 @_ZN1S3fooEi(%struct.S* %this, i32) -// CHECK: ret i32 2 - // CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi.sse4.2 -// CHECK: declare i32 @_ZN5templIiE3fooEi.arch_sandybridge // CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi.arch_ivybridge // CHECK: define linkonce_odr i32 @_ZN5templIiE3fooEi // CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi.sse4.2 -// CHECK: declare i32 @_ZN5templIdE3fooEi.arch_sandybridge // CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi.arch_ivybridge // CHECK: define linkonce_odr i32 @_ZN5templIdE3fooEi +// +// CHECK: declare i32 @_ZN1S3fooEi.arch_sandybridge(%struct.S*, i32) +// CHECK: declare i32 @_ZN5templIiE3fooEi.arch_sandybridge +// CHECK: declare i32 @_ZN5templIdE3fooEi.arch_sandybridge |