Skip to content

Commit 289d36f

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: llvm#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 ab8ace3 commit 289d36f

File tree

8 files changed

+403
-235
lines changed

8 files changed

+403
-235
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,7 +3711,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
37113711

37123712
// Forward declarations are emitted lazily on first use.
37133713
if (!FD->doesThisDeclarationHaveABody()) {
3714-
if (!FD->doesDeclarationForceExternallyVisibleDefinition())
3714+
if (!FD->doesDeclarationForceExternallyVisibleDefinition() &&
3715+
!FD->isTargetVersionMultiVersion())
37153716
return;
37163717

37173718
StringRef MangledName = getMangledName(GD);
@@ -4092,77 +4093,78 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
40924093
return llvm::GlobalValue::WeakODRLinkage;
40934094
}
40944095

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

4102-
bool EmitResolver = !FD->isTargetVersionMultiVersion();
4120+
auto createFunction = [&](const FunctionDecl *Decl, unsigned MVIdx = 0) {
4121+
GlobalDecl CurGD{Decl->isDefined() ? Decl->getDefinition() : Decl, MVIdx};
4122+
StringRef MangledName = getMangledName(CurGD);
4123+
llvm::Constant *Func = GetGlobalValue(MangledName);
4124+
if (!Func) {
4125+
if (Decl->isDefined()) {
4126+
EmitGlobalFunctionDefinition(CurGD, nullptr);
4127+
Func = GetGlobalValue(MangledName);
4128+
} else {
4129+
const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(CurGD);
4130+
llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);
4131+
Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false,
4132+
/*DontDefer=*/false, ForDefinition);
4133+
}
4134+
assert(Func && "This should have just been created");
4135+
}
4136+
return cast<llvm::Function>(Func);
4137+
};
4138+
4139+
bool HasDefaultDecl = !FD->isTargetVersionMultiVersion();
4140+
bool ShouldEmitResolver = !FD->isTargetVersionMultiVersion();
41034141
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
41044142
if (FD->isTargetMultiVersion()) {
41054143
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;
4144+
FD, [&](const FunctionDecl *CurFD) {
4145+
llvm::SmallVector<StringRef, 8> Feats;
4146+
llvm::Function *Func = createFunction(CurFD);
4147+
4148+
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
41274149
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;
4150+
Options.emplace_back(Func, TA->getArchitecture(), Feats);
4151+
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
4152+
bool HasDefaultDef = TVA->isDefaultVersion() &&
4153+
CurFD->doesThisDeclarationHaveABody();
4154+
HasDefaultDecl |= TVA->isDefaultVersion();
4155+
ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
41364156
TVA->getFeatures(Feats);
4137-
Options.emplace_back(cast<llvm::Function>(Func),
4138-
/*Architecture*/ "", Feats);
4139-
}
4157+
Options.emplace_back(Func, /*Architecture*/ "", Feats);
4158+
} else
4159+
llvm_unreachable("unexpected MultiVersionKind");
41404160
});
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))
4161+
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
4162+
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) {
4163+
if (!TC->isFirstOfVersion(I))
41464164
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-
}
41654165

4166+
llvm::Function *Func = createFunction(FD, I);
4167+
StringRef Version = TC->getFeatureStr(I);
41664168
StringRef Architecture;
41674169
llvm::SmallVector<StringRef, 1> Feature;
41684170

@@ -4180,16 +4182,23 @@ void CodeGenModule::emitMultiVersionFunctions() {
41804182
Feature.push_back(Version);
41814183
}
41824184

4183-
Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
4185+
Options.emplace_back(Func, Architecture, Feature);
41844186
}
41854187
} else {
41864188
assert(0 && "Expected a target or target_clones multiversion function");
41874189
continue;
41884190
}
41894191

4190-
if (!EmitResolver)
4192+
if (!ShouldEmitResolver)
41914193
continue;
41924194

4195+
if (!HasDefaultDecl) {
4196+
FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD);
4197+
llvm::Function *Func = createFunction(NewFD);
4198+
llvm::SmallVector<StringRef, 1> Feats;
4199+
Options.emplace_back(Func, /*Architecture*/ "", Feats);
4200+
}
4201+
41934202
llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD);
41944203
if (auto *IFunc = dyn_cast<llvm::GlobalIFunc>(ResolverConstant)) {
41954204
ResolverConstant = IFunc->getResolver();
@@ -4480,7 +4489,9 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
44804489

44814490
if (FD->isMultiVersion()) {
44824491
UpdateMultiVersionNames(GD, FD, MangledName);
4483-
if (!IsForDefinition)
4492+
if (FD->isTargetVersionMultiVersion() && !FD->isUsed())
4493+
AddDeferredMultiVersionResolverToEmit(GD);
4494+
else if (!IsForDefinition)
44844495
return GetOrCreateMultiVersionResolver(GD);
44854496
}
44864497
}

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)