Skip to content

Commit 001f970

Browse files
committed
[ARM] computeKnownBitsForTargetNode for VMOVIMM/VMVNIMM Fixes #149276
1 parent 4e94198 commit 001f970

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

llvm/lib/Target/ARM/ARMISelLowering.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19863,9 +19863,39 @@ void ARMTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
1986319863
Known.Zero = IsVORR ? (KnownLHS.Zero & ~Imm) : (KnownLHS.Zero | Imm);
1986419864
break;
1986519865
}
19866+
case ARMISD::VMOVIMM:
19867+
case ARMISD::VMVNIMM: {
19868+
unsigned Encoded = Op.getConstantOperandVal(0);
19869+
unsigned DecEltBits = 0;
19870+
uint64_t DecodedVal = ARM_AM::decodeVMOVModImm(Encoded, DecEltBits);
19871+
19872+
unsigned EltBits = Op.getScalarValueSizeInBits();
19873+
if (EltBits != DecEltBits)
19874+
break;
19875+
19876+
// Create APInt with the decoded value
19877+
APInt Imm(DecEltBits, DecodedVal);
19878+
19879+
// For VMVNIMM, apply bitwise NOT
19880+
if (Op.getOpcode() == ARMISD::VMVNIMM)
19881+
Imm.flipAllBits();
19882+
19883+
Known = KnownBits::makeConstant(Imm);
19884+
break;
19885+
}
1986619886
}
1986719887
}
1986819888

19889+
19890+
bool ARMTargetLowering::isTargetCanonicalConstantNode(SDValue Op) const {
19891+
// VMOVIMM/VMVNIMM are the canonical form for ARM vector constants.
19892+
// Prevent folding them into generic constants to avoid infinite loops
19893+
// in SimplifyDemandedBits.
19894+
return Op.getOpcode() == ARMISD::VMOVIMM ||
19895+
Op.getOpcode() == ARMISD::VMVNIMM ||
19896+
TargetLowering::isTargetCanonicalConstantNode(Op);
19897+
}
19898+
1986919899
bool ARMTargetLowering::targetShrinkDemandedConstant(
1987019900
SDValue Op, const APInt &DemandedBits, const APInt &DemandedElts,
1987119901
TargetLoweringOpt &TLO) const {

llvm/lib/Target/ARM/ARMISelLowering.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ class VectorType;
221221
const SelectionDAG &DAG,
222222
unsigned Depth) const override;
223223

224+
bool isTargetCanonicalConstantNode(SDValue Op) const override;
225+
224226
bool targetShrinkDemandedConstant(SDValue Op, const APInt &DemandedBits,
225227
const APInt &DemandedElts,
226228
TargetLoweringOpt &TLO) const override;

llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,4 +194,93 @@ TEST_F(ARMSelectionDAGTest, computeKnownBits_VBICIMM_cmode2_lhs_ones) {
194194
EXPECT_EQ(Known.Zero, APInt(32, 0x0000AA00));
195195
}
196196

197+
198+
/// VMOVIMM: Move immediate to vector register.
199+
/// cmode=0x0 puts imm8 in byte0 => per-lane constant = 0x000000AA.
200+
/// All bits are known since this creates a pure constant.
201+
TEST_F(ARMSelectionDAGTest, computeKnownBits_VMOVIMM) {
202+
SDLoc DL;
203+
EVT VT = MVT::v4i32;
204+
205+
// Encoded immediate: cmode=0x0, imm8=0xAA => per-lane = 0x000000AA
206+
SDValue EncSD =
207+
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
208+
SDValue Op = DAG->getNode(ARMISD::VMOVIMM, DL, VT, EncSD);
209+
210+
// VMOVIMM creates a constant, so all bits are known
211+
// Encoded (per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
212+
// =>
213+
// Known.One = 00000000 00000000 00000000 10101010 (0x000000AA)
214+
// Known.Zero = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
215+
APInt DemandedElts = APInt::getAllOnes(4);
216+
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
217+
EXPECT_EQ(Known.One, APInt(32, 0x000000AA));
218+
EXPECT_EQ(Known.Zero, APInt(32, 0xFFFFFF55));
219+
}
220+
221+
/// VMOVIMM with cmode=0x2 (shifted 32-bit elements).
222+
/// imm8=0xAB, cmode=0x2 => per-lane = 0x0000AB00.
223+
TEST_F(ARMSelectionDAGTest, computeKnownBits_VMOVIMM_cmode2) {
224+
SDLoc DL;
225+
EVT VT = MVT::v4i32;
226+
227+
// Encoded immediate: cmode=0x2, imm8=0xAB => per-lane = 0x0000AB00
228+
SDValue EncSD =
229+
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAB), DL, MVT::i32);
230+
SDValue Op = DAG->getNode(ARMISD::VMOVIMM, DL, VT, EncSD);
231+
232+
APInt DemandedElts = APInt::getAllOnes(4);
233+
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
234+
EXPECT_EQ(Known.One, APInt(32, 0x0000AB00));
235+
EXPECT_EQ(Known.Zero, APInt(32, 0xFFFF54FF));
236+
}
237+
238+
/// VMVNIMM: Move NOT immediate to vector register.
239+
/// cmode=0x0 puts imm8 in byte0 => decoded = 0x000000AA, result = ~0x000000AA.
240+
/// All bits are known since this creates a pure constant (inverted).
241+
TEST_F(ARMSelectionDAGTest, computeKnownBits_VMVNIMM) {
242+
SDLoc DL;
243+
EVT VT = MVT::v4i32;
244+
245+
// Encoded immediate: cmode=0x0, imm8=0xAA => decoded = 0x000000AA
246+
// VMVNIMM inverts it => result = 0xFFFFFF55
247+
SDValue EncSD =
248+
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
249+
SDValue Op = DAG->getNode(ARMISD::VMVNIMM, DL, VT, EncSD);
250+
251+
// VMVNIMM creates ~constant, so all bits are known
252+
// Decoded (per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
253+
// Inverted (per-lane) = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
254+
// =>
255+
// Known.One = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
256+
// Known.Zero = 00000000 00000000 00000000 10101010 (0x000000AA)
257+
APInt DemandedElts = APInt::getAllOnes(4);
258+
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
259+
EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF55));
260+
EXPECT_EQ(Known.Zero, APInt(32, 0x000000AA));
261+
}
262+
263+
/// VMVNIMM with cmode=0x2 (16-bit shifted elements).
264+
/// imm8=0xAA, cmode=0x2 => decoded = 0x0000AA00, result = ~0x0000AA00.
265+
TEST_F(ARMSelectionDAGTest, computeKnownBits_VMVNIMM_cmode2) {
266+
SDLoc DL;
267+
EVT VT = MVT::v4i32;
268+
269+
// Encoded immediate: cmode=0x2, imm8=0xAA => decoded = 0x0000AA00
270+
// VMVNIMM inverts it => result = 0xFFFF55FF
271+
SDValue EncSD =
272+
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAA), DL, MVT::i32);
273+
SDValue Op = DAG->getNode(ARMISD::VMVNIMM, DL, VT, EncSD);
274+
275+
// Decoded (per-lane) = 00000000 00000000 10101010 00000000 (0x0000AA00)
276+
// Inverted (per-lane) = 11111111 11111111 01010101 11111111 (0xFFFF55FF)
277+
// =>
278+
// Known.One = 11111111 11111111 01010101 11111111 (0xFFFF55FF)
279+
// Known.Zero = 00000000 00000000 10101010 00000000 (0x0000AA00)
280+
APInt DemandedElts = APInt::getAllOnes(4);
281+
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
282+
EXPECT_EQ(Known.One, APInt(32, 0xFFFF55FF));
283+
EXPECT_EQ(Known.Zero, APInt(32, 0x0000AA00));
284+
}
285+
197286
} // end namespace llvm

0 commit comments

Comments
 (0)