Skip to content

Commit 60a6fcd

Browse files
committed
[FMV] Allow multi versioning without default declaration.
This was a limitation which has now been lifted. 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. The ACLE spec has been updated accordingly to make this explicit: "Each version declaration should be visible at the translation unit in which the corresponding function version resides." ARM-software/acle#310 If a resolver is required (because there is a caller in the TU), then a default declaration is implicitly generated.
1 parent e925968 commit 60a6fcd

File tree

8 files changed

+339
-222
lines changed

8 files changed

+339
-222
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4092,77 +4092,78 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
40924092
return llvm::GlobalValue::WeakODRLinkage;
40934093
}
40944094

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

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

4165+
llvm::Function *Func = createFunction(FD, I);
4166+
StringRef Version = TC->getFeatureStr(I);
41664167
StringRef Architecture;
41674168
llvm::SmallVector<StringRef, 1> Feature;
41684169

@@ -4180,16 +4181,23 @@ void CodeGenModule::emitMultiVersionFunctions() {
41804181
Feature.push_back(Version);
41814182
}
41824183

4183-
Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
4184+
Options.emplace_back(Func, Architecture, Feature);
41844185
}
41854186
} else {
41864187
assert(0 && "Expected a target or target_clones multiversion function");
41874188
continue;
41884189
}
41894190

4190-
if (!EmitResolver)
4191+
if (!ShouldEmitResolver)
41914192
continue;
41924193

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

clang/lib/Sema/SemaDecl.cpp

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

1144911449
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)