//===----------------------------------------------------------------------===// // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "AArch64SelectionDAGInfo.h" #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/AsmParser/Parser.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" #include "gtest/gtest.h" namespace llvm { class AArch64SelectionDAGTest : public testing::Test { protected: static void SetUpTestCase() { LLVMInitializeAArch64TargetInfo(); LLVMInitializeAArch64Target(); LLVMInitializeAArch64TargetMC(); } void SetUp() override { StringRef Assembly = "define void @f() { ret void }"; Triple TargetTriple("aarch64--"); std::string Error; const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); TargetOptions Options; TM = std::unique_ptr( T->createTargetMachine(TargetTriple, "", "+sve", Options, std::nullopt, std::nullopt, CodeGenOptLevel::Aggressive)); SMDiagnostic SMError; M = parseAssemblyString(Assembly, SMError, Context); if (!M) report_fatal_error(SMError.getMessage()); M->setDataLayout(TM->createDataLayout()); F = M->getFunction("f"); if (!F) report_fatal_error("F?"); MachineModuleInfo MMI(TM.get()); MF = std::make_unique(*F, *TM, *TM->getSubtargetImpl(*F), MMI.getContext(), 0); DAG = std::make_unique(*TM, CodeGenOptLevel::None); if (!DAG) report_fatal_error("DAG?"); OptimizationRemarkEmitter ORE(F); DAG->init(*MF, ORE, nullptr, nullptr, nullptr, nullptr, nullptr, MMI, nullptr); } TargetLoweringBase::LegalizeTypeAction getTypeAction(EVT VT) { return DAG->getTargetLoweringInfo().getTypeAction(Context, VT); } EVT getTypeToTransformTo(EVT VT) { return DAG->getTargetLoweringInfo().getTypeToTransformTo(Context, VT); } LLVMContext Context; std::unique_ptr TM; std::unique_ptr M; Function *F; std::unique_ptr MF; std::unique_ptr DAG; }; TEST_F(AArch64SelectionDAGTest, computeKnownBits_ZERO_EXTEND_VECTOR_INREG) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int16VT = EVT::getIntegerVT(Context, 16); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4); auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2); auto InVec = DAG->getConstant(0, Loc, InVecVT); auto Op = DAG->getNode(ISD::ZERO_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); auto DemandedElts = APInt(2, 3); KnownBits Known = DAG->computeKnownBits(Op, DemandedElts); EXPECT_TRUE(Known.isZero()); } TEST_F(AArch64SelectionDAGTest, computeKnownBitsSVE_ZERO_EXTEND_VECTOR_INREG) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int16VT = EVT::getIntegerVT(Context, 16); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4, true); auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2, true); auto InVec = DAG->getConstant(0, Loc, InVecVT); auto Op = DAG->getNode(ISD::ZERO_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); auto DemandedElts = APInt(2, 3); KnownBits Known = DAG->computeKnownBits(Op, DemandedElts); // We don't know anything for SVE at the moment. EXPECT_EQ(Known.Zero, APInt(16, 0u)); EXPECT_EQ(Known.One, APInt(16, 0u)); EXPECT_FALSE(Known.isZero()); } TEST_F(AArch64SelectionDAGTest, computeKnownBits_EXTRACT_SUBVECTOR) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 3); auto IdxVT = EVT::getIntegerVT(Context, 64); auto Vec = DAG->getConstant(0, Loc, VecVT); auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); auto DemandedElts = APInt(3, 7); KnownBits Known = DAG->computeKnownBits(Op, DemandedElts); EXPECT_TRUE(Known.isZero()); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SIGN_EXTEND_VECTOR_INREG) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int16VT = EVT::getIntegerVT(Context, 16); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4); auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2); auto InVec = DAG->getConstant(1, Loc, InVecVT); auto Op = DAG->getNode(ISD::SIGN_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); auto DemandedElts = APInt(2, 3); EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 15u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBitsSVE_SIGN_EXTEND_VECTOR_INREG) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int16VT = EVT::getIntegerVT(Context, 16); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4, /*IsScalable=*/true); auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2, /*IsScalable=*/true); auto InVec = DAG->getConstant(1, Loc, InVecVT); auto Op = DAG->getNode(ISD::SIGN_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec); auto DemandedElts = APInt(2, 3); EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 1u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_EXTRACT_SUBVECTOR) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 3); auto IdxVT = EVT::getIntegerVT(Context, 64); auto Vec = DAG->getConstant(1, Loc, VecVT); auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); auto DemandedElts = APInt(3, 7); EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 7u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_VASHR) { SDLoc Loc; auto VecVT = MVT::v8i8; auto Shift = DAG->getConstant(4, Loc, MVT::i32); auto Vec0 = DAG->getConstant(1, Loc, VecVT); auto Op1 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec0, Shift); EXPECT_EQ(DAG->ComputeNumSignBits(Op1), 8u); auto VecA = DAG->getConstant(0xaa, Loc, VecVT); auto Op2 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, VecA, Shift); EXPECT_EQ(DAG->ComputeNumSignBits(Op2), 5u); // VASHR can't create undef/poison - FREEZE(VASHR(C1,C2)) -> VASHR(C1,C2). auto Fr2 = DAG->getFreeze(Op2); EXPECT_EQ(DAG->ComputeNumSignBits(Fr2), 5u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SUB) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto N0 = DAG->getConstant(0x00, Loc, IntVT); auto N1 = DAG->getConstant(0x01, Loc, IntVT); auto N5 = DAG->getConstant(0x05, Loc, IntVT); auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x1e, Loc, IntVT); auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); // RHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpRhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, Nsign1); EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); // Neg 0 // N0 = 00000000 auto OpNegZero = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N0); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); // Neg 1 // N0 = 00000000 // N1 = 00000001 auto OpNegOne = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); // Neg 5 // N0 = 00000000 // N5 = 00000101 auto OpNegFive = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N5); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegFive), 5u); // Non negative // N0 = 00000000 // Nsign3 = 000????0 auto OpNonNeg = DAG->getNode(ISD::SUB, Loc, IntVT, N0, Nsign3); EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); // LHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpLhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign1, Nsign3); EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); // Nsign3 = 000????0 // N5 = 00000101 auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, N5); EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); auto N0 = DAG->getConstant(0x00, Loc, IntVT); auto N1 = DAG->getConstant(0x01, Loc, IntVT); auto N5 = DAG->getConstant(0x05, Loc, IntVT); auto N8 = DAG->getConstant(0x08, Loc, IntVT); auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x1e, Loc, IntVT); auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); // RHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpRhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nsign1); EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); // ADD 0 -1 // N0 = 00000000 // Nneg1 = 11111111 auto OpNegZero = DAG->getNode(ISD::ADD, Loc, IntVT, N0, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); // ADD 1 -1 // N1 = 00000001 // Nneg1 = 11111111 auto OpNegOne = DAG->getNode(ISD::ADD, Loc, IntVT, N1, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); // ADD 8 -1 // N8 = 00001000 // Nneg1 = 11111111 auto OpSeven = DAG->getNode(ISD::ADD, Loc, IntVT, N8, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 5u); // Non negative // Nsign3 = 000????0 // Nneg1 = 11111111 auto OpNonNeg = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); // LHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpLhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign1, Nsign3); EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); // Nsign3 = 000????0 // N5 = 00000101 auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, N5); EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); } TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT); auto N0 = DAG->getConstant(0x00, Loc, IntVT); auto N1 = DAG->getConstant(0x01, Loc, IntVT); auto N5 = DAG->getConstant(0x05, Loc, IntVT); auto N8 = DAG->getConstant(0x08, Loc, IntVT); auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x1e, Loc, IntVT); auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); // RHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpRhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nsign1); EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u); // ADD 0 -1 // N0 = 00000000 // Nneg1 = 11111111 auto OpNegZero = DAG->getNode(ISD::ADDC, Loc, IntVT, N0, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u); // ADD 1 -1 // N1 = 00000001 // Nneg1 = 11111111 auto OpNegOne = DAG->getNode(ISD::ADDC, Loc, IntVT, N1, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u); // ADD 8 -1 // N8 = 00001000 // Nneg1 = 11111111 auto OpSeven = DAG->getNode(ISD::ADDC, Loc, IntVT, N8, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 4u); // Non negative // Nsign3 = 000????0 // Nneg1 = 11111111 auto OpNonNeg = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nneg1); EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u); // LHS early out // Nsign1 = 01010101 // Nsign3 = 000????0 auto OpLhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign1, Nsign3); EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u); // Nsign3 = 000????0 // N5 = 00000101 auto Op = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, N5); EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u); } TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 3); auto IdxVT = EVT::getIntegerVT(Context, 64); auto Vec = DAG->getConstant(1, Loc, VecVT); auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT); auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx); auto DemandedElts = APInt(3, 7); auto KnownUndef = APInt(3, 0); auto KnownZero = APInt(3, 0); TargetLowering::TargetLoweringOpt TLO(*DAG, false, false); EXPECT_EQ(TL.SimplifyDemandedVectorElts(Op, DemandedElts, KnownUndef, KnownZero, TLO), false); } TEST_F(AArch64SelectionDAGTest, SimplifyDemandedBitsNEON) { TargetLowering TL(*TM); SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 16); SDValue UnknownOp = DAG->getRegister(0, InVecVT); SDValue Mask1S = DAG->getConstant(0x8A, Loc, Int8VT); SDValue Mask1V = DAG->getSplatBuildVector(InVecVT, Loc, Mask1S); SDValue N0 = DAG->getNode(ISD::AND, Loc, InVecVT, Mask1V, UnknownOp); SDValue Mask2S = DAG->getConstant(0x55, Loc, Int8VT); SDValue Mask2V = DAG->getSplatBuildVector(InVecVT, Loc, Mask2S); SDValue Op = DAG->getNode(ISD::AND, Loc, InVecVT, N0, Mask2V); // N0 = ?000?0?0 // Mask2V = 01010101 // => // Known.Zero = 00100000 (0xAA) KnownBits Known; APInt DemandedBits = APInt(8, 0xFF); TargetLowering::TargetLoweringOpt TLO(*DAG, false, false); EXPECT_TRUE(TL.SimplifyDemandedBits(Op, DemandedBits, Known, TLO)); EXPECT_EQ(Known.Zero, APInt(8, 0xAA)); } TEST_F(AArch64SelectionDAGTest, SimplifyDemandedBitsSVE) { TargetLowering TL(*TM); SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto InVecVT = EVT::getVectorVT(Context, Int8VT, 16, /*IsScalable=*/true); SDValue UnknownOp = DAG->getRegister(0, InVecVT); SDValue Mask1S = DAG->getConstant(0x8A, Loc, Int8VT); SDValue Mask1V = DAG->getSplatVector(InVecVT, Loc, Mask1S); SDValue N0 = DAG->getNode(ISD::AND, Loc, InVecVT, Mask1V, UnknownOp); SDValue Mask2S = DAG->getConstant(0x55, Loc, Int8VT); SDValue Mask2V = DAG->getSplatVector(InVecVT, Loc, Mask2S); SDValue Op = DAG->getNode(ISD::AND, Loc, InVecVT, N0, Mask2V); // N0 = ?000?0?0 // Mask2V = 01010101 // => // Known.Zero = 00100000 (0xAA) KnownBits Known; APInt DemandedBits = APInt(8, 0xFF); TargetLowering::TargetLoweringOpt TLO(*DAG, false, false); EXPECT_TRUE(TL.SimplifyDemandedBits(Op, DemandedBits, Known, TLO)); EXPECT_EQ(Known.Zero, APInt(8, 0xAA)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_ADD) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x8A, Loc, IntVT); auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); auto N1 = DAG->getConstant(0x55, Loc, IntVT); auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, N0, N1); // N0 = ?000?0?0 // N1 = 01010101 // => // Known.One = 01010101 (0x55) // Known.Zero = 00100000 (0x20) KnownBits Known = DAG->computeKnownBits(Op); EXPECT_EQ(Known.Zero, APInt(8, 0x20)); EXPECT_EQ(Known.One, APInt(8, 0x55)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_UADDO_CARRY) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask_Zero = DAG->getConstant(0x28, Loc, IntVT); auto Mask_One = DAG->getConstant(0x20, Loc, IntVT); auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask_Zero, UnknownOp); N0 = DAG->getNode(ISD::OR, Loc, IntVT, Mask_One, N0); auto N1 = DAG->getConstant(0x65, Loc, IntVT); KnownBits Known; auto UnknownBorrow = DAG->getRegister(1, IntVT); auto OpUnknownBorrow = DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow); // N0 = 0010?000 // N1 = 01100101 // B = ? // => // Known.Zero = 01110000 (0x70) // Known.One = 10000100 (0x84) Known = DAG->computeKnownBits(OpUnknownBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0x70)); EXPECT_EQ(Known.One, APInt(8, 0x84)); auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT); auto OpZeroBorrow = DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow); // N0 = 0010?000 // N1 = 01100101 // B = 0 // => // Known.Zero = 01110010 (0x72) // Known.One = 10000101 (0x85) Known = DAG->computeKnownBits(OpZeroBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0x72)); EXPECT_EQ(Known.One, APInt(8, 0x85)); auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT); auto OpOneBorrow = DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, OneBorrow); // N0 = 0010?000 // N1 = 01100101 // B = 1 // => // Known.Zero = 01110001 (0x71) // Known.One = 10000110 (0x86) Known = DAG->computeKnownBits(OpOneBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0x71)); EXPECT_EQ(Known.One, APInt(8, 0x86)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. // Attempt to FREEZE the MOV/MVN nodes to show that they can still be analysed. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) { SDLoc Loc; auto IntSca32VT = MVT::i32; auto Int8Vec8VT = MVT::v8i8; auto Int16Vec8VT = MVT::v16i8; auto Int4Vec16VT = MVT::v4i16; auto Int8Vec16VT = MVT::v8i16; auto Int2Vec32VT = MVT::v2i32; auto Int4Vec32VT = MVT::v4i32; auto IntVec64VT = MVT::v1i64; auto Int2Vec64VT = MVT::v2i64; auto N165 = DAG->getConstant(0x000000A5, Loc, IntSca32VT); KnownBits Known; auto OpMOVIedit64 = DAG->getNode(AArch64ISD::MOVIedit, Loc, IntVec64VT, N165); Known = DAG->computeKnownBits(OpMOVIedit64); EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00)); EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF)); auto OpMOVIedit128 = DAG->getNode(AArch64ISD::MOVIedit, Loc, Int2Vec64VT, N165); Known = DAG->computeKnownBits(OpMOVIedit128); EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00)); EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF)); auto FrMOVIedit128 = DAG->getFreeze(OpMOVIedit128); Known = DAG->computeKnownBits(FrMOVIedit128); EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00)); EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF)); auto N264 = DAG->getConstant(264, Loc, IntSca32VT); auto OpMOVImsl64 = DAG->getNode(AArch64ISD::MOVImsl, Loc, Int2Vec32VT, N165, N264); Known = DAG->computeKnownBits(OpMOVImsl64); EXPECT_EQ(Known.Zero, APInt(32, 0xFFFF5A00)); EXPECT_EQ(Known.One, APInt(32, 0x0000A5FF)); auto N272 = DAG->getConstant(272, Loc, IntSca32VT); auto OpMOVImsl128 = DAG->getNode(AArch64ISD::MOVImsl, Loc, Int4Vec32VT, N165, N272); Known = DAG->computeKnownBits(OpMOVImsl128); EXPECT_EQ(Known.Zero, APInt(32, 0xFF5A0000)); EXPECT_EQ(Known.One, APInt(32, 0x00A5FFFF)); auto FrMOVImsl128 = DAG->getFreeze(OpMOVImsl128); Known = DAG->computeKnownBits(FrMOVImsl128); EXPECT_EQ(Known.Zero, APInt(32, 0xFF5A0000)); EXPECT_EQ(Known.One, APInt(32, 0x00A5FFFF)); auto OpMVNImsl64 = DAG->getNode(AArch64ISD::MVNImsl, Loc, Int2Vec32VT, N165, N272); Known = DAG->computeKnownBits(OpMVNImsl64); EXPECT_EQ(Known.Zero, APInt(32, 0x00A5FFFF)); EXPECT_EQ(Known.One, APInt(32, 0xFF5A0000)); auto OpMVNImsl128 = DAG->getNode(AArch64ISD::MVNImsl, Loc, Int4Vec32VT, N165, N264); Known = DAG->computeKnownBits(OpMVNImsl128); EXPECT_EQ(Known.Zero, APInt(32, 0x0000A5FF)); EXPECT_EQ(Known.One, APInt(32, 0xFFFF5A00)); auto FrMVNImsl128 = DAG->getFreeze(OpMVNImsl128); Known = DAG->computeKnownBits(FrMVNImsl128); EXPECT_EQ(Known.Zero, APInt(32, 0x0000A5FF)); EXPECT_EQ(Known.One, APInt(32, 0xFFFF5A00)); auto N0 = DAG->getConstant(0, Loc, IntSca32VT); auto OpMOVIshift2Vec32 = DAG->getNode(AArch64ISD::MOVIshift, Loc, Int2Vec32VT, N165, N0); Known = DAG->computeKnownBits(OpMOVIshift2Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0xFFFFFF5A)); EXPECT_EQ(Known.One, APInt(32, 0x000000A5)); auto N24 = DAG->getConstant(24, Loc, IntSca32VT); auto OpMOVIshift4Vec32 = DAG->getNode(AArch64ISD::MOVIshift, Loc, Int4Vec32VT, N165, N24); Known = DAG->computeKnownBits(OpMOVIshift4Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0x5AFFFFFF)); EXPECT_EQ(Known.One, APInt(32, 0xA5000000)); auto FrMOVIshift4Vec32 = DAG->getFreeze(OpMOVIshift4Vec32); Known = DAG->computeKnownBits(FrMOVIshift4Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0x5AFFFFFF)); EXPECT_EQ(Known.One, APInt(32, 0xA5000000)); auto OpMVNIshift2Vec32 = DAG->getNode(AArch64ISD::MVNIshift, Loc, Int2Vec32VT, N165, N24); Known = DAG->computeKnownBits(OpMVNIshift2Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0xA5000000)); EXPECT_EQ(Known.One, APInt(32, 0x5AFFFFFF)); auto OpMVNIshift4Vec32 = DAG->getNode(AArch64ISD::MVNIshift, Loc, Int4Vec32VT, N165, N0); Known = DAG->computeKnownBits(OpMVNIshift4Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0x000000A5)); EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF5A)); auto FrMVNIshift4Vec32 = DAG->getFreeze(OpMVNIshift4Vec32); Known = DAG->computeKnownBits(FrMVNIshift4Vec32); EXPECT_EQ(Known.Zero, APInt(32, 0x000000A5)); EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF5A)); auto N8 = DAG->getConstant(8, Loc, IntSca32VT); auto OpMOVIshift4Vec16 = DAG->getNode(AArch64ISD::MOVIshift, Loc, Int4Vec16VT, N165, N0); Known = DAG->computeKnownBits(OpMOVIshift4Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0xFF5A)); EXPECT_EQ(Known.One, APInt(16, 0x00A5)); auto OpMOVIshift8Vec16 = DAG->getNode(AArch64ISD::MOVIshift, Loc, Int8Vec16VT, N165, N8); Known = DAG->computeKnownBits(OpMOVIshift8Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0x5AFF)); EXPECT_EQ(Known.One, APInt(16, 0xA500)); auto FrMOVIshift8Vec16 = DAG->getFreeze(OpMOVIshift8Vec16); Known = DAG->computeKnownBits(FrMOVIshift8Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0x5AFF)); EXPECT_EQ(Known.One, APInt(16, 0xA500)); auto OpMVNIshift4Vec16 = DAG->getNode(AArch64ISD::MVNIshift, Loc, Int4Vec16VT, N165, N8); Known = DAG->computeKnownBits(OpMVNIshift4Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0xA500)); EXPECT_EQ(Known.One, APInt(16, 0x5AFF)); auto OpMVNIshift8Vec16 = DAG->getNode(AArch64ISD::MVNIshift, Loc, Int8Vec16VT, N165, N0); Known = DAG->computeKnownBits(OpMVNIshift8Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0x00A5)); EXPECT_EQ(Known.One, APInt(16, 0xFF5A)); auto FrMVNIshift8Vec16 = DAG->getFreeze(OpMVNIshift8Vec16); Known = DAG->computeKnownBits(FrMVNIshift8Vec16); EXPECT_EQ(Known.Zero, APInt(16, 0x00A5)); EXPECT_EQ(Known.One, APInt(16, 0xFF5A)); auto OpMOVI8Vec8 = DAG->getNode(AArch64ISD::MOVI, Loc, Int8Vec8VT, N165); Known = DAG->computeKnownBits(OpMOVI8Vec8); EXPECT_EQ(Known.Zero, APInt(8, 0x5A)); EXPECT_EQ(Known.One, APInt(8, 0xA5)); auto OpMOVI16Vec8 = DAG->getNode(AArch64ISD::MOVI, Loc, Int16Vec8VT, N165); Known = DAG->computeKnownBits(OpMOVI16Vec8); EXPECT_EQ(Known.Zero, APInt(8, 0x5A)); EXPECT_EQ(Known.One, APInt(8, 0xA5)); auto FrMOVI16Vec8 = DAG->getFreeze(OpMOVI16Vec8); Known = DAG->computeKnownBits(FrMOVI16Vec8); EXPECT_EQ(Known.Zero, APInt(8, 0x5A)); EXPECT_EQ(Known.One, APInt(8, 0xA5)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto N0 = DAG->getConstant(0x55, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); auto Mask = DAG->getConstant(0x2e, Loc, IntVT); auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp); auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); // N0 = 01010101 // N1 = 00?0???0 // => // Known.One = 00000001 (0x1) // Known.Zero = 10000000 (0x80) KnownBits Known = DAG->computeKnownBits(Op); EXPECT_EQ(Known.Zero, APInt(8, 0x80)); EXPECT_EQ(Known.One, APInt(8, 0x1)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_USUBO_CARRY) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto N0 = DAG->getConstant(0x5a, Loc, IntVT); auto UnknownOp = DAG->getRegister(0, IntVT); // ???????? auto Mask1_Zero = DAG->getConstant(0x8, Loc, IntVT); // 00001000 auto Mask1_One = DAG->getConstant(0x20, Loc, IntVT); // 00100000 // N1 = (???????? & 00001000) | 00100000 = 0010?000 auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask1_Zero, UnknownOp); N1 = DAG->getNode(ISD::OR, Loc, IntVT, Mask1_One, N1); KnownBits Known; auto UnknownBorrow = DAG->getRegister(1, IntVT); auto OpUnknownBorrow = DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow); // N0 = 01011010 // N1 = 0010?000 // B = ? // => // Known.Zero = 11000100 (0xc4) // Known.One = 00110000 (0x30) Known = DAG->computeKnownBits(OpUnknownBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0xc4)); EXPECT_EQ(Known.One, APInt(8, 0x30)); auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT); auto OpZeroBorrow = DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow); // N0 = 01011010 // N1 = 0010?000 // B = 0 // => // Known.Zero = 11000101 (0xc5) // Known.One = 00110010 (0x32) Known = DAG->computeKnownBits(OpZeroBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0xc5)); EXPECT_EQ(Known.One, APInt(8, 0x32)); auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT); auto OpOneBorrow = DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, OneBorrow); // N0 = 01011010 // N1 = 0010?000 // B = 1 // => // Known.Zero = 11000110 (0xc6) // Known.One = 00110001 (0x31) Known = DAG->computeKnownBits(OpOneBorrow); EXPECT_EQ(Known.Zero, APInt(8, 0xc6)); EXPECT_EQ(Known.One, APInt(8, 0x31)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VASHR) { SDLoc Loc; KnownBits Known; auto VecVT = MVT::v8i8; auto Shift0 = DAG->getConstant(4, Loc, MVT::i32); auto Vec0 = DAG->getConstant(0x80, Loc, VecVT); auto Op0 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec0, Shift0); Known = DAG->computeKnownBits(Op0); EXPECT_EQ(Known.Zero, APInt(8, 0x07)); EXPECT_EQ(Known.One, APInt(8, 0xF8)); auto Shift1 = DAG->getConstant(7, Loc, MVT::i32); auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT); auto Op1 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec1, Shift1); Known = DAG->computeKnownBits(Op1); EXPECT_EQ(Known.Zero, APInt(8, 0x00)); EXPECT_EQ(Known.One, APInt(8, 0xFF)); auto Fr1 = DAG->getFreeze(Op1); Known = DAG->computeKnownBits(Fr1); EXPECT_EQ(Known.Zero, APInt(8, 0x00)); EXPECT_EQ(Known.One, APInt(8, 0xFF)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VLSHR) { SDLoc Loc; KnownBits Known; auto VecVT = MVT::v8i8; auto Shift0 = DAG->getConstant(4, Loc, MVT::i32); auto Vec0 = DAG->getConstant(0x80, Loc, VecVT); auto Op0 = DAG->getNode(AArch64ISD::VLSHR, Loc, VecVT, Vec0, Shift0); Known = DAG->computeKnownBits(Op0); EXPECT_EQ(Known.Zero, APInt(8, 0xF7)); EXPECT_EQ(Known.One, APInt(8, 0x08)); auto Shift1 = DAG->getConstant(7, Loc, MVT::i32); auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT); auto Op1 = DAG->getNode(AArch64ISD::VLSHR, Loc, VecVT, Vec1, Shift1); Known = DAG->computeKnownBits(Op1); EXPECT_EQ(Known.Zero, APInt(8, 0xFE)); EXPECT_EQ(Known.One, APInt(8, 0x1)); auto Fr1 = DAG->getFreeze(Op1); Known = DAG->computeKnownBits(Fr1); EXPECT_EQ(Known.Zero, APInt(8, 0xFE)); EXPECT_EQ(Known.One, APInt(8, 0x1)); } // Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits. TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VSHL) { SDLoc Loc; KnownBits Known; auto VecVT = MVT::v8i8; auto Shift0 = DAG->getConstant(4, Loc, MVT::i32); auto Vec0 = DAG->getConstant(0x02, Loc, VecVT); auto Op0 = DAG->getNode(AArch64ISD::VSHL, Loc, VecVT, Vec0, Shift0); Known = DAG->computeKnownBits(Op0); EXPECT_EQ(Known.Zero, APInt(8, 0xDF)); EXPECT_EQ(Known.One, APInt(8, 0x20)); auto Shift1 = DAG->getConstant(7, Loc, MVT::i32); auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT); auto Op1 = DAG->getNode(AArch64ISD::VSHL, Loc, VecVT, Vec1, Shift1); Known = DAG->computeKnownBits(Op1); EXPECT_EQ(Known.Zero, APInt(8, 0x7F)); EXPECT_EQ(Known.One, APInt(8, 0x80)); auto Fr1 = DAG->getFreeze(Op1); Known = DAG->computeKnownBits(Fr1); EXPECT_EQ(Known.Zero, APInt(8, 0x7F)); EXPECT_EQ(Known.One, APInt(8, 0x80)); } TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_BUILD_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); // Create a BUILD_VECTOR SDValue Op = DAG->getConstant(1, Loc, VecVT); EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR); EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); APInt UndefElts; APInt DemandedElts; EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); // Width=16, Mask=3 DemandedElts = APInt(16, 3); EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); } TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_ADD_of_BUILD_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); // Should create BUILD_VECTORs SDValue Val1 = DAG->getConstant(1, Loc, VecVT); SDValue Val2 = DAG->getConstant(3, Loc, VecVT); EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR); SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); APInt UndefElts; APInt DemandedElts; EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); // Width=16, Mask=3 DemandedElts = APInt(16, 3); EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); } TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_SPLAT_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); // Create a SPLAT_VECTOR SDValue Op = DAG->getConstant(1, Loc, VecVT); EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR); EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); APInt UndefElts; APInt DemandedElts(1, 1); EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); } TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_ADD_of_SPLAT_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); // Should create SPLAT_VECTORS SDValue Val1 = DAG->getConstant(1, Loc, VecVT); SDValue Val2 = DAG->getConstant(3, Loc, VecVT); EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR); SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false)); APInt UndefElts; APInt DemandedElts(1, 1); EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts)); } TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Fixed_BUILD_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); // Create a BUILD_VECTOR SDValue Op = DAG->getConstant(1, Loc, VecVT); EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR); int SplatIdx = -1; EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); EXPECT_EQ(SplatIdx, 0); } TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Fixed_ADD_of_BUILD_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false); // Should create BUILD_VECTORs SDValue Val1 = DAG->getConstant(1, Loc, VecVT); SDValue Val2 = DAG->getConstant(3, Loc, VecVT); EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR); SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); int SplatIdx = -1; EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); EXPECT_EQ(SplatIdx, 0); } TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Scalable_SPLAT_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); // Create a SPLAT_VECTOR SDValue Op = DAG->getConstant(1, Loc, VecVT); EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR); int SplatIdx = -1; EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); EXPECT_EQ(SplatIdx, 0); } TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Scalable_ADD_of_SPLAT_VECTOR) { TargetLowering TL(*TM); SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true); // Should create SPLAT_VECTORS SDValue Val1 = DAG->getConstant(1, Loc, VecVT); SDValue Val2 = DAG->getConstant(3, Loc, VecVT); EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR); SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2); int SplatIdx = -1; EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op); EXPECT_EQ(SplatIdx, 0); } TEST_F(AArch64SelectionDAGTest, getRepeatedSequence_Patterns) { TargetLowering TL(*TM); SDLoc Loc; unsigned NumElts = 16; MVT IntVT = MVT::i8; MVT VecVT = MVT::getVectorVT(IntVT, NumElts); // Base scalar constants. SDValue Val0 = DAG->getConstant(0, Loc, IntVT); SDValue Val1 = DAG->getConstant(1, Loc, IntVT); SDValue Val2 = DAG->getConstant(2, Loc, IntVT); SDValue Val3 = DAG->getConstant(3, Loc, IntVT); SDValue UndefVal = DAG->getUNDEF(IntVT); // Build some repeating sequences. SmallVector Pattern1111, Pattern1133, Pattern0123; for (int I = 0; I != 4; ++I) { Pattern1111.append(4, Val1); Pattern1133.append(2, Val1); Pattern1133.append(2, Val3); Pattern0123.push_back(Val0); Pattern0123.push_back(Val1); Pattern0123.push_back(Val2); Pattern0123.push_back(Val3); } // Build a non-pow2 repeating sequence. SmallVector Pattern022; Pattern022.push_back(Val0); Pattern022.append(2, Val2); Pattern022.push_back(Val0); Pattern022.append(2, Val2); Pattern022.push_back(Val0); Pattern022.append(2, Val2); Pattern022.push_back(Val0); Pattern022.append(2, Val2); Pattern022.push_back(Val0); Pattern022.append(2, Val2); Pattern022.push_back(Val0); // Build a non-repeating sequence. SmallVector Pattern1_3; Pattern1_3.append(8, Val1); Pattern1_3.append(8, Val3); // Add some undefs to make it trickier. Pattern1111[1] = Pattern1111[2] = Pattern1111[15] = UndefVal; Pattern1133[0] = Pattern1133[2] = UndefVal; auto *BV1111 = cast(DAG->getBuildVector(VecVT, Loc, Pattern1111)); auto *BV1133 = cast(DAG->getBuildVector(VecVT, Loc, Pattern1133)); auto *BV0123 = cast(DAG->getBuildVector(VecVT, Loc, Pattern0123)); auto *BV022 = cast(DAG->getBuildVector(VecVT, Loc, Pattern022)); auto *BV1_3 = cast(DAG->getBuildVector(VecVT, Loc, Pattern1_3)); // Check for sequences. SmallVector Seq1111, Seq1133, Seq0123, Seq022, Seq1_3; BitVector Undefs1111, Undefs1133, Undefs0123, Undefs022, Undefs1_3; EXPECT_TRUE(BV1111->getRepeatedSequence(Seq1111, &Undefs1111)); EXPECT_EQ(Undefs1111.count(), 3u); EXPECT_EQ(Seq1111.size(), 1u); EXPECT_EQ(Seq1111[0], Val1); EXPECT_TRUE(BV1133->getRepeatedSequence(Seq1133, &Undefs1133)); EXPECT_EQ(Undefs1133.count(), 2u); EXPECT_EQ(Seq1133.size(), 4u); EXPECT_EQ(Seq1133[0], Val1); EXPECT_EQ(Seq1133[1], Val1); EXPECT_EQ(Seq1133[2], Val3); EXPECT_EQ(Seq1133[3], Val3); EXPECT_TRUE(BV0123->getRepeatedSequence(Seq0123, &Undefs0123)); EXPECT_EQ(Undefs0123.count(), 0u); EXPECT_EQ(Seq0123.size(), 4u); EXPECT_EQ(Seq0123[0], Val0); EXPECT_EQ(Seq0123[1], Val1); EXPECT_EQ(Seq0123[2], Val2); EXPECT_EQ(Seq0123[3], Val3); EXPECT_FALSE(BV022->getRepeatedSequence(Seq022, &Undefs022)); EXPECT_FALSE(BV1_3->getRepeatedSequence(Seq1_3, &Undefs1_3)); // Try again with DemandedElts masks. APInt Mask1111_0 = APInt::getOneBitSet(NumElts, 0); EXPECT_TRUE(BV1111->getRepeatedSequence(Mask1111_0, Seq1111, &Undefs1111)); EXPECT_EQ(Undefs1111.count(), 0u); EXPECT_EQ(Seq1111.size(), 1u); EXPECT_EQ(Seq1111[0], Val1); APInt Mask1111_1 = APInt::getOneBitSet(NumElts, 2); EXPECT_TRUE(BV1111->getRepeatedSequence(Mask1111_1, Seq1111, &Undefs1111)); EXPECT_EQ(Undefs1111.count(), 1u); EXPECT_EQ(Seq1111.size(), 1u); EXPECT_EQ(Seq1111[0], UndefVal); APInt Mask0123 = APInt(NumElts, 0x7777); EXPECT_TRUE(BV0123->getRepeatedSequence(Mask0123, Seq0123, &Undefs0123)); EXPECT_EQ(Undefs0123.count(), 0u); EXPECT_EQ(Seq0123.size(), 4u); EXPECT_EQ(Seq0123[0], Val0); EXPECT_EQ(Seq0123[1], Val1); EXPECT_EQ(Seq0123[2], Val2); EXPECT_EQ(Seq0123[3], SDValue()); APInt Mask1_3 = APInt::getHighBitsSet(16, 8); EXPECT_TRUE(BV1_3->getRepeatedSequence(Mask1_3, Seq1_3, &Undefs1_3)); EXPECT_EQ(Undefs1_3.count(), 0u); EXPECT_EQ(Seq1_3.size(), 1u); EXPECT_EQ(Seq1_3[0], Val3); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableMVT) { MVT VT = MVT::nxv4i64; EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector); ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_PromoteScalableMVT) { MVT VT = MVT::nxv2i32; EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypePromoteInteger); ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_NoScalarizeMVT_nxv1f32) { MVT VT = MVT::nxv1f32; EXPECT_NE(getTypeAction(VT), TargetLoweringBase::TypeScalarizeVector); ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector()); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableEVT) { EVT VT = EVT::getVectorVT(Context, MVT::i64, 256, true); EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector); EXPECT_EQ(getTypeToTransformTo(VT), VT.getHalfNumVectorElementsVT(Context)); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_WidenScalableEVT) { EVT FromVT = EVT::getVectorVT(Context, MVT::i64, 6, true); EVT ToVT = EVT::getVectorVT(Context, MVT::i64, 8, true); EXPECT_EQ(getTypeAction(FromVT), TargetLoweringBase::TypeWidenVector); EXPECT_EQ(getTypeToTransformTo(FromVT), ToVT); } TEST_F(AArch64SelectionDAGTest, getTypeConversion_ScalarizeScalableEVT_nxv1f128) { EVT VT = EVT::getVectorVT(Context, MVT::f128, ElementCount::getScalable(1)); EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeScalarizeScalableVector); EXPECT_EQ(getTypeToTransformTo(VT), MVT::f128); } TEST_F(AArch64SelectionDAGTest, TestFold_STEP_VECTOR) { SDLoc Loc; auto IntVT = EVT::getIntegerVT(Context, 8); auto VecVT = EVT::getVectorVT(Context, MVT::i8, 16, true); // Should create SPLAT_VECTOR SDValue Zero = DAG->getConstant(0, Loc, IntVT); SDValue Op = DAG->getNode(ISD::STEP_VECTOR, Loc, VecVT, Zero); EXPECT_EQ(Op.getOpcode(), ISD::SPLAT_VECTOR); } TEST_F(AArch64SelectionDAGTest, ReplaceAllUsesWith) { SDLoc Loc; EVT IntVT = EVT::getIntegerVT(Context, 8); SDValue N0 = DAG->getConstant(0x42, Loc, IntVT); SDValue N1 = DAG->getRegister(0, IntVT); // Construct node to fill arbitrary ExtraInfo. SDValue N2 = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1); EXPECT_FALSE(DAG->getHeapAllocSite(N2.getNode())); EXPECT_FALSE(DAG->getNoMergeSiteInfo(N2.getNode())); EXPECT_FALSE(DAG->getPCSections(N2.getNode())); MDNode *MD = MDNode::get(Context, {}); DAG->addHeapAllocSite(N2.getNode(), MD); DAG->addNoMergeSiteInfo(N2.getNode(), true); DAG->addPCSections(N2.getNode(), MD); EXPECT_EQ(DAG->getHeapAllocSite(N2.getNode()), MD); EXPECT_TRUE(DAG->getNoMergeSiteInfo(N2.getNode())); EXPECT_EQ(DAG->getPCSections(N2.getNode()), MD); SDValue Root = DAG->getNode(ISD::ADD, Loc, IntVT, N2, N2); EXPECT_EQ(Root->getOperand(0)->getOpcode(), ISD::SUB); // Create new node and check that ExtraInfo is propagated on RAUW. SDValue New = DAG->getNode(ISD::ADD, Loc, IntVT, N1, N1); EXPECT_FALSE(DAG->getHeapAllocSite(New.getNode())); EXPECT_FALSE(DAG->getNoMergeSiteInfo(New.getNode())); EXPECT_FALSE(DAG->getPCSections(New.getNode())); DAG->ReplaceAllUsesWith(N2, New); EXPECT_EQ(Root->getOperand(0), New); EXPECT_EQ(DAG->getHeapAllocSite(New.getNode()), MD); EXPECT_TRUE(DAG->getNoMergeSiteInfo(New.getNode())); EXPECT_EQ(DAG->getPCSections(New.getNode()), MD); } TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_known01) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int32VT = EVT::getIntegerVT(Context, 32); auto Int64VT = EVT::getIntegerVT(Context, 64); auto Ptr = DAG->getConstant(0, Loc, Int64VT); auto PtrInfo = MachinePointerInfo::getFixedStack(DAG->getMachineFunction(), 0); AAMDNodes AA; MDBuilder MDHelper(*DAG->getContext()); MDNode *Range = MDHelper.createRange(APInt(8, 0), APInt(8, 2)); MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand( PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range); auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); KnownBits Known = DAG->computeKnownBits(ALoad); EXPECT_EQ(Known.Zero, APInt(32, 0xfe)); EXPECT_EQ(Known.One, APInt(32, 0)); auto ZLoad = DAG->getExtLoad(ISD::ZEXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); Known = DAG->computeKnownBits(ZLoad); EXPECT_EQ(Known.Zero, APInt(32, 0xfffffffe)); EXPECT_EQ(Known.One, APInt(32, 0)); auto SLoad = DAG->getExtLoad(ISD::SEXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); Known = DAG->computeKnownBits(SLoad); EXPECT_EQ(Known.Zero, APInt(32, 0xfffffffe)); EXPECT_EQ(Known.One, APInt(32, 0)); } TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_knownnegative) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int32VT = EVT::getIntegerVT(Context, 32); auto Int64VT = EVT::getIntegerVT(Context, 64); auto Ptr = DAG->getConstant(0, Loc, Int64VT); auto PtrInfo = MachinePointerInfo::getFixedStack(DAG->getMachineFunction(), 0); AAMDNodes AA; MDBuilder MDHelper(*DAG->getContext()); MDNode *Range = MDHelper.createRange(APInt(8, 0xf0), APInt(8, 0xff)); MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand( PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range); auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); KnownBits Known = DAG->computeKnownBits(ALoad); EXPECT_EQ(Known.Zero, APInt(32, 0)); EXPECT_EQ(Known.One, APInt(32, 0xf0)); auto ZLoad = DAG->getExtLoad(ISD::ZEXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); Known = DAG->computeKnownBits(ZLoad); EXPECT_EQ(Known.Zero, APInt(32, 0xffffff00)); EXPECT_EQ(Known.One, APInt(32, 0x000000f0)); auto SLoad = DAG->getExtLoad(ISD::SEXTLOAD, Loc, Int32VT, DAG->getEntryNode(), Ptr, Int8VT, MMO); Known = DAG->computeKnownBits(SLoad); EXPECT_EQ(Known.Zero, APInt(32, 0)); EXPECT_EQ(Known.One, APInt(32, 0xfffffff0)); } TEST_F(AArch64SelectionDAGTest, computeKnownBits_AVGFLOORU_AVGFLOORS_AVGCEILU_AVGCEILS) { SDLoc Loc; auto Int8VT = EVT::getIntegerVT(Context, 8); auto Int16VT = EVT::getIntegerVT(Context, 16); auto Int8Vec8VT = EVT::getVectorVT(Context, Int8VT, 8); auto Int16Vec8VT = EVT::getVectorVT(Context, Int16VT, 8); SDValue UnknownOp0 = DAG->getRegister(0, Int8Vec8VT); SDValue UnknownOp1 = DAG->getRegister(1, Int8Vec8VT); SDValue ZextOp0 = DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp0); SDValue ZextOp1 = DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp1); // ZextOp0 = 00000000???????? // ZextOp1 = 00000000???????? // => (for all AVG* instructions) // Known.Zero = 1111111100000000 (0xFF00) // Known.One = 0000000000000000 (0x0000) auto Zeroes = APInt(16, 0xFF00); auto Ones = APInt(16, 0x0000); SDValue AVGFLOORU = DAG->getNode(ISD::AVGFLOORU, Loc, Int16Vec8VT, ZextOp0, ZextOp1); KnownBits KnownAVGFLOORU = DAG->computeKnownBits(AVGFLOORU); EXPECT_EQ(KnownAVGFLOORU.Zero, Zeroes); EXPECT_EQ(KnownAVGFLOORU.One, Ones); SDValue AVGFLOORS = DAG->getNode(ISD::AVGFLOORS, Loc, Int16Vec8VT, ZextOp0, ZextOp1); KnownBits KnownAVGFLOORS = DAG->computeKnownBits(AVGFLOORS); EXPECT_EQ(KnownAVGFLOORS.Zero, Zeroes); EXPECT_EQ(KnownAVGFLOORS.One, Ones); SDValue AVGCEILU = DAG->getNode(ISD::AVGCEILU, Loc, Int16Vec8VT, ZextOp0, ZextOp1); KnownBits KnownAVGCEILU = DAG->computeKnownBits(AVGCEILU); EXPECT_EQ(KnownAVGCEILU.Zero, Zeroes); EXPECT_EQ(KnownAVGCEILU.One, Ones); SDValue AVGCEILS = DAG->getNode(ISD::AVGCEILS, Loc, Int16Vec8VT, ZextOp0, ZextOp1); KnownBits KnownAVGCEILS = DAG->computeKnownBits(AVGCEILS); EXPECT_EQ(KnownAVGCEILS.Zero, Zeroes); EXPECT_EQ(KnownAVGCEILS.One, Ones); } } // end namespace llvm