-
Notifications
You must be signed in to change notification settings - Fork 14k
[AArch64TargetParser]Fix reconstructFromParsedFeatures ignoring negative features #142236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…ive features The `targetFeatureToExtension` function used by reconstructFromParsedFeatures only found positive `+FEATURE` strings, but not negative `-FEATURE` strings. Extend the function to handle both to fix `reconstructFromParsedFeatures`.
CI failures are unrelated to the change. |
I need to remind myself what is the expected behavior. Lemme take a look. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since reconstructFromParsedFeatures
is intended to reconstruct the extensions bitset from the -cc1
command line, I'd like to see an integration test in addition to the TargetParserTests unittest. For example using -cc1
with --print-enabled-extensions
if that is possible.
@llvm/pr-subscribers-clang Author: Matthias Braun (MatzeB) ChangesThe Full diff: https://github.com/llvm/llvm-project/pull/142236.diff 3 Files Affected:
diff --git a/clang/test/CodeGen/aarch64-always-inline-feature-bug.c b/clang/test/CodeGen/aarch64-always-inline-feature-bug.c
new file mode 100644
index 0000000000000..27c3983c66d2b
--- /dev/null
+++ b/clang/test/CodeGen/aarch64-always-inline-feature-bug.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 -triple aarch64-- -target-feature +neon -target-feature +sve\
+// RUN: -target-feature -sve -emit-llvm %s -o - | FileCheck %s
+
+// Reproducer for bug where clang would reject always_inline for unrelated
+// target features if they were disable with `-feature` on the command line.
+// CHECK: @bar
+__attribute__((always_inline)) __attribute__((target("neon"))) void foo() {}
+void bar() { foo(); }
diff --git a/llvm/lib/TargetParser/AArch64TargetParser.cpp b/llvm/lib/TargetParser/AArch64TargetParser.cpp
index e13c6e6d28c2b..4a2523440f0f0 100644
--- a/llvm/lib/TargetParser/AArch64TargetParser.cpp
+++ b/llvm/lib/TargetParser/AArch64TargetParser.cpp
@@ -60,7 +60,7 @@ uint64_t AArch64::getFMVPriority(ArrayRef<StringRef> Features) {
ExtensionSet FeatureBits;
for (const StringRef Feature : Features) {
std::optional<FMVInfo> FMV = parseFMVExtension(Feature);
- if (!FMV) {
+ if (!FMV && Feature.starts_with('+')) {
if (std::optional<ExtensionInfo> Info = targetFeatureToExtension(Feature))
FMV = lookupFMVByID(Info->ID);
}
@@ -181,7 +181,8 @@ std::optional<AArch64::FMVInfo> AArch64::parseFMVExtension(StringRef FMVExt) {
std::optional<AArch64::ExtensionInfo>
AArch64::targetFeatureToExtension(StringRef TargetFeature) {
for (const auto &E : Extensions)
- if (TargetFeature == E.PosTargetFeature)
+ if (TargetFeature == E.PosTargetFeature ||
+ TargetFeature == E.NegTargetFeature)
return E;
return {};
}
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index f4c93334ac682..468ef57cb5b9b 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1831,6 +1831,22 @@ TEST_P(AArch64ExtensionDependenciesBaseCPUTestFixture,
}
}
+TEST(TargetParserTest, testAArch64ReconstructFromParsedFeatures) {
+ AArch64::ExtensionSet Extensions;
+ std::vector<std::string> FeatureOptions = {
+ "-sve2", "-Baz", "+sve", "+FooBar", "+sve2", "+neon", "-sve",
+ };
+ std::vector<std::string> NonExtensions;
+ Extensions.reconstructFromParsedFeatures(FeatureOptions, NonExtensions);
+
+ std::vector<std::string> NonExtensionsExpected = {"-Baz", "+FooBar"};
+ ASSERT_THAT(NonExtensions, testing::ContainerEq(NonExtensionsExpected));
+ std::vector<StringRef> Features;
+ Extensions.toLLVMFeatureList(Features);
+ std::vector<StringRef> FeaturesExpected = {"+sve2", "+neon", "-sve"};
+ ASSERT_THAT(FeaturesExpected, testing::ContainerEq(FeaturesExpected));
+}
+
AArch64ExtensionDependenciesBaseArchTestParams
AArch64ExtensionDependenciesArchData[] = {
// Base architecture features
|
Cannot test with But I added a test based on the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding the test. Unfortunately because it looks invalid to me, I still don't understand what the user facing problem is. Can you give a clang driver command line + C file that exhibits it?
// RUN: %clang_cc1 -triple aarch64-- -target-feature +neon -target-feature +sve\ | ||
// RUN: -target-feature -sve -emit-llvm %s -o - | FileCheck %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The driver should never emit a -cc1
command line with -target-feature +sve -target-feature -sve
, so I don't think this is a valid way to test whatever the problem is.
// Reproducer for bug where clang would reject always_inline for unrelated | ||
// target features if they were disable with `-feature` on the command line. | ||
// CHECK: @bar | ||
__attribute__((always_inline)) __attribute__((target("neon"))) void foo() {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neon
is not actually a valid argument here, it should be simd
.
https://gcc.gnu.org/onlinedocs/gcc/AArch64-Options.html#index-march
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The __attribute__((target("neon")))
comes originally from the arm_neon.h
header shipping with clang where this is used all over.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, but the header shouldn't be doing that. neon
is the LLVM subtarget feature name which shouldn't be exposed to the user, simd
is the user-facing name that is used on the command line with -march
. target
attribute parameters should match the command line, but historically it accepts any LLVM subtarget feature, which we are trying to clean up. Because neon
is used here rather than simd
, I believe it is not recognised as an extension and just gets passed through to LLVM as-is, and therefore takes a different codepath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, since the header does use it we should check that it behaves sensibly.
|
||
// Reproducer for bug where clang would reject always_inline for unrelated | ||
// target features if they were disable with `-feature` on the command line. | ||
// CHECK: @bar |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to check the LLVM IR attributes
for both functions, which is what reconstructFromParsedFeatures
is used to construct.
TEST(TargetParserTest, testAArch64ReconstructFromParsedFeatures) { | ||
AArch64::ExtensionSet Extensions; | ||
std::vector<std::string> FeatureOptions = { | ||
"-sve2", "-Baz", "+sve", "+FooBar", "+sve2", "+neon", "-sve", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this has the same issue as described for the C test: the function is not designed to be able to handle both +feat
and -feat
in the same list, because the driver would never emit that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line made me believe it was meant to handle negative features: https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/AArch64TargetParser.cpp#L368
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the original intention was for it to be able to handle either positive (added to the ExtensionSet
without dependencies) or negative (marked as "touched" on the ExtensionSet
) for a given feature, but not see both of them in the same list. As @labrinea pointed out though the code is not perfect, the negative branch looks dead since targetFeatureToExtension
doesn't handle negative features.
I submitted this fix after seeing this line: https://github.com/llvm/llvm-project/blob/main/llvm/lib/TargetParser/AArch64TargetParser.cpp#L368 which looks like the function intends to handle negative features. |
The original situation looks something like:
Compiled with This compiled fine in clang-17, but with the clang-19 the frontend started producing this confusing message (because this is a neon intrinsic, not an SVE one):
|
Well, with your patch this now compiles, but the unit test demonstrates that none of the extensions of that command line which depend on sve (like sve2, sve2-bitperm, etc) will get disabled. I doubt this was the intention. Passing internal frontend options with -Xclang is not recommended. I tried modifying |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the slow responses, this has revealed some issues that we are not sure how to fix... I am happy with the patch as it is, it is a strict improvement for reconstructFromParsedFeatures
.
As @labrinea pointed out though, you should be aware that disabling SVE like this via -Xclang
will bypass the driver, where the dependency tracking logic exists, and disable SVE only. Any subtarget features that depend on SVE (e.g. SVE2) will still be enabled, unless you explicitly disable them too. It is strongly advised to modify the -march
flag instead.
Also be aware that you can't (currently) rely on --print-enabled-extensions
to give you an accurate view of what is enabled/disabled if you are manually adding -target-feature
flags to the -cc1
command.
See #143570 for the details.
Yeah I'm definitely not happy about the |
The
targetFeatureToExtension
function used byreconstructFromParsedFeatures only found positive
+FEATURE
strings,but not negative
-FEATURE
strings. Extend the function to handle bothto fix
reconstructFromParsedFeatures
.