diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 2d26c67a8077a..1f85765167138 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -19863,7 +19863,31 @@ 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; + + APInt Imm(DecEltBits, DecodedVal); + + if (Op.getOpcode() == ARMISD::VMVNIMM) + Imm.flipAllBits(); + + Known = KnownBits::makeConstant(Imm); + break; } + } +} + +bool ARMTargetLowering::isTargetCanonicalConstantNode(SDValue Op) const { + return Op.getOpcode() == ARMISD::VMOVIMM || + Op.getOpcode() == ARMISD::VMVNIMM || + TargetLowering::isTargetCanonicalConstantNode(Op); } bool ARMTargetLowering::targetShrinkDemandedConstant( 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..852e07d5c24f1 100644 --- a/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp +++ b/llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp @@ -194,4 +194,36 @@ 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. +TEST_F(ARMSelectionDAGTest, computeKnownBits_VMOVIMM) { + SDLoc DL; + EVT VT = MVT::v4i32; + + SDValue EncSD = + DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), 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, 0x000000AA)); + EXPECT_EQ(Known.Zero, APInt(32, 0xFFFFFF55)); +} + +/// VMVNIMM: Move NOT immediate to vector register. +/// cmode=0x0 puts imm8 in byte0 => decoded = 0x000000AA, result = ~0x000000AA. +TEST_F(ARMSelectionDAGTest, computeKnownBits_VMVNIMM) { + SDLoc DL; + EVT VT = MVT::v4i32; + + SDValue EncSD = + DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32); + SDValue Op = DAG->getNode(ARMISD::VMVNIMM, DL, VT, EncSD); + + 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)); +} + } // end namespace llvm