Skip to content

Commit a03d06a

Browse files
Reland "[AArch64] Decouple feature dependency expansion. (#94279)" (#95519)
This is the second attempt. When parsing the target attribute we should be letting cc1 features which don't correspond to Extensions pass through to avoid errors like the following: % cat neon.c __attribute__((target("arch=armv8-a"))) uint64x2_t foo(uint64x2_t a, uint64x2_t b) { return veorq_u64(a, b); } % clang --target=aarch64-linux-gnu -c neon.c error: always_inline function 'veorq_u64' requires target feature 'outline-atomics', but would be inlined into function 'foo' that is compiled without support for 'outline-atomics' Co-authored-by: Tomas Matheson <[email protected]>
1 parent e5f1639 commit a03d06a

File tree

15 files changed

+239
-237
lines changed

15 files changed

+239
-237
lines changed

clang/include/clang/AST/ASTContext.h

-3
Original file line numberDiff line numberDiff line change
@@ -3210,9 +3210,6 @@ class ASTContext : public RefCountedBase<ASTContext> {
32103210
/// valid feature names.
32113211
ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const;
32123212

3213-
std::vector<std::string>
3214-
filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const;
3215-
32163213
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
32173214
const FunctionDecl *) const;
32183215
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>
@@ -13676,17 +13677,20 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
1367613677
}
1367713678
}
1367813679

13679-
std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs(
13680-
const TargetVersionAttr *TV) const {
13681-
assert(TV != nullptr);
13682-
llvm::SmallVector<StringRef, 8> Feats;
13683-
std::vector<std::string> ResFeats;
13684-
TV->getFeatures(Feats);
13685-
for (auto &Feature : Feats)
13686-
if (Target->validateCpuSupports(Feature.str()))
13687-
// Use '?' to mark features that came from TargetVersion.
13688-
ResFeats.push_back("?" + Feature.str());
13689-
return ResFeats;
13680+
// Given a list of FMV features, return a concatenated list of the
13681+
// corresponding backend features (which may contain duplicates).
13682+
static std::vector<std::string> getFMVBackendFeaturesFor(
13683+
const llvm::SmallVectorImpl<StringRef> &FMVFeatStrings) {
13684+
std::vector<std::string> BackendFeats;
13685+
for (StringRef F : FMVFeatStrings) {
13686+
if (auto FMVExt = llvm::AArch64::parseArchExtension(F)) {
13687+
SmallVector<StringRef, 8> Feats;
13688+
FMVExt->DependentFeatures.split(Feats, ',', -1, false);
13689+
for (StringRef F : Feats)
13690+
BackendFeats.push_back(F.str());
13691+
}
13692+
}
13693+
return BackendFeats;
1369013694
}
1369113695

1369213696
ParsedTargetAttr
@@ -13721,10 +13725,12 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1372113725

1372213726
// Make a copy of the features as passed on the command line into the
1372313727
// beginning of the additional features from the function to override.
13724-
ParsedAttr.Features.insert(
13725-
ParsedAttr.Features.begin(),
13726-
Target->getTargetOpts().FeaturesAsWritten.begin(),
13727-
Target->getTargetOpts().FeaturesAsWritten.end());
13728+
// AArch64 handles command line option features in parseTargetAttr().
13729+
if (!Target->getTriple().isAArch64())
13730+
ParsedAttr.Features.insert(
13731+
ParsedAttr.Features.begin(),
13732+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13733+
Target->getTargetOpts().FeaturesAsWritten.end());
1372813734

1372913735
if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU))
1373013736
TargetCPU = ParsedAttr.CPU;
@@ -13745,32 +13751,31 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
1374513751
Target->getTargetOpts().FeaturesAsWritten.end());
1374613752
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1374713753
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
13748-
std::vector<std::string> Features;
1374913754
if (Target->getTriple().isAArch64()) {
13750-
// TargetClones for AArch64
1375113755
llvm::SmallVector<StringRef, 8> Feats;
1375213756
TC->getFeatures(Feats, GD.getMultiVersionIndex());
13753-
for (StringRef Feat : Feats)
13754-
if (Target->validateCpuSupports(Feat.str()))
13755-
// Use '?' to mark features that came from AArch64 TargetClones.
13756-
Features.push_back("?" + Feat.str());
13757+
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
1375713758
Features.insert(Features.begin(),
1375813759
Target->getTargetOpts().FeaturesAsWritten.begin(),
1375913760
Target->getTargetOpts().FeaturesAsWritten.end());
13761+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1376013762
} else {
13763+
std::vector<std::string> Features;
1376113764
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
1376213765
if (VersionStr.starts_with("arch="))
1376313766
TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
1376413767
else if (VersionStr != "default")
1376513768
Features.push_back((StringRef{"+"} + VersionStr).str());
13769+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1376613770
}
13767-
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1376813771
} else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
13769-
std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV);
13770-
Feats.insert(Feats.begin(),
13771-
Target->getTargetOpts().FeaturesAsWritten.begin(),
13772-
Target->getTargetOpts().FeaturesAsWritten.end());
13773-
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats);
13772+
llvm::SmallVector<StringRef, 8> Feats;
13773+
TV->getFeatures(Feats);
13774+
std::vector<std::string> Features = getFMVBackendFeaturesFor(Feats);
13775+
Features.insert(Features.begin(),
13776+
Target->getTargetOpts().FeaturesAsWritten.begin(),
13777+
Target->getTargetOpts().FeaturesAsWritten.end());
13778+
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
1377413779
} else {
1377513780
FeatureMap = Target->getTargetOpts().FeatureMap;
1377613781
}

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

+41-72
Original file line numberDiff line numberDiff line change
@@ -1064,57 +1064,17 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
10641064
return true;
10651065
}
10661066

1067-
bool AArch64TargetInfo::initFeatureMap(
1068-
llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
1069-
const std::vector<std::string> &FeaturesVec) const {
1070-
std::vector<std::string> UpdatedFeaturesVec;
1071-
// Parse the CPU and add any implied features.
1072-
std::optional<llvm::AArch64::CpuInfo> CpuInfo = llvm::AArch64::parseCpu(CPU);
1073-
if (CpuInfo) {
1074-
auto Exts = CpuInfo->getImpliedExtensions();
1075-
std::vector<StringRef> CPUFeats;
1076-
llvm::AArch64::getExtensionFeatures(Exts, CPUFeats);
1077-
for (auto F : CPUFeats) {
1078-
assert((F[0] == '+' || F[0] == '-') && "Expected +/- in target feature!");
1079-
UpdatedFeaturesVec.push_back(F.str());
1080-
}
1081-
}
1082-
1083-
// Process target and dependent features. This is done in two loops collecting
1084-
// them into UpdatedFeaturesVec: first to add dependent '+'features, second to
1085-
// add target '+/-'features that can later disable some of features added on
1086-
// the first loop. Function Multi Versioning features begin with '?'.
1087-
for (const auto &Feature : FeaturesVec)
1088-
if (((Feature[0] == '?' || Feature[0] == '+')) &&
1089-
AArch64TargetInfo::doesFeatureAffectCodeGen(Feature.substr(1))) {
1090-
StringRef DepFeatures =
1091-
AArch64TargetInfo::getFeatureDependencies(Feature.substr(1));
1092-
SmallVector<StringRef, 1> AttrFeatures;
1093-
DepFeatures.split(AttrFeatures, ",");
1094-
for (auto F : AttrFeatures)
1095-
UpdatedFeaturesVec.push_back(F.str());
1096-
}
1097-
for (const auto &Feature : FeaturesVec)
1098-
if (Feature[0] != '?') {
1099-
std::string UpdatedFeature = Feature;
1100-
if (Feature[0] == '+') {
1101-
std::optional<llvm::AArch64::ExtensionInfo> Extension =
1102-
llvm::AArch64::parseArchExtension(Feature.substr(1));
1103-
if (Extension)
1104-
UpdatedFeature = Extension->Feature.str();
1105-
}
1106-
UpdatedFeaturesVec.push_back(UpdatedFeature);
1107-
}
1108-
1109-
return TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec);
1110-
}
1111-
11121067
// Parse AArch64 Target attributes, which are a comma separated list of:
11131068
// "arch=<arch>" - parsed to features as per -march=..
11141069
// "cpu=<cpu>" - parsed to features as per -mcpu=.., with CPU set to <cpu>
11151070
// "tune=<cpu>" - TuneCPU set to <cpu>
11161071
// "feature", "no-feature" - Add (or remove) feature.
11171072
// "+feature", "+nofeature" - Add (or remove) feature.
1073+
//
1074+
// A feature may correspond to an Extension (anything with a corresponding
1075+
// AEK_), in which case an ExtensionSet is used to parse it and expand its
1076+
// dependencies. If the feature does not yield a successful parse then it
1077+
// is passed through.
11181078
ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11191079
ParsedTargetAttr Ret;
11201080
if (Features == "default")
@@ -1124,23 +1084,31 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11241084
bool FoundArch = false;
11251085

11261086
auto SplitAndAddFeatures = [](StringRef FeatString,
1127-
std::vector<std::string> &Features) {
1087+
std::vector<std::string> &Features,
1088+
llvm::AArch64::ExtensionSet &FeatureBits) {
11281089
SmallVector<StringRef, 8> SplitFeatures;
11291090
FeatString.split(SplitFeatures, StringRef("+"), -1, false);
11301091
for (StringRef Feature : SplitFeatures) {
1131-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1132-
if (!FeatureName.empty())
1133-
Features.push_back(FeatureName.str());
1092+
if (FeatureBits.parseModifier(Feature))
1093+
continue;
1094+
// Pass through anything that failed to parse so that we can emit
1095+
// diagnostics, as well as valid internal feature names.
1096+
//
1097+
// FIXME: We should consider rejecting internal feature names like
1098+
// neon, v8a, etc.
1099+
// FIXME: We should consider emitting diagnostics here.
1100+
if (Feature.starts_with("no"))
1101+
Features.push_back("-" + Feature.drop_front(2).str());
11341102
else
1135-
// Pushing the original feature string to give a sema error later on
1136-
// when they get checked.
1137-
if (Feature.starts_with("no"))
1138-
Features.push_back("-" + Feature.drop_front(2).str());
1139-
else
1140-
Features.push_back("+" + Feature.str());
1103+
Features.push_back("+" + Feature.str());
11411104
}
11421105
};
11431106

1107+
llvm::AArch64::ExtensionSet FeatureBits;
1108+
// Reconstruct the bitset from the command line option features.
1109+
FeatureBits.reconstructFromParsedFeatures(getTargetOpts().FeaturesAsWritten,
1110+
Ret.Features);
1111+
11441112
for (auto &Feature : AttrFeatures) {
11451113
Feature = Feature.trim();
11461114
if (Feature.starts_with("fpmath="))
@@ -1163,9 +1131,9 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11631131
// Ret.Features.
11641132
if (!AI)
11651133
continue;
1166-
Ret.Features.push_back(AI->ArchFeature.str());
1134+
FeatureBits.addArchDefaults(*AI);
11671135
// Add any extra features, after the +
1168-
SplitAndAddFeatures(Split.second, Ret.Features);
1136+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
11691137
} else if (Feature.starts_with("cpu=")) {
11701138
if (!Ret.CPU.empty())
11711139
Ret.Duplicate = "cpu=";
@@ -1175,33 +1143,34 @@ ParsedTargetAttr AArch64TargetInfo::parseTargetAttr(StringRef Features) const {
11751143
std::pair<StringRef, StringRef> Split =
11761144
Feature.split("=").second.trim().split("+");
11771145
Ret.CPU = Split.first;
1178-
SplitAndAddFeatures(Split.second, Ret.Features);
1146+
if (auto CpuInfo = llvm::AArch64::parseCpu(Ret.CPU)) {
1147+
FeatureBits.addCPUDefaults(*CpuInfo);
1148+
SplitAndAddFeatures(Split.second, Ret.Features, FeatureBits);
1149+
}
11791150
}
11801151
} else if (Feature.starts_with("tune=")) {
11811152
if (!Ret.Tune.empty())
11821153
Ret.Duplicate = "tune=";
11831154
else
11841155
Ret.Tune = Feature.split("=").second.trim();
11851156
} else if (Feature.starts_with("+")) {
1186-
SplitAndAddFeatures(Feature, Ret.Features);
1187-
} else if (Feature.starts_with("no-")) {
1188-
StringRef FeatureName =
1189-
llvm::AArch64::getArchExtFeature(Feature.split("-").second);
1190-
if (!FeatureName.empty())
1191-
Ret.Features.push_back("-" + FeatureName.drop_front(1).str());
1192-
else
1193-
Ret.Features.push_back("-" + Feature.split("-").second.str());
1157+
SplitAndAddFeatures(Feature, Ret.Features, FeatureBits);
11941158
} else {
1195-
// Try parsing the string to the internal target feature name. If it is
1196-
// invalid, add the original string (which could already be an internal
1197-
// name). These should be checked later by isValidFeatureName.
1198-
StringRef FeatureName = llvm::AArch64::getArchExtFeature(Feature);
1199-
if (!FeatureName.empty())
1200-
Ret.Features.push_back(FeatureName.str());
1159+
if (FeatureBits.parseModifier(Feature, /* AllowNoDashForm = */ true))
1160+
continue;
1161+
// Pass through anything that failed to parse so that we can emit
1162+
// diagnostics, as well as valid internal feature names.
1163+
//
1164+
// FIXME: We should consider rejecting internal feature names like
1165+
// neon, v8a, etc.
1166+
// FIXME: We should consider emitting diagnostics here.
1167+
if (Feature.starts_with("no-"))
1168+
Ret.Features.push_back("-" + Feature.drop_front(3).str());
12011169
else
12021170
Ret.Features.push_back("+" + Feature.str());
12031171
}
12041172
}
1173+
FeatureBits.toLLVMFeatureList(Ret.Features);
12051174
return Ret;
12061175
}
12071176

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)