[llvm] [ARM] computeKnownBitsForTargetNode for VMOVIMM/VMVNIMM Fixes #149276 (PR #171434)
Medha Tiwari via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 9 05:04:56 PST 2025
https://github.com/medhatiwari updated https://github.com/llvm/llvm-project/pull/171434
>From 001f970d75a9555595fc05754e119d86003a0df2 Mon Sep 17 00:00:00 2001
From: Medha Tiwari <medhatiwari at ibm.com>
Date: Tue, 9 Dec 2025 18:22:00 +0530
Subject: [PATCH] [ARM] computeKnownBitsForTargetNode for VMOVIMM/VMVNIMM Fixes
#149276
---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 30 +++++++
llvm/lib/Target/ARM/ARMISelLowering.h | 2 +
.../Target/ARM/ARMSelectionDAGTest.cpp | 89 +++++++++++++++++++
3 files changed, 121 insertions(+)
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
More information about the llvm-commits
mailing list