Skip to content

Commit dfef9d0

Browse files
committed
[FMV] Allow mixing target_version with target_clones.
The latest ACLE allows it and further clarifies the following in regards to the combination of the two attributes: "If the `default` matches with another explicitly provided version in the same translation unit, then the compiler can emit only one function instead of the two. The explicitly provided version shall be preferred." ("default" refers to the default clone here) ARM-software/acle#310
1 parent 13078cb commit dfef9d0

File tree

8 files changed

+537
-189
lines changed

8 files changed

+537
-189
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3088,6 +3088,20 @@ def TargetClones : InheritableAttr {
30883088
StringRef getFeatureStr(unsigned Index) const {
30893089
return *(featuresStrs_begin() + Index);
30903090
}
3091+
bool isDefaultVersion(unsigned Index) const {
3092+
return getFeatureStr(Index) == "default";
3093+
}
3094+
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out,
3095+
unsigned Index) const {
3096+
if (isDefaultVersion(Index)) return;
3097+
StringRef Features = getFeatureStr(Index);
3098+
SmallVector<StringRef, 8> AttrFeatures;
3099+
Features.split(AttrFeatures, "+");
3100+
for (auto &Feature : AttrFeatures) {
3101+
Feature = Feature.trim();
3102+
Out.push_back(Feature);
3103+
}
3104+
}
30913105
// Given an index into the 'featuresStrs' sequence, compute a unique
30923106
// ID to be used with function name mangling for the associated variant.
30933107
// This mapping is necessary due to a requirement that the mangling ID

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13676,22 +13676,19 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1367613676
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1367713677
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
1367813678
std::vector<std::string> Features;
13679-
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
1368013679
if (Target->getTriple().isAArch64()) {
1368113680
// TargetClones for AArch64
13682-
if (VersionStr != "default") {
13683-
SmallVector<StringRef, 1> VersionFeatures;
13684-
VersionStr.split(VersionFeatures, "+");
13685-
for (auto &VFeature : VersionFeatures) {
13686-
VFeature = VFeature.trim();
13681+
llvm::SmallVector<StringRef, 8> Feats;
13682+
TC->getFeatures(Feats, GD.getMultiVersionIndex());
13683+
for (StringRef Feat : Feats)
13684+
if (Target->validateCpuSupports(Feat.str()))
1368713685
// Use '?' to mark features that came from AArch64 TargetClones.
13688-
Features.push_back((StringRef{"?"} + VFeature).str());
13689-
}
13690-
}
13686+
Features.push_back("?" + Feat.str());
1369113687
Features.insert(Features.begin(),
1369213688
Target->getTargetOpts().FeaturesAsWritten.begin(),
1369313689
Target->getTargetOpts().FeaturesAsWritten.end());
1369413690
} else {
13691+
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
1369513692
if (VersionStr.starts_with("arch="))
1369613693
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
1369713694
else if (VersionStr != "default")

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3712,7 +3712,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
37123712
// Forward declarations are emitted lazily on first use.
37133713
if (!FD->doesThisDeclarationHaveABody()) {
37143714
if (!FD->doesDeclarationForceExternallyVisibleDefinition() &&
3715-
!FD->isTargetVersionMultiVersion())
3715+
(!FD->isMultiVersion() ||
3716+
!FD->getASTContext().getTargetInfo().getTriple().isAArch64()))
37163717
return;
37173718

37183719
StringRef MangledName = getMangledName(GD);
@@ -3994,10 +3995,11 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
39943995
auto *Spec = FD->getAttr<CPUSpecificAttr>();
39953996
for (unsigned I = 0; I < Spec->cpus_size(); ++I)
39963997
EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
3997-
} else if (FD->isTargetClonesMultiVersion()) {
3998-
auto *Clone = FD->getAttr<TargetClonesAttr>();
3999-
for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I)
4000-
if (Clone->isFirstOfVersion(I))
3998+
} else if (auto *TC = FD->getAttr<TargetClonesAttr>()) {
3999+
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I)
4000+
// AArch64 favors the default target version over the clone if any.
4001+
if ((!TC->isDefaultVersion(I) || !getTarget().getTriple().isAArch64()) &&
4002+
TC->isFirstOfVersion(I))
40014003
EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
40024004
// Ensure that the resolver function is also emitted.
40034005
GetOrCreateMultiVersionResolver(GD);
@@ -4137,57 +4139,49 @@ void CodeGenModule::emitMultiVersionFunctions() {
41374139
};
41384140

41394141
bool HasDefaultDecl = !FD->isTargetVersionMultiVersion();
4140-
bool ShouldEmitResolver = !FD->isTargetVersionMultiVersion();
4142+
bool ShouldEmitResolver =
4143+
!getContext().getTargetInfo().getTriple().isAArch64();
41414144
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
4142-
if (FD->isTargetMultiVersion()) {
4143-
getContext().forEachMultiversionedFunctionVersion(
4144-
FD, [&](const FunctionDecl *CurFD) {
4145-
llvm::SmallVector<StringRef, 8> Feats;
4146-
llvm::Function *Func = createFunction(CurFD);
41474145

4148-
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
4149-
TA->getAddedFeatures(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);
4156-
TVA->getFeatures(Feats);
4157-
Options.emplace_back(Func, /*Architecture*/ "", Feats);
4158-
} else
4159-
llvm_unreachable("unexpected MultiVersionKind");
4160-
});
4161-
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
4162-
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) {
4163-
if (!TC->isFirstOfVersion(I))
4164-
continue;
4146+
getContext().forEachMultiversionedFunctionVersion(
4147+
FD, [&](const FunctionDecl *CurFD) {
4148+
llvm::SmallVector<StringRef, 8> Feats;
41654149

4166-
llvm::Function *Func = createFunction(FD, I);
4167-
StringRef Version = TC->getFeatureStr(I);
4168-
StringRef Architecture;
4169-
llvm::SmallVector<StringRef, 1> Feature;
4170-
4171-
if (getTarget().getTriple().isAArch64()) {
4172-
if (Version != "default") {
4173-
llvm::SmallVector<StringRef, 8> VerFeats;
4174-
Version.split(VerFeats, "+");
4175-
for (auto &CurFeat : VerFeats)
4176-
Feature.push_back(CurFeat.trim());
4177-
}
4178-
} else {
4179-
if (Version.starts_with("arch="))
4180-
Architecture = Version.drop_front(sizeof("arch=") - 1);
4181-
else if (Version != "default")
4182-
Feature.push_back(Version);
4183-
}
4184-
4185-
Options.emplace_back(Func, Architecture, Feature);
4186-
}
4187-
} else {
4188-
assert(0 && "Expected a target or target_clones multiversion function");
4189-
continue;
4190-
}
4150+
if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
4151+
TA->getAddedFeatures(Feats);
4152+
llvm::Function *Func = createFunction(CurFD);
4153+
Options.emplace_back(Func, TA->getArchitecture(), Feats);
4154+
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
4155+
bool HasDefaultDef = TVA->isDefaultVersion() &&
4156+
CurFD->doesThisDeclarationHaveABody();
4157+
HasDefaultDecl |= TVA->isDefaultVersion();
4158+
ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef);
4159+
TVA->getFeatures(Feats);
4160+
llvm::Function *Func = createFunction(CurFD);
4161+
Options.emplace_back(Func, /*Architecture*/ "", Feats);
4162+
} else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
4163+
ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody();
4164+
for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) {
4165+
if (!TC->isFirstOfVersion(I))
4166+
continue;
4167+
4168+
llvm::Function *Func = createFunction(CurFD, I);
4169+
StringRef Architecture;
4170+
Feats.clear();
4171+
if (getTarget().getTriple().isAArch64())
4172+
TC->getFeatures(Feats, I);
4173+
else {
4174+
StringRef Version = TC->getFeatureStr(I);
4175+
if (Version.starts_with("arch="))
4176+
Architecture = Version.drop_front(sizeof("arch=") - 1);
4177+
else if (Version != "default")
4178+
Feats.push_back(Version);
4179+
}
4180+
Options.emplace_back(Func, Architecture, Feats);
4181+
}
4182+
} else
4183+
llvm_unreachable("unexpected MultiVersionKind");
4184+
});
41914185

41924186
if (!ShouldEmitResolver)
41934187
continue;
@@ -4378,7 +4372,7 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) {
43784372
const auto *FD = cast<FunctionDecl>(GD.getDecl());
43794373
assert(FD && "Not a FunctionDecl?");
43804374

4381-
if (FD->isTargetVersionMultiVersion()) {
4375+
if (FD->isTargetVersionMultiVersion() || FD->isTargetClonesMultiVersion()) {
43824376
std::string MangledName =
43834377
getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true);
43844378
if (!DeferredResolversToEmit.insert(MangledName).second)
@@ -4489,7 +4483,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
44894483

44904484
if (FD->isMultiVersion()) {
44914485
UpdateMultiVersionNames(GD, FD, MangledName);
4492-
if (FD->isTargetVersionMultiVersion() && !FD->isUsed())
4486+
if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() &&
4487+
!FD->isUsed())
44934488
AddDeferredMultiVersionResolverToEmit(GD);
44944489
else if (!IsForDefinition)
44954490
return GetOrCreateMultiVersionResolver(GD);

0 commit comments

Comments
 (0)