Skip to content

Commit ec2af3b

Browse files
committed
[FMV] Allow multi versioning without default declaration.
This was a limitation which has now been lifted upon request. Please read the thread below for more details: #84405 (comment) Basically it allows to separate versioned implementations across different TUs without having to share private header files which contain the default declaration. If a resolver is required (because there is a caller in the TU), then a default declaration is implicitly generated.
1 parent 6a49501 commit ec2af3b

File tree

8 files changed

+337
-217
lines changed

8 files changed

+337
-217
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 64 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4090,77 +4090,81 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
40904090
return llvm::GlobalValue::WeakODRLinkage;
40914091
}
40924092

4093+
static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) {
4094+
DeclContext *DeclCtx = FD->getASTContext().getTranslationUnitDecl();
4095+
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
4096+
StorageClass SC = FD->getStorageClass();
4097+
DeclarationName Name = FD->getNameInfo().getName();
4098+
4099+
FunctionDecl *NewDecl = FunctionDecl::Create(
4100+
FD->getASTContext(), DeclCtx, FD->getBeginLoc(), FD->getEndLoc(), Name,
4101+
TInfo->getType(), TInfo, SC);
4102+
4103+
NewDecl->setIsMultiVersion();
4104+
NewDecl->addAttr(TargetVersionAttr::CreateImplicit(
4105+
NewDecl->getASTContext(), "default", NewDecl->getSourceRange()));
4106+
4107+
return NewDecl;
4108+
}
4109+
40934110
void CodeGenModule::emitMultiVersionFunctions() {
40944111
std::vector<GlobalDecl> MVFuncsToEmit;
40954112
MultiVersionFuncs.swap(MVFuncsToEmit);
40964113
for (GlobalDecl GD : MVFuncsToEmit) {
40974114
const auto *FD = cast<FunctionDecl>(GD.getDecl());
40984115
assert(FD && "Expected a FunctionDecl");
40994116

4100-
bool EmitResolver = !FD->isTargetVersionMultiVersion();
4117+
auto createFunction = [&](const FunctionDecl *Decl, unsigned MVIdx = 0) {
4118+
GlobalDecl CurGD{Decl->isDefined() ? Decl->getDefinition() : Decl, MVIdx};
4119+
StringRef MangledName = getMangledName(CurGD);
4120+
llvm::Constant *Func = GetGlobalValue(MangledName);
4121+
if (!Func) {
4122+
if (Decl->isDefined()) {
4123+
EmitGlobalFunctionDefinition(CurGD, nullptr);
4124+
Func = GetGlobalValue(MangledName);
4125+
} else {
4126+
const CGFunctionInfo &FI =
4127+
getTypes().arrangeGlobalDeclaration(CurGD);
4128+
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
4129+
Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
4130+
/*DontDefer=*/false, ForDefinition);
4131+
}
4132+
assert(Func && "This should have just been created");
4133+
}
4134+
return Func;
4135+
};
4136+
4137+
bool HasDefaultDecl = !FD->isTargetVersionMultiVersion();
4138+
bool ShouldEmitResolver = !FD->isTargetVersionMultiVersion();
41014139
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
41024140
if (FD->isTargetMultiVersion()) {
41034141
getContext().forEachMultiversionedFunctionVersion(
4104-
FD, [this, &GD, &Options, &EmitResolver](const FunctionDecl *CurFD) {
4105-
GlobalDecl CurGD{
4106-
(CurFD->isDefined() ? CurFD->getDefinition() : CurFD)};
4107-
StringRef MangledName = getMangledName(CurGD);
4108-
llvm::Constant *Func = GetGlobalValue(MangledName);
4109-
if (!Func) {
4110-
if (CurFD->isDefined()) {
4111-
EmitGlobalFunctionDefinition(CurGD, nullptr);
4112-
Func = GetGlobalValue(MangledName);
4113-
} else {
4114-
const CGFunctionInfo &FI =
4115-
getTypes().arrangeGlobalDeclaration(GD);
4116-
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
4117-
Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
4118-
/*DontDefer=*/false, ForDefinition);
4119-
}
4120-
assert(Func && "This should have just been created");
4121-
}
4122-
if (CurFD->getMultiVersionKind() == MultiVersionKind::Target) {
4123-
const auto *TA = CurFD->getAttr<TargetAttr>();
4124-
llvm::SmallVector<StringRef, 8> Feats;
4142+
FD, [&](const FunctionDecl *CurFD) {
4143+
llvm::SmallVector<StringRef, 8> Feats;
4144+
llvm::Constant *Func = createFunction(CurFD);
4145+
4146+
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
41254147
TA->getAddedFeatures(Feats);
41264148
Options.emplace_back(cast<llvm::Function>(Func),
41274149
TA->getArchitecture(), Feats);
4128-
} else {
4129-
const auto *TVA = CurFD->getAttr<TargetVersionAttr>();
4130-
if (CurFD->isUsed() || (TVA->isDefaultVersion() &&
4131-
CurFD->doesThisDeclarationHaveABody()))
4132-
EmitResolver = true;
4133-
llvm::SmallVector<StringRef, 8> Feats;
4150+
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
4151+
bool HasDefaultDef = TVA->isDefaultVersion() &&
4152+
CurFD->doesThisDeclarationHaveABody();
4153+
HasDefaultDecl |= TVA->isDefaultVersion();
4154+
ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
41344155
TVA->getFeatures(Feats);
41354156
Options.emplace_back(cast<llvm::Function>(Func),
41364157
/*Architecture*/ "", Feats);
4137-
}
4158+
} else
4159+
llvm_unreachable("unexpected MultiVersionKind");
41384160
});
4139-
} else if (FD->isTargetClonesMultiVersion()) {
4140-
const auto *TC = FD->getAttr<TargetClonesAttr>();
4141-
for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size();
4142-
++VersionIndex) {
4143-
if (!TC->isFirstOfVersion(VersionIndex))
4161+
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
4162+
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) {
4163+
if (!TC->isFirstOfVersion(I))
41444164
continue;
4145-
GlobalDecl CurGD{(FD->isDefined() ? FD->getDefinition() : FD),
4146-
VersionIndex};
4147-
StringRef Version = TC->getFeatureStr(VersionIndex);
4148-
StringRef MangledName = getMangledName(CurGD);
4149-
llvm::Constant *Func = GetGlobalValue(MangledName);
4150-
if (!Func) {
4151-
if (FD->isDefined()) {
4152-
EmitGlobalFunctionDefinition(CurGD, nullptr);
4153-
Func = GetGlobalValue(MangledName);
4154-
} else {
4155-
const CGFunctionInfo &FI =
4156-
getTypes().arrangeGlobalDeclaration(CurGD);
4157-
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
4158-
Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
4159-
/*DontDefer=*/false, ForDefinition);
4160-
}
4161-
assert(Func && "This should have just been created");
4162-
}
41634165

4166+
llvm::Constant *Func = createFunction(FD, I);
4167+
StringRef Version = TC->getFeatureStr(I);
41644168
StringRef Architecture;
41654169
llvm::SmallVector<StringRef, 1> Feature;
41664170

@@ -4185,9 +4189,16 @@ void CodeGenModule::emitMultiVersionFunctions() {
41854189
continue;
41864190
}
41874191

4188-
if (!EmitResolver)
4192+
if (!ShouldEmitResolver)
41894193
continue;
41904194

4195+
if (!HasDefaultDecl) {
4196+
FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD);
4197+
llvm::Constant *Func = createFunction(NewFD);
4198+
llvm::SmallVector<StringRef, 1> Feats;
4199+
Options.emplace_back(cast<llvm::Function>(Func), "", Feats);
4200+
}
4201+
41914202
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
41924203
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
41934204
ResolverConstant = IFunc->getResolver();

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11447,9 +11447,9 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) {
1144711447
"Function lacks multiversion attribute");
1144811448
const auto *TA = FD->getAttr<TargetAttr>();
1144911449
const auto *TVA = FD->getAttr<TargetVersionAttr>();
11450-
// Target and target_version only causes MV if it is default, otherwise this
11451-
// is a normal function.
11452-
if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion()))
11450+
// The target attribute only causes MV if this declaration is the default,
11451+
// otherwise it is treated as a normal function.
11452+
if (TA && !TA->isDefaultVersion())
1145311453
return false;
1145411454

1145511455
if ((TA || TVA) && CheckMultiVersionValue(S, FD)) {

clang/lib/Sema/SemaOverload.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6865,6 +6865,32 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
68656865
return false;
68666866
}
68676867

6868+
static bool isNonViableMultiVersionOverload(FunctionDecl *FD) {
6869+
if (FD->isTargetMultiVersionDefault())
6870+
return false;
6871+
6872+
if (!FD->getASTContext().getTargetInfo().getTriple().isAArch64())
6873+
return FD->isTargetMultiVersion();
6874+
6875+
if (!FD->isMultiVersion())
6876+
return false;
6877+
6878+
// Among multiple target versions consider either the default,
6879+
// or the first non-default in the absence of default version.
6880+
unsigned SeenAt = 0;
6881+
unsigned I = 0;
6882+
bool HasDefault = false;
6883+
FD->getASTContext().forEachMultiversionedFunctionVersion(
6884+
FD, [&](const FunctionDecl *CurFD) {
6885+
if (FD == CurFD)
6886+
SeenAt = I;
6887+
else if (CurFD->isTargetMultiVersionDefault())
6888+
HasDefault = true;
6889+
++I;
6890+
});
6891+
return HasDefault || SeenAt != 0;
6892+
}
6893+
68686894
/// AddOverloadCandidate - Adds the given function to the set of
68696895
/// candidate functions, using the given function call arguments. If
68706896
/// @p SuppressUserConversions, then don't allow user-defined
@@ -6970,11 +6996,7 @@ void Sema::AddOverloadCandidate(
69706996
}
69716997
}
69726998

6973-
if (Function->isMultiVersion() &&
6974-
((Function->hasAttr<TargetAttr>() &&
6975-
!Function->getAttr<TargetAttr>()->isDefaultVersion()) ||
6976-
(Function->hasAttr<TargetVersionAttr>() &&
6977-
!Function->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
6999+
if (isNonViableMultiVersionOverload(Function)) {
69787000
Candidate.Viable = false;
69797001
Candidate.FailureKind = ovl_non_default_multiversion_function;
69807002
return;
@@ -7637,11 +7659,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
76377659
return;
76387660
}
76397661

7640-
if (Method->isMultiVersion() &&
7641-
((Method->hasAttr<TargetAttr>() &&
7642-
!Method->getAttr<TargetAttr>()->isDefaultVersion()) ||
7643-
(Method->hasAttr<TargetVersionAttr>() &&
7644-
!Method->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
7662+
if (isNonViableMultiVersionOverload(Method)) {
76457663
Candidate.Viable = false;
76467664
Candidate.FailureKind = ovl_non_default_multiversion_function;
76477665
}
@@ -8127,11 +8145,7 @@ void Sema::AddConversionCandidate(
81278145
return;
81288146
}
81298147

8130-
if (Conversion->isMultiVersion() &&
8131-
((Conversion->hasAttr<TargetAttr>() &&
8132-
!Conversion->getAttr<TargetAttr>()->isDefaultVersion()) ||
8133-
(Conversion->hasAttr<TargetVersionAttr>() &&
8134-
!Conversion->getAttr<TargetVersionAttr>()->isDefaultVersion()))) {
8148+
if (isNonViableMultiVersionOverload(Conversion)) {
81358149
Candidate.Viable = false;
81368150
Candidate.FailureKind = ovl_non_default_multiversion_function;
81378151
}

0 commit comments

Comments
 (0)