Skip to content

Conversation

@RKSimon
Copy link
Collaborator

@RKSimon RKSimon commented Jul 17, 2025

Possible fix for failed fold in #148191

…des can't create undef/poison

Possible fix for failed fold in llvm#148191
case AArch64ISD::MOVIedit:
case AArch64ISD::MOVImsl:
case AArch64ISD::MOVIshift:
case AArch64ISD::MVNIshift:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact I think these can be put into a AArch64TargetLowering::isGuaranteedNotToBeUndefOrPoisonForTargetNode implementation, but this should have the same effect

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds OK to me, they should never be poison. Do we have a standard way of creating tests for changes like this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be that #148191 is the first case where we manage to show the problem (we need a case where the freeze needs removing quite late into lowering) - I haven't had time to investigate though.

RKSimon added a commit to RKSimon/llvm-project that referenced this pull request Sep 2, 2025
…'t create undef/poison

We can always fold freeze(vashr(x,y)) -> vashr(freeze(x),freeze(y)) as VASHR has defined behaviour for out-of-range shift amounts.

Test coverage can be tricky, so I've hijacked a ComputeNumSignBits test to show that value tracking can still analyse the VASHR node as the FREEZE will have been discarded by the canCreateUndefOrPoison/isGuaranteedNotToBeUndefOrPoison logic in getFreeze().

If this AArch64SelectionDAGTest.cpp approach is OK I'm intending to use it in llvm#149323 once llvm#155696 has landed.
@RKSimon RKSimon marked this pull request as ready for review September 3, 2025 08:55
@RKSimon
Copy link
Collaborator Author

RKSimon commented Sep 3, 2025

@davemgreen I've added test coverage similar to what I'm attempting on #156445

Copy link
Collaborator

@davemgreen davemgreen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds great, thanks. LGTM

@RKSimon RKSimon enabled auto-merge (squash) September 4, 2025 09:31
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-backend-aarch64

Author: Simon Pilgrim (RKSimon)

Changes

Possible fix for failed fold in #148191


Full diff: https://github.com/llvm/llvm-project/pull/149323.diff

3 Files Affected:

  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (+18)
  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.h (+6)
  • (modified) llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp (+41)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index d3515cf81f443..f59cb9c5c6770 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -30959,6 +30959,24 @@ bool AArch64TargetLowering::SimplifyDemandedBitsForTargetNode(
       Op, OriginalDemandedBits, OriginalDemandedElts, Known, TLO, Depth);
 }
 
+bool AArch64TargetLowering::canCreateUndefOrPoisonForTargetNode(
+    SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
+    bool PoisonOnly, bool ConsiderFlags, unsigned Depth) const {
+
+  // TODO: Add more target nodes.
+  switch (Op.getOpcode()) {
+  case AArch64ISD::MOVI:
+  case AArch64ISD::MOVIedit:
+  case AArch64ISD::MOVImsl:
+  case AArch64ISD::MOVIshift:
+  case AArch64ISD::MVNImsl:
+  case AArch64ISD::MVNIshift:
+    return false;
+  }
+  return TargetLowering::canCreateUndefOrPoisonForTargetNode(
+      Op, DemandedElts, DAG, PoisonOnly, ConsiderFlags, Depth);
+}
+
 bool AArch64TargetLowering::isTargetCanonicalConstantNode(SDValue Op) const {
   return Op.getOpcode() == AArch64ISD::DUP ||
          Op.getOpcode() == AArch64ISD::MOVI ||
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index b840af36be7e7..1988ee82880a8 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -869,6 +869,12 @@ class AArch64TargetLowering : public TargetLowering {
                                          TargetLoweringOpt &TLO,
                                          unsigned Depth) const override;
 
+  bool canCreateUndefOrPoisonForTargetNode(SDValue Op,
+                                           const APInt &DemandedElts,
+                                           const SelectionDAG &DAG,
+                                           bool PoisonOnly, bool ConsiderFlags,
+                                           unsigned Depth) const override;
+
   bool isTargetCanonicalConstantNode(SDValue Op) const override;
 
   // With the exception of data-predicate transitions, no instructions are
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index 18c8d4a69e7a8..c4cbd4f7015e6 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -319,6 +319,7 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_UADDO_CARRY) {
 }
 
 // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
+// Attempt to FREEZE the MOV/MVN nodes to show that they can still be analysed.
 TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   SDLoc Loc;
   auto IntSca32VT = MVT::i32;
@@ -344,6 +345,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00));
   EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF));
 
+  auto FrMOVIedit128 = DAG->getFreeze(OpMOVIedit128);
+  Known = DAG->computeKnownBits(FrMOVIedit128);
+  EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00));
+  EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF));
+
   auto N264 = DAG->getConstant(264, Loc, IntSca32VT);
   auto OpMOVImsl64 =
       DAG->getNode(AArch64ISD::MOVImsl, Loc, Int2Vec32VT, N165, N264);
@@ -358,6 +364,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(32, 0xFF5A0000));
   EXPECT_EQ(Known.One, APInt(32, 0x00A5FFFF));
 
+  auto FrMOVImsl128 = DAG->getFreeze(OpMOVImsl128);
+  Known = DAG->computeKnownBits(FrMOVImsl128);
+  EXPECT_EQ(Known.Zero, APInt(32, 0xFF5A0000));
+  EXPECT_EQ(Known.One, APInt(32, 0x00A5FFFF));
+
   auto OpMVNImsl64 =
       DAG->getNode(AArch64ISD::MVNImsl, Loc, Int2Vec32VT, N165, N272);
   Known = DAG->computeKnownBits(OpMVNImsl64);
@@ -370,6 +381,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(32, 0x0000A5FF));
   EXPECT_EQ(Known.One, APInt(32, 0xFFFF5A00));
 
+  auto FrMVNImsl128 = DAG->getFreeze(OpMVNImsl128);
+  Known = DAG->computeKnownBits(FrMVNImsl128);
+  EXPECT_EQ(Known.Zero, APInt(32, 0x0000A5FF));
+  EXPECT_EQ(Known.One, APInt(32, 0xFFFF5A00));
+
   auto N0 = DAG->getConstant(0, Loc, IntSca32VT);
   auto OpMOVIshift2Vec32 =
       DAG->getNode(AArch64ISD::MOVIshift, Loc, Int2Vec32VT, N165, N0);
@@ -384,6 +400,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(32, 0x5AFFFFFF));
   EXPECT_EQ(Known.One, APInt(32, 0xA5000000));
 
+  auto FrMOVIshift4Vec32 = DAG->getFreeze(OpMOVIshift4Vec32);
+  Known = DAG->computeKnownBits(FrMOVIshift4Vec32);
+  EXPECT_EQ(Known.Zero, APInt(32, 0x5AFFFFFF));
+  EXPECT_EQ(Known.One, APInt(32, 0xA5000000));
+
   auto OpMVNIshift2Vec32 =
       DAG->getNode(AArch64ISD::MVNIshift, Loc, Int2Vec32VT, N165, N24);
   Known = DAG->computeKnownBits(OpMVNIshift2Vec32);
@@ -396,6 +417,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(32, 0x000000A5));
   EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF5A));
 
+  auto FrMVNIshift4Vec32 = DAG->getFreeze(OpMVNIshift4Vec32);
+  Known = DAG->computeKnownBits(FrMVNIshift4Vec32);
+  EXPECT_EQ(Known.Zero, APInt(32, 0x000000A5));
+  EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF5A));
+
   auto N8 = DAG->getConstant(8, Loc, IntSca32VT);
   auto OpMOVIshift4Vec16 =
       DAG->getNode(AArch64ISD::MOVIshift, Loc, Int4Vec16VT, N165, N0);
@@ -409,6 +435,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(16, 0x5AFF));
   EXPECT_EQ(Known.One, APInt(16, 0xA500));
 
+  auto FrMOVIshift8Vec16 = DAG->getFreeze(OpMOVIshift8Vec16);
+  Known = DAG->computeKnownBits(FrMOVIshift8Vec16);
+  EXPECT_EQ(Known.Zero, APInt(16, 0x5AFF));
+  EXPECT_EQ(Known.One, APInt(16, 0xA500));
+
   auto OpMVNIshift4Vec16 =
       DAG->getNode(AArch64ISD::MVNIshift, Loc, Int4Vec16VT, N165, N8);
   Known = DAG->computeKnownBits(OpMVNIshift4Vec16);
@@ -421,6 +452,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   EXPECT_EQ(Known.Zero, APInt(16, 0x00A5));
   EXPECT_EQ(Known.One, APInt(16, 0xFF5A));
 
+  auto FrMVNIshift8Vec16 = DAG->getFreeze(OpMVNIshift8Vec16);
+  Known = DAG->computeKnownBits(FrMVNIshift8Vec16);
+  EXPECT_EQ(Known.Zero, APInt(16, 0x00A5));
+  EXPECT_EQ(Known.One, APInt(16, 0xFF5A));
+
   auto OpMOVI8Vec8 = DAG->getNode(AArch64ISD::MOVI, Loc, Int8Vec8VT, N165);
   Known = DAG->computeKnownBits(OpMOVI8Vec8);
   EXPECT_EQ(Known.Zero, APInt(8, 0x5A));
@@ -430,6 +466,11 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
   Known = DAG->computeKnownBits(OpMOVI16Vec8);
   EXPECT_EQ(Known.Zero, APInt(8, 0x5A));
   EXPECT_EQ(Known.One, APInt(8, 0xA5));
+
+  auto FrMOVI16Vec8 = DAG->getFreeze(OpMOVI16Vec8);
+  Known = DAG->computeKnownBits(FrMOVI16Vec8);
+  EXPECT_EQ(Known.Zero, APInt(8, 0x5A));
+  EXPECT_EQ(Known.One, APInt(8, 0xA5));
 }
 
 // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.

@RKSimon RKSimon merged commit eb19183 into llvm:main Sep 4, 2025
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 4, 2025

LLVM Buildbot has detected a new failure on builder cross-project-tests-sie-ubuntu-dwarf5 running on doug-worker-1b while building llvm at step 6 "test-build-unified-tree-check-cross-project".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/163/builds/25881

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-cross-project) failure: test (failure)
******************** TEST 'cross-project-tests :: debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp' FAILED ********************
Exit Code: 2

Command Output (stderr):
--
clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_program_state.cpp.tmp # RUN: at line 8
+ clang++ -O0 -glldb -std=gnu++11 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp -o /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_program_state.cpp.tmp
"/usr/bin/python3.10" "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py" test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable "/home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap" --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_program_state.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp | /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp # RUN: at line 9
+ /usr/bin/python3.10 /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/dexter.py test --fail-lt 1.0 -w --debugger lldb-dap --lldb-executable /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/lldb-dap --binary /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/projects/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/Output/expect_program_state.cpp.tmp -- /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp
+ /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/build/bin/FileCheck /home/buildbot/buildbot-root/cross-project-tests-sie-ubuntu-dwarf5/llvm-project/cross-project-tests/debuginfo-tests/dexter/feature_tests/commands/perfect/expect_program_state.cpp


****************************************


@RKSimon RKSimon deleted the aarch64-nopoison-vmov branch September 4, 2025 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants