Skip to content

Commit 8edd8aa

Browse files
committed
Reland "[AArch64] Decouple feature dependency expansion. (llvm#94279)"
My reverted attempt to decouple feature dependency expansion (see llvm#95056) made it evident that some features are still using the FMV dependencies in the target attribute. The original commit broke the llvm test suite. This was addressed here: llvm/llvm-test-suite#133. I am now relanding it.
1 parent 1d45235 commit 8edd8aa

File tree

12 files changed

+213
-222
lines changed

12 files changed

+213
-222
lines changed

clang/include/clang/AST/ASTContext.h

-3
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

+32-27
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/AST/CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,6 @@ add_clang_library(clangAST
139139
omp_gen
140140
ClangDriverOptions
141141
intrinsics_gen
142+
# These generated headers are included transitively.
143+
AArch64TargetParserTableGen
142144
)

clang/lib/Basic/Targets/AArch64.cpp

+33-72
Original file line numberDiff line numberDiff line change
@@ -1052,57 +1052,18 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
10521052
return true;
10531053
}
10541054

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

11141075
auto SplitAndAddFeatures = [](StringRef FeatString,
1115-
std::vector<std::string> &Features) {
1076+
std::vector<std::string> &Features,
1077+
llvm::AArch64::ExtensionSet &FeatureBits) {
11161078
SmallVector<StringRef, 8> SplitFeatures;
11171079
FeatString.split(SplitFeatures, StringRef("+"), -1, false);
11181080
for (StringRef Feature : SplitFeatures) {
1119-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1120-
if (!FeatureName.empty())
1121-
Features.push_back(FeatureName.str());
1081+
if (FeatureBits.parseModifier(Feature, /* AllowNoDashForm = */ true))
1082+
continue;
1083+
// Pass through features that are not extensions, e.g. +v8.1a,
1084+
// +outline-atomics, -fmv, etc.
1085+
if (Feature.starts_with("no"))
1086+
Features.push_back("-" + Feature.drop_front(2).str());
11221087
else
1123-
// Pushing the original feature string to give a sema error later on
1124-
// when they get checked.
1125-
if (Feature.starts_with("no"))
1126-
Features.push_back("-" + Feature.drop_front(2).str());
1127-
else
1128-
Features.push_back("+" + Feature.str());
1088+
Features.push_back("+" + Feature.str());
11291089
}
11301090
};
11311091

1092+
llvm::AArch64::ExtensionSet FeatureBits;
1093+
// Reconstruct the bitset from the command line option features.
1094+
FeatureBits.reconstructFromParsedFeatures(getTargetOpts().FeaturesAsWritten);
1095+
11321096
for (auto &Feature : AttrFeatures) {
11331097
Feature = Feature.trim();
11341098
if (Feature.starts_with("fpmath="))
@@ -1151,9 +1115,9 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11511115
// Ret.Features.
11521116
if (!AI)
11531117
continue;
1154-
Ret.Features.push_back(AI->ArchFeature.str());
1118+
FeatureBits.addArchDefaults(*AI);
11551119
// Add any extra features, after the +
1156-
SplitAndAddFeatures(Split.second, Ret.Features);
1120+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
11571121
} else if (Feature.starts_with("cpu=")) {
11581122
if (!Ret.CPU.empty())
11591123
Ret.Duplicate = "cpu=";
@@ -1163,33 +1127,30 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11631127
std::pair<StringRef, StringRef> Split =
11641128
Feature.split("=").second.trim().split("+");
11651129
Ret.CPU = Split.first;
1166-
SplitAndAddFeatures(Split.second, Ret.Features);
1130+
if (auto CpuInfo = llvm::AArch64::parseCpu(Ret.CPU)) {
1131+
FeatureBits.addCPUDefaults(*CpuInfo);
1132+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
1133+
}
11671134
}
11681135
} else if (Feature.starts_with("tune=")) {
11691136
if (!Ret.Tune.empty())
11701137
Ret.Duplicate = "tune=";
11711138
else
11721139
Ret.Tune = Feature.split("=").second.trim();
11731140
} else if (Feature.starts_with("+")) {
1174-
SplitAndAddFeatures(Feature, Ret.Features);
1175-
} else if (Feature.starts_with("no-")) {
1176-
StringRef FeatureName =
1177-
llvm::AArch64::getArchExtFeature(Feature.split("-").second);
1178-
if (!FeatureName.empty())
1179-
Ret.Features.push_back("-" + FeatureName.drop_front(1).str());
1180-
else
1181-
Ret.Features.push_back("-" + Feature.split("-").second.str());
1141+
SplitAndAddFeatures(Feature, Ret.Features, FeatureBits);
11821142
} else {
1183-
// Try parsing the string to the internal target feature name. If it is
1184-
// invalid, add the original string (which could already be an internal
1185-
// name). These should be checked later by isValidFeatureName.
1186-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1187-
if (!FeatureName.empty())
1188-
Ret.Features.push_back(FeatureName.str());
1143+
if (FeatureBits.parseModifier(Feature, /* AllowNoDashForm = */ true))
1144+
continue;
1145+
// Pass through features that are not extensions, e.g. +v8.1a,
1146+
// +outline-atomics, -fmv, etc.
1147+
if (Feature.starts_with("no-"))
1148+
Ret.Features.push_back("-" + Feature.drop_front(3).str());
11891149
else
11901150
Ret.Features.push_back("+" + Feature.str());
11911151
}
11921152
}
1153+
FeatureBits.toLLVMFeatureList(Ret.Features);
11931154
return Ret;
11941155
}
11951156

clang/lib/Basic/Targets/AArch64.h

-4
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

+2-2
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

+1-1
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)