[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