@@ -3449,6 +3449,9 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
3449
3449
// Implicit template instantiations may change linkage if they are later
3450
3450
// explicitly instantiated, so they should not be emitted eagerly.
3451
3451
return false ;
3452
+ // Defer until all versions have been semantically checked.
3453
+ if (FD->hasAttr <TargetVersionAttr>() && !FD->isMultiVersion ())
3454
+ return false ;
3452
3455
}
3453
3456
if (const auto *VD = dyn_cast<VarDecl>(Global)) {
3454
3457
if (Context.getInlineVariableDefinitionKind (VD) ==
@@ -3997,10 +4000,13 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
3997
4000
EmitGlobalFunctionDefinition (GD.getWithMultiVersionIndex (I), nullptr );
3998
4001
// Ensure that the resolver function is also emitted.
3999
4002
GetOrCreateMultiVersionResolver (GD);
4000
- } else if (FD->hasAttr <TargetVersionAttr>()) {
4001
- GetOrCreateMultiVersionResolver (GD);
4002
4003
} else
4003
4004
EmitGlobalFunctionDefinition (GD, GV);
4005
+
4006
+ // Defer the resolver emission until we can reason whether the TU
4007
+ // contains a default target version implementation.
4008
+ if (FD->isTargetVersionMultiVersion ())
4009
+ AddDeferredMultiVersionResolverToEmit (GD);
4004
4010
}
4005
4011
4006
4012
void CodeGenModule::EmitGlobalDefinition (GlobalDecl GD, llvm::GlobalValue *GV) {
@@ -4093,10 +4099,11 @@ void CodeGenModule::emitMultiVersionFunctions() {
4093
4099
const auto *FD = cast<FunctionDecl>(GD.getDecl ());
4094
4100
assert (FD && " Expected a FunctionDecl" );
4095
4101
4102
+ bool EmitResolver = !FD->isTargetVersionMultiVersion ();
4096
4103
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10 > Options;
4097
4104
if (FD->isTargetMultiVersion ()) {
4098
4105
getContext ().forEachMultiversionedFunctionVersion (
4099
- FD, [this , &GD, &Options](const FunctionDecl *CurFD) {
4106
+ FD, [this , &GD, &Options, &EmitResolver ](const FunctionDecl *CurFD) {
4100
4107
GlobalDecl CurGD{
4101
4108
(CurFD->isDefined () ? CurFD->getDefinition () : CurFD)};
4102
4109
StringRef MangledName = getMangledName (CurGD);
@@ -4122,6 +4129,9 @@ void CodeGenModule::emitMultiVersionFunctions() {
4122
4129
TA->getArchitecture (), Feats);
4123
4130
} else {
4124
4131
const auto *TVA = CurFD->getAttr <TargetVersionAttr>();
4132
+ if (CurFD->isUsed () || (TVA->isDefaultVersion () &&
4133
+ CurFD->doesThisDeclarationHaveABody ()))
4134
+ EmitResolver = true ;
4125
4135
llvm::SmallVector<StringRef, 8 > Feats;
4126
4136
TVA->getFeatures (Feats);
4127
4137
Options.emplace_back (cast<llvm::Function>(Func),
@@ -4177,22 +4187,27 @@ void CodeGenModule::emitMultiVersionFunctions() {
4177
4187
continue ;
4178
4188
}
4179
4189
4190
+ if (!EmitResolver)
4191
+ continue ;
4192
+
4180
4193
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver (GD);
4181
4194
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
4182
4195
ResolverConstant = IFunc->getResolver ();
4183
4196
if (FD->isTargetClonesMultiVersion () ||
4184
4197
FD->isTargetVersionMultiVersion ()) {
4185
- const CGFunctionInfo &FI = getTypes ().arrangeGlobalDeclaration (GD);
4186
- llvm::FunctionType *DeclTy = getTypes ().GetFunctionType (FI);
4187
4198
std::string MangledName = getMangledNameImpl (
4188
4199
*this , GD, FD, /* OmitMultiVersionMangling=*/ true );
4189
- // In prior versions of Clang, the mangling for ifuncs incorrectly
4190
- // included an .ifunc suffix. This alias is generated for backward
4191
- // compatibility. It is deprecated, and may be removed in the future.
4192
- auto *Alias = llvm::GlobalAlias::create (
4193
- DeclTy, 0 , getMultiversionLinkage (*this , GD),
4194
- MangledName + " .ifunc" , IFunc, &getModule ());
4195
- SetCommonAttributes (FD, Alias);
4200
+ if (!GetGlobalValue (MangledName + " .ifunc" )) {
4201
+ const CGFunctionInfo &FI = getTypes ().arrangeGlobalDeclaration (GD);
4202
+ llvm::FunctionType *DeclTy = getTypes ().GetFunctionType (FI);
4203
+ // In prior versions of Clang, the mangling for ifuncs incorrectly
4204
+ // included an .ifunc suffix. This alias is generated for backward
4205
+ // compatibility. It is deprecated, and may be removed in the future.
4206
+ auto *Alias = llvm::GlobalAlias::create (
4207
+ DeclTy, 0 , getMultiversionLinkage (*this , GD),
4208
+ MangledName + " .ifunc" , IFunc, &getModule ());
4209
+ SetCommonAttributes (FD, Alias);
4210
+ }
4196
4211
}
4197
4212
}
4198
4213
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
@@ -4349,6 +4364,20 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
4349
4364
}
4350
4365
}
4351
4366
4367
+ // / Adds a declaration to the list of multi version functions if not present.
4368
+ void CodeGenModule::AddDeferredMultiVersionResolverToEmit (GlobalDecl GD) {
4369
+ const auto *FD = cast<FunctionDecl>(GD.getDecl ());
4370
+ assert (FD && " Not a FunctionDecl?" );
4371
+
4372
+ if (FD->isTargetVersionMultiVersion ()) {
4373
+ std::string MangledName =
4374
+ getMangledNameImpl (*this , GD, FD, /* OmitMultiVersionMangling=*/ true );
4375
+ if (!DeferredResolversToEmit.insert (MangledName).second )
4376
+ return ;
4377
+ }
4378
+ MultiVersionFuncs.push_back (GD);
4379
+ }
4380
+
4352
4381
// / If a dispatcher for the specified mangled name is not in the module, create
4353
4382
// / and return an llvm Function with the specified type.
4354
4383
llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver (GlobalDecl GD) {
@@ -4388,7 +4417,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
4388
4417
// The resolver needs to be created. For target and target_clones, defer
4389
4418
// creation until the end of the TU.
4390
4419
if (FD->isTargetMultiVersion () || FD->isTargetClonesMultiVersion ())
4391
- MultiVersionFuncs. push_back (GD);
4420
+ AddDeferredMultiVersionResolverToEmit (GD);
4392
4421
4393
4422
// For cpu_specific, don't create an ifunc yet because we don't know if the
4394
4423
// cpu_dispatch will be emitted in this translation unit.
0 commit comments