-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[ARM] computeKnownBitsForTargetNode for VMOVIMM/VMVNIMM Fixes #149276 #171434
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
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-backend-arm Author: Medha Tiwari (medhatiwari) ChangesSummaryAdd Also adds Includes unit test coverage in Regression
Fixes #149276 Full diff: https://github.com/llvm/llvm-project/pull/171434.diff 3 Files Affected:
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 2d26c67a8077a..d5d6cd132068a 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -19863,9 +19863,39 @@ void ARMTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
Known.Zero = IsVORR ? (KnownLHS.Zero & ~Imm) : (KnownLHS.Zero | Imm);
break;
}
+ case ARMISD::VMOVIMM:
+ case ARMISD::VMVNIMM: {
+ unsigned Encoded = Op.getConstantOperandVal(0);
+ unsigned DecEltBits = 0;
+ uint64_t DecodedVal = ARM_AM::decodeVMOVModImm(Encoded, DecEltBits);
+
+ unsigned EltBits = Op.getScalarValueSizeInBits();
+ if (EltBits != DecEltBits)
+ break;
+
+ // Create APInt with the decoded value
+ APInt Imm(DecEltBits, DecodedVal);
+
+ // For VMVNIMM, apply bitwise NOT
+ if (Op.getOpcode() == ARMISD::VMVNIMM)
+ Imm.flipAllBits();
+
+ Known = KnownBits::makeConstant(Imm);
+ break;
+ }
}
}
+
+bool ARMTargetLowering::isTargetCanonicalConstantNode(SDValue Op) const {
+ // VMOVIMM/VMVNIMM are the canonical form for ARM vector constants.
+ // Prevent folding them into generic constants to avoid infinite loops
+ // in SimplifyDemandedBits.
+ return Op.getOpcode() == ARMISD::VMOVIMM ||
+ Op.getOpcode() == ARMISD::VMVNIMM ||
+ TargetLowering::isTargetCanonicalConstantNode(Op);
+}
+
bool ARMTargetLowering::targetShrinkDemandedConstant(
SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts,
TargetLoweringOpt &TLO) const {
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h
index d0fb58c764edd..4c1fc6fdfac90 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.h
+++ b/llvm/lib/Target/ARM/ARMISelLowering.h
@@ -221,6 +221,8 @@ class VectorType;
const SelectionDAG &DAG,
unsigned Depth) const override;
+ bool isTargetCanonicalConstantNode(SDValue Op) const override;
+
bool targetShrinkDemandedConstant(SDValue Op, const APInt &DemandedBits,
const APInt &DemandedElts,
TargetLoweringOpt &TLO) const override;
diff --git a/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp b/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp
index c763da95fa455..c7ce0e12be037 100644
--- a/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp
+++ b/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp
@@ -194,4 +194,93 @@ TEST_F(ARMSelectionDAGTest, computeKnownBits_VBICIMM_cmode2_lhs_ones) {
EXPECT_EQ(Known.Zero, APInt(32, 0x0000AA00));
}
+
+/// VMOVIMM: Move immediate to vector register.
+/// cmode=0x0 puts imm8 in byte0 => per-lane constant = 0x000000AA.
+/// All bits are known since this creates a pure constant.
+TEST_F(ARMSelectionDAGTest, computeKnownBits_VMOVIMM) {
+ SDLoc DL;
+ EVT VT = MVT::v4i32;
+
+ // Encoded immediate: cmode=0x0, imm8=0xAA => per-lane = 0x000000AA
+ SDValue EncSD =
+ DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
+ SDValue Op = DAG->getNode(ARMISD::VMOVIMM, DL, VT, EncSD);
+
+ // VMOVIMM creates a constant, so all bits are known
+ // Encoded (per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
+ // =>
+ // Known.One = 00000000 00000000 00000000 10101010 (0x000000AA)
+ // Known.Zero = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
+ APInt DemandedElts = APInt::getAllOnes(4);
+ KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
+ EXPECT_EQ(Known.One, APInt(32, 0x000000AA));
+ EXPECT_EQ(Known.Zero, APInt(32, 0xFFFFFF55));
+}
+
+/// VMOVIMM with cmode=0x2 (shifted 32-bit elements).
+/// imm8=0xAB, cmode=0x2 => per-lane = 0x0000AB00.
+TEST_F(ARMSelectionDAGTest, computeKnownBits_VMOVIMM_cmode2) {
+ SDLoc DL;
+ EVT VT = MVT::v4i32;
+
+ // Encoded immediate: cmode=0x2, imm8=0xAB => per-lane = 0x0000AB00
+ SDValue EncSD =
+ DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAB), DL, MVT::i32);
+ SDValue Op = DAG->getNode(ARMISD::VMOVIMM, DL, VT, EncSD);
+
+ APInt DemandedElts = APInt::getAllOnes(4);
+ KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
+ EXPECT_EQ(Known.One, APInt(32, 0x0000AB00));
+ EXPECT_EQ(Known.Zero, APInt(32, 0xFFFF54FF));
+}
+
+/// VMVNIMM: Move NOT immediate to vector register.
+/// cmode=0x0 puts imm8 in byte0 => decoded = 0x000000AA, result = ~0x000000AA.
+/// All bits are known since this creates a pure constant (inverted).
+TEST_F(ARMSelectionDAGTest, computeKnownBits_VMVNIMM) {
+ SDLoc DL;
+ EVT VT = MVT::v4i32;
+
+ // Encoded immediate: cmode=0x0, imm8=0xAA => decoded = 0x000000AA
+ // VMVNIMM inverts it => result = 0xFFFFFF55
+ SDValue EncSD =
+ DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
+ SDValue Op = DAG->getNode(ARMISD::VMVNIMM, DL, VT, EncSD);
+
+ // VMVNIMM creates ~constant, so all bits are known
+ // Decoded (per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
+ // Inverted (per-lane) = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
+ // =>
+ // Known.One = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
+ // Known.Zero = 00000000 00000000 00000000 10101010 (0x000000AA)
+ APInt DemandedElts = APInt::getAllOnes(4);
+ KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
+ EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF55));
+ EXPECT_EQ(Known.Zero, APInt(32, 0x000000AA));
+}
+
+/// VMVNIMM with cmode=0x2 (16-bit shifted elements).
+/// imm8=0xAA, cmode=0x2 => decoded = 0x0000AA00, result = ~0x0000AA00.
+TEST_F(ARMSelectionDAGTest, computeKnownBits_VMVNIMM_cmode2) {
+ SDLoc DL;
+ EVT VT = MVT::v4i32;
+
+ // Encoded immediate: cmode=0x2, imm8=0xAA => decoded = 0x0000AA00
+ // VMVNIMM inverts it => result = 0xFFFF55FF
+ SDValue EncSD =
+ DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAA), DL, MVT::i32);
+ SDValue Op = DAG->getNode(ARMISD::VMVNIMM, DL, VT, EncSD);
+
+ // Decoded (per-lane) = 00000000 00000000 10101010 00000000 (0x0000AA00)
+ // Inverted (per-lane) = 11111111 11111111 01010101 11111111 (0xFFFF55FF)
+ // =>
+ // Known.One = 11111111 11111111 01010101 11111111 (0xFFFF55FF)
+ // Known.Zero = 00000000 00000000 10101010 00000000 (0x0000AA00)
+ APInt DemandedElts = APInt::getAllOnes(4);
+ KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
+ EXPECT_EQ(Known.One, APInt(32, 0xFFFF55FF));
+ EXPECT_EQ(Known.Zero, APInt(32, 0x0000AA00));
+}
+
} // end namespace llvm
|
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
001f970 to
ff3f366
Compare
🪟 Windows x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/ARM/fcopysign.llLLVM.CodeGen/Thumb2/float-intrinsics-float.llLLVM.CodeGen/Thumb2/mve-vecreduce-add.llLLVM.CodeGen/Thumb2/mve-vecreduce-mla.llLLVM.CodeGen/Thumb2/mve-vqmovn-combine.llIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/ARM/fcopysign.llLLVM.CodeGen/Thumb2/float-intrinsics-float.llLLVM.CodeGen/Thumb2/mve-vecreduce-add.llLLVM.CodeGen/Thumb2/mve-vecreduce-mla.llLLVM.CodeGen/Thumb2/mve-vqmovn-combine.llIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
|
Can you remove all the formatting changes and update the tests that require it, so we can see the differences. This might take quite a bit of work to work through the issues. |
ff3f366 to
b95076a
Compare
I've cleaned up here, now it shows only the actual code changes |
Summary
Add
computeKnownBitsForTargetNodehandling forARMISD::VMOVIMMandARMISD::VMVNIMM, following the pattern from #149494 (VORRIMM/VBICIMM).Also adds
isTargetCanonicalConstantNodeoverride to mark these nodes as canonical (similar to AArch64 in #148634), preventing infinite loops inSimplifyDemandedBits.Includes unit test coverage in
ARMSelectionDAGTest.cpp.Regression
fcopysign.llgeneratesvand + vorrinstead ofvbif/vbsl. The code is functionally correct but slightly less optimal. This occurs because KnownBits analysis enables earlier optimizations that transform the VBSP pattern before it can be matched.Fixes #149276