Skip to content

Reland [FMV] Emit the resolver along with the default version definit… #85923

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 42 additions & 13 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
@@ -3449,6 +3449,9 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
// Implicit template instantiations may change linkage if they are later
// explicitly instantiated, so they should not be emitted eagerly.
return false;
// Defer until all versions have been semantically checked.
if (FD->hasAttr<TargetVersionAttr>() && !FD->isMultiVersion())
return false;
}
if (const auto *VD = dyn_cast<VarDecl>(Global)) {
if (Context.getInlineVariableDefinitionKind(VD) ==
@@ -3997,10 +4000,13 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
// Ensure that the resolver function is also emitted.
GetOrCreateMultiVersionResolver(GD);
} else if (FD->hasAttr<TargetVersionAttr>()) {
GetOrCreateMultiVersionResolver(GD);
} else
EmitGlobalFunctionDefinition(GD, GV);

// Defer the resolver emission until we can reason whether the TU
// contains a default target version implementation.
if (FD->isTargetVersionMultiVersion())
AddDeferredMultiVersionResolverToEmit(GD);
}

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

bool EmitResolver = !FD->isTargetVersionMultiVersion();
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
if (FD->isTargetMultiVersion()) {
getContext().forEachMultiversionedFunctionVersion(
FD, [this, &GD, &Options](const FunctionDecl *CurFD) {
FD, [this, &GD, &Options, &EmitResolver](const FunctionDecl *CurFD) {
GlobalDecl CurGD{
(CurFD->isDefined() ? CurFD->getDefinition() : CurFD)};
StringRef MangledName = getMangledName(CurGD);
@@ -4122,6 +4129,9 @@ void CodeGenModule::emitMultiVersionFunctions() {
TA->getArchitecture(), Feats);
} else {
const auto *TVA = CurFD->getAttr<TargetVersionAttr>();
if (CurFD->isUsed() || (TVA->isDefaultVersion() &&
CurFD->doesThisDeclarationHaveABody()))
EmitResolver = true;
llvm::SmallVector<StringRef, 8> Feats;
TVA->getFeatures(Feats);
Options.emplace_back(cast<llvm::Function>(Func),
@@ -4177,22 +4187,27 @@ void CodeGenModule::emitMultiVersionFunctions() {
continue;
}

if (!EmitResolver)
continue;

llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
ResolverConstant = IFunc->getResolver();
if (FD->isTargetClonesMultiVersion() ||
FD->isTargetVersionMultiVersion()) {
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
std::string MangledName = getMangledNameImpl(
*this, GD, FD, /*OmitMultiVersionMangling=*/true);
// In prior versions of Clang, the mangling for ifuncs incorrectly
// included an .ifunc suffix. This alias is generated for backward
// compatibility. It is deprecated, and may be removed in the future.
auto *Alias = llvm::GlobalAlias::create(
DeclTy, 0, getMultiversionLinkage(*this, GD),
MangledName + ".ifunc", IFunc, &getModule());
SetCommonAttributes(FD, Alias);
if (!GetGlobalValue(MangledName + ".ifunc")) {
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
llvm::FunctionType *DeclTy = getTypes().GetFunctionType(FI);
// In prior versions of Clang, the mangling for ifuncs incorrectly
// included an .ifunc suffix. This alias is generated for backward
// compatibility. It is deprecated, and may be removed in the future.
auto *Alias = llvm::GlobalAlias::create(
DeclTy, 0, getMultiversionLinkage(*this, GD),
MangledName + ".ifunc", IFunc, &getModule());
SetCommonAttributes(FD, Alias);
}
}
}
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
@@ -4349,6 +4364,20 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
}
}

/// Adds a declaration to the list of multi version functions if not present.
void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) {
const auto *FD = cast<FunctionDecl>(GD.getDecl());
assert(FD && "Not a FunctionDecl?");

if (FD->isTargetVersionMultiVersion()) {
std::string MangledName =
getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true);
if (!DeferredResolversToEmit.insert(MangledName).second)
return;
}
MultiVersionFuncs.push_back(GD);
}

/// If a dispatcher for the specified mangled name is not in the module, create
/// and return an llvm Function with the specified type.
llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
@@ -4388,7 +4417,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
// The resolver needs to be created. For target and target_clones, defer
// creation until the end of the TU.
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
MultiVersionFuncs.push_back(GD);
AddDeferredMultiVersionResolverToEmit(GD);

// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
@@ -348,6 +348,8 @@ class CodeGenModule : public CodeGenTypeCache {
/// yet.
llvm::DenseMap<StringRef, GlobalDecl> DeferredDecls;

llvm::StringSet<llvm::BumpPtrAllocator> DeferredResolversToEmit;

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

// Adds a declaration to the list of multi version functions if not present.
void AddDeferredMultiVersionResolverToEmit(GlobalDecl GD);

// References to multiversion functions are resolved through an implicitly
// defined resolver function. This function is responsible for creating
// the resolver symbol for the provided declaration. The value returned
Loading