Skip to content

Commit 2cf1439

Browse files
authored
[AArch64] Decouple feature dependency expansion. (llvm#94279)
The dependency expansion step which was introduced by FMV has been erroneously used for non-FMV features, for example when parsing the target attribute. The PR llvm#93695 has rectified most of the tests which were relying on dependency expansion of target features specified on the -cc1 command line. In this patch I am decoupling the dependency expansion of features specified on the target attribute from FMV. To do that first I am expanding FMV dependencies before passing the list of target features to initFeatureMap(). Similarly when parsing the target attribute I am reconstructing an ExtensionSet from the list of target features which was created during the command line option parsing. The attribute parsing may toggle bits of that ExtensionSet and at the end it is converted to a list of target features. Those are passed to initFeatureMap(), which no longer requires an override. A side effect of this refactoring is that features specified on the target_version attribute now supersede the command line options, which is what should be happening in the first place.
1 parent dcd9a50 commit 2cf1439

File tree

11 files changed

+211
-222
lines changed

11 files changed

+211
-222
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3203,9 +3203,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
32033203
/// valid feature names.
32043204
ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const;
32053205

3206-
std::vector<std::string>
3207-
filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const;
3208-
32093206
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
32103207
const FunctionDecl *) const;
32113208
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,

clang/lib/AST/ASTContext.cpp

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
#include "llvm/Support/MD5.h"
8888
#include "llvm/Support/MathExtras.h"
8989
#include "llvm/Support/raw_ostream.h"
90+
#include "llvm/TargetParser/AArch64TargetParser.h"
9091
#include "llvm/TargetParser/Triple.h"
9192
#include <algorithm>
9293
#include <cassert>
@@ -13663,17 +13664,20 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
1366313664
}
1366413665
}
1366513666

13666-
std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs(
13667-
const TargetVersionAttr *TV) const {
13668-
assert(TV != nullptr);
13669-
llvm::SmallVector<StringRef, 8> Feats;
13670-
std::vector<std::string> ResFeats;
13671-
TV->getFeatures(Feats);
13672-
for (auto &Feature : Feats)
13673-
if (Target->validateCpuSupports(Feature.str()))
13674-
// Use '?' to mark features that came from TargetVersion.
13675-
ResFeats.push_back("?" + Feature.str());
13676-
return ResFeats;
13667+
// Given a list of FMV features, return a concatenated list of the
13668+
// corresponding backend features (which may contain duplicates).
13669+
static std::vector<std::string> getFMVBackendFeaturesFor(
13670+
const llvm::SmallVectorImpl<StringRef> &FMVFeatStrings) {
13671+
std::vector<std::string> BackendFeats;
13672+
for (StringRef F : FMVFeatStrings) {
13673+
if (auto FMVExt = llvm::AArch64::parseArchExtension(F)) {
13674+
SmallVector<StringRef, 8> Feats;
13675+
FMVExt->DependentFeatures.split(Feats, ',', -1, false);
13676+
for (StringRef F : Feats)
13677+
BackendFeats.push_back(F.str());
13678+
}
13679+
}
13680+
return BackendFeats;
1367713681
}
1367813682

1367913683
ParsedTargetAttr
@@ -13708,10 +13712,12 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1370813712

1370913713
// Make a copy of the features as passed on the command line into the
1371013714
// beginning of the additional features from the function to override.
13711-
ParsedAttr.Features.insert(
13712-
ParsedAttr.Features.begin(),
13713-
Target->getTargetOpts().FeaturesAsWritten.begin(),
13714-
Target->getTargetOpts().FeaturesAsWritten.end());
13715+
// AArch64 handles command line option features in parseTargetAttr().
13716+
if (!Target->getTriple().isAArch64())
13717+
ParsedAttr.Features.insert(
13718+
ParsedAttr.Features.begin(),
13719+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13720+
Target->getTargetOpts().FeaturesAsWritten.end());
1371513721

1371613722
if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU))
1371713723
TargetCPU = ParsedAttr.CPU;
@@ -13732,32 +13738,31 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1373213738
Target->getTargetOpts().FeaturesAsWritten.end());
1373313739
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1373413740
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
13735-
std::vector<std::string> Features;
1373613741
if (Target->getTriple().isAArch64()) {
13737-
// TargetClones for AArch64
1373813742
llvm::SmallVector<StringRef, 8> Feats;
1373913743
TC->getFeatures(Feats, GD.getMultiVersionIndex());
13740-
for (StringRef Feat : Feats)
13741-
if (Target->validateCpuSupports(Feat.str()))
13742-
// Use '?' to mark features that came from AArch64 TargetClones.
13743-
Features.push_back("?" + Feat.str());
13744+
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
1374413745
Features.insert(Features.begin(),
1374513746
Target->getTargetOpts().FeaturesAsWritten.begin(),
1374613747
Target->getTargetOpts().FeaturesAsWritten.end());
13748+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1374713749
} else {
13750+
std::vector<std::string> Features;
1374813751
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
1374913752
if (VersionStr.starts_with("arch="))
1375013753
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
1375113754
else if (VersionStr != "default")
1375213755
Features.push_back((StringRef{"+"} + VersionStr).str());
13756+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1375313757
}
13754-
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1375513758
} else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
13756-
std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV);
13757-
Feats.insert(Feats.begin(),
13758-
Target->getTargetOpts().FeaturesAsWritten.begin(),
13759-
Target->getTargetOpts().FeaturesAsWritten.end());
13760-
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats);
13759+
llvm::SmallVector<StringRef, 8> Feats;
13760+
TV->getFeatures(Feats);
13761+
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
13762+
Features.insert(Features.begin(),
13763+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13764+
Target->getTargetOpts().FeaturesAsWritten.end());
13765+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1376113766
} else {
1376213767
FeatureMap = Target->getTargetOpts().FeatureMap;
1376313768
}

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 33 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,57 +1050,18 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
10501050
return true;
10511051
}
10521052

1053-
bool AArch64TargetInfo::initFeatureMap(
1054-
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
1055-
const std::vector<std::string> &FeaturesVec) const {
1056-
std::vector<std::string> UpdatedFeaturesVec;
1057-
// Parse the CPU and add any implied features.
1058-
std::optional<llvm::AArch64::CpuInfo> CpuInfo = llvm::AArch64::parseCpu(CPU);
1059-
if (CpuInfo) {
1060-
auto Exts = CpuInfo->getImpliedExtensions();
1061-
std::vector<StringRef> CPUFeats;
1062-
llvm::AArch64::getExtensionFeatures(Exts, CPUFeats);
1063-
for (auto F : CPUFeats) {
1064-
assert((F[0] == '+' || F[0] == '-') && "Expected +/- in target feature!");
1065-
UpdatedFeaturesVec.push_back(F.str());
1066-
}
1067-
}
1068-
1069-
// Process target and dependent features. This is done in two loops collecting
1070-
// them into UpdatedFeaturesVec: first to add dependent '+'features, second to
1071-
// add target '+/-'features that can later disable some of features added on
1072-
// the first loop. Function Multi Versioning features begin with '?'.
1073-
for (const auto &Feature : FeaturesVec)
1074-
if (((Feature[0] == '?' || Feature[0] == '+')) &&
1075-
AArch64TargetInfo::doesFeatureAffectCodeGen(Feature.substr(1))) {
1076-
StringRef DepFeatures =
1077-
AArch64TargetInfo::getFeatureDependencies(Feature.substr(1));
1078-
SmallVector<StringRef, 1> AttrFeatures;
1079-
DepFeatures.split(AttrFeatures, ",");
1080-
for (auto F : AttrFeatures)
1081-
UpdatedFeaturesVec.push_back(F.str());
1082-
}
1083-
for (const auto &Feature : FeaturesVec)
1084-
if (Feature[0] != '?') {
1085-
std::string UpdatedFeature = Feature;
1086-
if (Feature[0] == '+') {
1087-
std::optional<llvm::AArch64::ExtensionInfo> Extension =
1088-
llvm::AArch64::parseArchExtension(Feature.substr(1));
1089-
if (Extension)
1090-
UpdatedFeature = Extension->Feature.str();
1091-
}
1092-
UpdatedFeaturesVec.push_back(UpdatedFeature);
1093-
}
1094-
1095-
return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
1096-
}
1097-
10981053
// Parse AArch64 Target attributes, which are a comma separated list of:
10991054
// "arch=<arch>" - parsed to features as per -march=..
11001055
// "cpu=<cpu>" - parsed to features as per -mcpu=.., with CPU set to <cpu>
11011056
// "tune=<cpu>" - TuneCPU set to <cpu>
11021057
// "feature", "no-feature" - Add (or remove) feature.
11031058
// "+feature", "+nofeature" - Add (or remove) feature.
1059+
//
1060+
// A feature may correspond to an Extension (anything with a corresponding
1061+
// AEK_), in which case an ExtensionSet is used to parse it and expand its
1062+
// dependencies. Otherwise the feature is passed through (e.g. +v8.1a,
1063+
// +outline-atomics, -fmv, etc). Features coming from the command line are
1064+
// already parsed, therefore their dependencies do not need expansion.
11041065
ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11051066
ParsedTargetAttr Ret;
11061067
if (Features == "default")
@@ -1110,23 +1071,26 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11101071
bool FoundArch = false;
11111072

11121073
auto SplitAndAddFeatures = [](StringRef FeatString,
1113-
std::vector<std::string> &Features) {
1074+
std::vector<std::string> &Features,
1075+
llvm::AArch64::ExtensionSet &FeatureBits) {
11141076
SmallVector<StringRef, 8> SplitFeatures;
11151077
FeatString.split(SplitFeatures, StringRef("+"), -1, false);
11161078
for (StringRef Feature : SplitFeatures) {
1117-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1118-
if (!FeatureName.empty())
1119-
Features.push_back(FeatureName.str());
1079+
if (FeatureBits.parseModifier(Feature, /* AllowNoDashForm = */ true))
1080+
continue;
1081+
// Pass through features that are not extensions, e.g. +v8.1a,
1082+
// +outline-atomics, -fmv, etc.
1083+
if (Feature.starts_with("no"))
1084+
Features.push_back("-" + Feature.drop_front(2).str());
11201085
else
1121-
// Pushing the original feature string to give a sema error later on
1122-
// when they get checked.
1123-
if (Feature.starts_with("no"))
1124-
Features.push_back("-" + Feature.drop_front(2).str());
1125-
else
1126-
Features.push_back("+" + Feature.str());
1086+
Features.push_back("+" + Feature.str());
11271087
}
11281088
};
11291089

1090+
llvm::AArch64::ExtensionSet FeatureBits;
1091+
// Reconstruct the bitset from the command line option features.
1092+
FeatureBits.reconstructFromParsedFeatures(getTargetOpts().FeaturesAsWritten);
1093+
11301094
for (auto &Feature : AttrFeatures) {
11311095
Feature = Feature.trim();
11321096
if (Feature.starts_with("fpmath="))
@@ -1149,9 +1113,9 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11491113
// Ret.Features.
11501114
if (!AI)
11511115
continue;
1152-
Ret.Features.push_back(AI->ArchFeature.str());
1116+
FeatureBits.addArchDefaults(*AI);
11531117
// Add any extra features, after the +
1154-
SplitAndAddFeatures(Split.second, Ret.Features);
1118+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
11551119
} else if (Feature.starts_with("cpu=")) {
11561120
if (!Ret.CPU.empty())
11571121
Ret.Duplicate = "cpu=";
@@ -1161,33 +1125,30 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11611125
std::pair<StringRef, StringRef> Split =
11621126
Feature.split("=").second.trim().split("+");
11631127
Ret.CPU = Split.first;
1164-
SplitAndAddFeatures(Split.second, Ret.Features);
1128+
if (auto CpuInfo = llvm::AArch64::parseCpu(Ret.CPU)) {
1129+
FeatureBits.addCPUDefaults(*CpuInfo);
1130+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
1131+
}
11651132
}
11661133
} else if (Feature.starts_with("tune=")) {
11671134
if (!Ret.Tune.empty())
11681135
Ret.Duplicate = "tune=";
11691136
else
11701137
Ret.Tune = Feature.split("=").second.trim();
11711138
} else if (Feature.starts_with("+")) {
1172-
SplitAndAddFeatures(Feature, Ret.Features);
1173-
} else if (Feature.starts_with("no-")) {
1174-
StringRef FeatureName =
1175-
llvm::AArch64::getArchExtFeature(Feature.split("-").second);
1176-
if (!FeatureName.empty())
1177-
Ret.Features.push_back("-" + FeatureName.drop_front(1).str());
1178-
else
1179-
Ret.Features.push_back("-" + Feature.split("-").second.str());
1139+
SplitAndAddFeatures(Feature, Ret.Features, FeatureBits);
11801140
} else {
1181-
// Try parsing the string to the internal target feature name. If it is
1182-
// invalid, add the original string (which could already be an internal
1183-
// name). These should be checked later by isValidFeatureName.
1184-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1185-
if (!FeatureName.empty())
1186-
Ret.Features.push_back(FeatureName.str());
1141+
if (FeatureBits.parseModifier(Feature, /* AllowNoDashForm = */ true))
1142+
continue;
1143+
// Pass through features that are not extensions, e.g. +v8.1a,
1144+
// +outline-atomics, -fmv, etc.
1145+
if (Feature.starts_with("no-"))
1146+
Ret.Features.push_back("-" + Feature.drop_front(3).str());
11871147
else
11881148
Ret.Features.push_back("+" + Feature.str());
11891149
}
11901150
}
1151+
FeatureBits.toLLVMFeatureList(Ret.Features);
11911152
return Ret;
11921153
}
11931154

clang/lib/Basic/Targets/AArch64.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
107107
unsigned multiVersionSortPriority(StringRef Name) const override;
108108
unsigned multiVersionFeatureCost() const override;
109109

110-
bool
111-
initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags,
112-
StringRef CPU,
113-
const std::vector<std::string> &FeaturesVec) const override;
114110
bool useFP16ConversionIntrinsics() const override {
115111
return false;
116112
}

clang/test/CodeGen/aarch64-cpu-supports-target.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,5 @@ int test_versions() {
4848
return code();
4949
}
5050
// CHECK: attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
51-
// CHECK: attributes #1 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+neon" }
52-
// CHECK: attributes #2 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve" }
51+
// CHECK: attributes #1 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon" }
52+
// CHECK: attributes #2 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+sve" }

clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme \
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +bf16 \
22
// RUN: -disable-O0-optnone -Werror -emit-llvm -o - %s \
33
// RUN: | opt -S -passes=mem2reg \
44
// RUN: | opt -S -passes=inline \

0 commit comments

Comments
 (0)