Skip to content

Commit bde335c

Browse files
committed
[FMV] Emit the resolver along with the default version definition.
We would like the resolver to be generated eagerly, even if the versioned function is not called from the current translation unit. Fixes #81494. It further allows Multi Versioning to work even if the default target version attribute is omitted from function declarations.
1 parent 8c4546f commit bde335c

File tree

4 files changed

+651
-219
lines changed

4 files changed

+651
-219
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3447,6 +3447,9 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
34473447
// Implicit template instantiations may change linkage if they are later
34483448
// explicitly instantiated, so they should not be emitted eagerly.
34493449
return false;
3450+
// Defer until all versions have been semantically checked.
3451+
if (FD->hasAttr<TargetVersionAttr>() && !FD->isMultiVersion())
3452+
return false;
34503453
}
34513454
if (const auto *VD = dyn_cast<VarDecl>(Global)) {
34523455
if (Context.getInlineVariableDefinitionKind(VD) ==
@@ -3995,10 +3998,13 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
39953998
EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
39963999
// Ensure that the resolver function is also emitted.
39974000
GetOrCreateMultiVersionResolver(GD);
3998-
} else if (FD->hasAttr<TargetVersionAttr>()) {
3999-
GetOrCreateMultiVersionResolver(GD);
40004001
} else
40014002
EmitGlobalFunctionDefinition(GD, GV);
4003+
4004+
// Defer the resolver emission until we can reason whether the TU
4005+
// contains a default target version implementation.
4006+
if (FD->isTargetVersionMultiVersion())
4007+
AddDeferredMultiVersionResolverToEmit(GD);
40024008
}
40034009

40044010
void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
@@ -4091,10 +4097,11 @@ void CodeGenModule::emitMultiVersionFunctions() {
40914097
const auto *FD = cast<FunctionDecl>(GD.getDecl());
40924098
assert(FD && "Expected a FunctionDecl");
40934099

4100+
bool EmitResolver = !FD->isTargetVersionMultiVersion();
40944101
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
40954102
if (FD->isTargetMultiVersion()) {
40964103
getContext().forEachMultiversionedFunctionVersion(
4097-
FD, [this, &GD, &Options](const FunctionDecl *CurFD) {
4104+
FD, [this, &GD, &Options, &EmitResolver](const FunctionDecl *CurFD) {
40984105
GlobalDecl CurGD{
40994106
(CurFD->isDefined() ? CurFD->getDefinition() : CurFD)};
41004107
StringRef MangledName = getMangledName(CurGD);
@@ -4120,6 +4127,9 @@ void CodeGenModule::emitMultiVersionFunctions() {
41204127
TA->getArchitecture(), Feats);
41214128
} else {
41224129
const auto *TVA = CurFD->getAttr<TargetVersionAttr>();
4130+
if (TVA->isDefaultVersion() &&
4131+
CurFD->doesThisDeclarationHaveABody())
4132+
EmitResolver = true;
41234133
llvm::SmallVector<StringRef, 8> Feats;
41244134
TVA->getFeatures(Feats);
41254135
Options.emplace_back(cast<llvm::Function>(Func),
@@ -4175,22 +4185,27 @@ void CodeGenModule::emitMultiVersionFunctions() {
41754185
continue;
41764186
}
41774187

4188+
if (!EmitResolver)
4189+
continue;
4190+
41784191
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
41794192
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
41804193
ResolverConstant = IFunc->getResolver();
41814194
if (FD->isTargetClonesMultiVersion() ||
41824195
FD->isTargetVersionMultiVersion()) {
4183-
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
4184-
llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
41854196
std::string MangledName = getMangledNameImpl(
41864197
*this, GD, FD, /*OmitMultiVersionMangling=*/true);
4187-
// In prior versions of Clang, the mangling for ifuncs incorrectly
4188-
// included an .ifunc suffix. This alias is generated for backward
4189-
// compatibility. It is deprecated, and may be removed in the future.
4190-
auto *Alias = llvm::GlobalAlias::create(
4191-
DeclTy, 0, getMultiversionLinkage(*this, GD),
4192-
MangledName + ".ifunc", IFunc, &getModule());
4193-
SetCommonAttributes(FD, Alias);
4198+
if (!GetGlobalValue(MangledName + ".ifunc")) {
4199+
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
4200+
llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
4201+
// In prior versions of Clang, the mangling for ifuncs incorrectly
4202+
// included an .ifunc suffix. This alias is generated for backward
4203+
// compatibility. It is deprecated, and may be removed in the future.
4204+
auto *Alias = llvm::GlobalAlias::create(
4205+
DeclTy, 0, getMultiversionLinkage(*this, GD),
4206+
MangledName + ".ifunc", IFunc, &getModule());
4207+
SetCommonAttributes(FD, Alias);
4208+
}
41944209
}
41954210
}
41964211
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
@@ -4347,6 +4362,19 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
43474362
}
43484363
}
43494364

4365+
/// Adds a declaration to the list of multi version functions if not present.
4366+
void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) {
4367+
const auto *FD = cast<FunctionDecl>(GD.getDecl());
4368+
assert(FD && "Not a FunctionDecl?");
4369+
4370+
if (FD->isTargetVersionMultiVersion()) {
4371+
StringRef NamePrefix = getMangledName(GD).split('.').first;
4372+
if (!DeferredResolversToEmit.insert(NamePrefix).second)
4373+
return;
4374+
}
4375+
MultiVersionFuncs.push_back(GD);
4376+
}
4377+
43504378
/// If a dispatcher for the specified mangled name is not in the module, create
43514379
/// and return an llvm Function with the specified type.
43524380
llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
@@ -4386,7 +4414,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
43864414
// The resolver needs to be created. For target and target_clones, defer
43874415
// creation until the end of the TU.
43884416
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
4389-
MultiVersionFuncs.push_back(GD);
4417+
AddDeferredMultiVersionResolverToEmit(GD);
43904418

43914419
// For cpu_specific, don't create an ifunc yet because we don't know if the
43924420
// cpu_dispatch will be emitted in this translation unit.

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ class CodeGenModule : public CodeGenTypeCache {
348348
/// yet.
349349
llvm::DenseMap<StringRef, GlobalDecl> DeferredDecls;
350350

351+
llvm::DenseSet<StringRef> DeferredResolversToEmit;
352+
351353
/// This is a list of deferred decls which we have seen that *are* actually
352354
/// referenced. These get code generated when the module is done.
353355
std::vector<GlobalDecl> DeferredDeclsToEmit;
@@ -1588,6 +1590,9 @@ class CodeGenModule : public CodeGenTypeCache {
15881590
llvm::AttributeList ExtraAttrs = llvm::AttributeList(),
15891591
ForDefinition_t IsForDefinition = NotForDefinition);
15901592

1593+
// Adds a declaration to the list of multi version functions if not present.
1594+
void AddDeferredMultiVersionResolverToEmit(GlobalDecl GD);
1595+
15911596
// References to multiversion functions are resolved through an implicitly
15921597
// defined resolver function. This function is responsible for creating
15931598
// the resolver symbol for the provided declaration. The value returned

0 commit comments

Comments
 (0)