//===- CSETest.cpp -----------------------------------------------===// // // 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 "GISelMITest.h" #include "llvm/CodeGen/GlobalISel/CSEInfo.h" #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" #include "gtest/gtest.h" namespace { TEST_F(AArch64GISelMITest, TestCSE) { setUp(); if (!TM) GTEST_SKIP(); LLT s16{LLT::scalar(16)}; LLT s32{LLT::scalar(32)}; auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[1]}); auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); CSEB.setInsertPt(B.getMBB(), B.getInsertPt()); Register AddReg = MRI->createGenericVirtualRegister(s16); auto MIBAddCopy = CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput}); EXPECT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); auto MIBAdd2 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); EXPECT_TRUE(&*MIBAdd == &*MIBAdd2); auto MIBAdd4 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); EXPECT_TRUE(&*MIBAdd == &*MIBAdd4); auto MIBAdd5 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1}); EXPECT_TRUE(&*MIBAdd != &*MIBAdd5); // Try building G_CONSTANTS. auto MIBCst = CSEB.buildConstant(s32, 0); auto MIBCst1 = CSEB.buildConstant(s32, 0); EXPECT_TRUE(&*MIBCst == &*MIBCst1); // Try the CFing of BinaryOps. auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst}); EXPECT_TRUE(&*MIBCF1 == &*MIBCst); // Try out building FCONSTANTs. auto MIBFP0 = CSEB.buildFConstant(s32, 1.0); auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0); EXPECT_TRUE(&*MIBFP0 == &*MIBFP0_1); CSEInfo.print(); // Make sure buildConstant with a vector type doesn't crash, and the elements // CSE. auto Splat0 = CSEB.buildConstant(LLT::fixed_vector(2, s32), 0); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, Splat0->getOpcode()); EXPECT_EQ(Splat0.getReg(1), Splat0.getReg(2)); EXPECT_EQ(&*MIBCst, MRI->getVRegDef(Splat0.getReg(1))); auto FSplat = CSEB.buildFConstant(LLT::fixed_vector(2, s32), 1.0); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, FSplat->getOpcode()); EXPECT_EQ(FSplat.getReg(1), FSplat.getReg(2)); EXPECT_EQ(&*MIBFP0, MRI->getVRegDef(FSplat.getReg(1))); // Check G_UNMERGE_VALUES auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]); auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]); EXPECT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); // Check G_FADD { auto MIBFAdd = CSEB.buildFAdd(s32, Copies[0], Copies[1]); auto MIBFAdd2 = CSEB.buildFAdd(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFAdd == &*MIBFAdd2); auto MIBFAdd3 = CSEB.buildFAdd(s32, Copies[0], Copies[1], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFAdd == &*MIBFAdd3); MIBFAdd2->setFlag(MachineInstr::FmNsz); MIBFAdd2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFAdd == &*MIBFAdd2); } // Check G_FSUB { auto MIBFSub = CSEB.buildFSub(s32, Copies[0], Copies[1]); auto MIBFSub2 = CSEB.buildFSub(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFSub == &*MIBFSub2); auto MIBFSub3 = CSEB.buildFSub(s32, Copies[0], Copies[1], MachineInstr::FmNoNans); EXPECT_FALSE(&*MIBFSub == &*MIBFSub3); MIBFSub2->setFlag(MachineInstr::FmNoNans); MIBFSub2->clearFlag(MachineInstr::FmNoNans); EXPECT_TRUE(&*MIBFSub == &*MIBFSub2); } // Check G_FMUL { auto MIBFMul = CSEB.buildFMul(s32, Copies[0], Copies[1]); auto MIBFMul2 = CSEB.buildFMul(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFMul == &*MIBFMul2); auto MIBFMul3 = CSEB.buildFMul(s32, Copies[0], Copies[1], MachineInstr::FmNoNans); EXPECT_FALSE(&*MIBFMul == &*MIBFMul3); MIBFMul2->setFlag(MachineInstr::FmNoNans); MIBFMul2->clearFlag(MachineInstr::FmNoNans); EXPECT_TRUE(&*MIBFMul == &*MIBFMul2); } // Check G_FDIV { auto MIBFDiv = CSEB.buildFDiv(s32, Copies[0], Copies[1]); auto MIBFDiv2 = CSEB.buildFDiv(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFDiv == &*MIBFDiv2); auto MIBFDiv3 = CSEB.buildFDiv(s32, Copies[0], Copies[1], MachineInstr::FmNoNans); EXPECT_FALSE(&*MIBFDiv == &*MIBFDiv3); MIBFDiv2->setFlag(MachineInstr::FmNoNans); MIBFDiv2->clearFlag(MachineInstr::FmNoNans); EXPECT_TRUE(&*MIBFDiv == &*MIBFDiv2); } // Check G_FABS { auto MIBFAbs = CSEB.buildFAbs(s32, Copies[0]); auto MIBFAbs2 = CSEB.buildFAbs(s32, Copies[0]); EXPECT_TRUE(&*MIBFAbs == &*MIBFAbs2); auto MIBFAbs3 = CSEB.buildFAbs(s32, Copies[0], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFAbs == &*MIBFAbs3); MIBFAbs2->setFlag(MachineInstr::FmNsz); MIBFAbs2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFAbs == &*MIBFAbs2); } // Check G_FMINNUM/F_MAXNUM: { auto MIBFMinNum = CSEB.buildFMinNum(s32, Copies[0], Copies[1]); auto MIBFMinNum2 = CSEB.buildFMinNum(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFMinNum == &*MIBFMinNum2); auto MIBFMinNum3 = CSEB.buildFMinNum(s32, Copies[0], Copies[1], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFMinNum == &*MIBFMinNum3); MIBFMinNum2->setFlag(MachineInstr::FmNsz); MIBFMinNum2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFMinNum == &*MIBFMinNum2); } { auto MIBFMaxNum = CSEB.buildFMaxNum(s32, Copies[0], Copies[1]); auto MIBFMaxNum2 = CSEB.buildFMaxNum(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFMaxNum == &*MIBFMaxNum2); auto MIBFMaxNum3 = CSEB.buildFMaxNum(s32, Copies[0], Copies[1], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFMaxNum == &*MIBFMaxNum3); MIBFMaxNum2->setFlag(MachineInstr::FmNsz); MIBFMaxNum2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFMaxNum == &*MIBFMaxNum2); } // Check G_FMINNUM_IEEE/F_MAXNUM_IEEE: { auto MIBFMinNumIEEE = CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1]); auto MIBFMinNumIEEE2 = CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE2); auto MIBFMinNumIEEE3 = CSEB.buildFMinNumIEEE(s32, Copies[0], Copies[1], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE3); MIBFMinNumIEEE2->setFlag(MachineInstr::FmNsz); MIBFMinNumIEEE2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFMinNumIEEE == &*MIBFMinNumIEEE2); } { auto MIBFMaxNumIEEE = CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1]); auto MIBFMaxNumIEEE2 = CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1]); EXPECT_TRUE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE2); auto MIBFMaxNumIEEE3 = CSEB.buildFMaxNumIEEE(s32, Copies[0], Copies[1], MachineInstr::FmNsz); EXPECT_FALSE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE3); MIBFMaxNumIEEE2->setFlag(MachineInstr::FmNsz); MIBFMaxNumIEEE2->clearFlag(MachineInstr::FmNsz); EXPECT_TRUE(&*MIBFMaxNumIEEE == &*MIBFMaxNumIEEE2); } // Check G_BUILD_VECTOR Register Reg1 = MRI->createGenericVirtualRegister(s32); Register Reg2 = MRI->createGenericVirtualRegister(s32); auto BuildVec1 = CSEB.buildBuildVector(LLT::fixed_vector(4, 32), {Reg1, Reg2, Reg1, Reg2}); auto BuildVec2 = CSEB.buildBuildVector(LLT::fixed_vector(4, 32), {Reg1, Reg2, Reg1, Reg2}); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, BuildVec1->getOpcode()); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, BuildVec2->getOpcode()); EXPECT_TRUE(&*BuildVec1 == &*BuildVec2); // Check G_BUILD_VECTOR_TRUNC auto BuildVecTrunc1 = CSEB.buildBuildVectorTrunc(LLT::fixed_vector(4, 16), {Reg1, Reg2, Reg1, Reg2}); auto BuildVecTrunc2 = CSEB.buildBuildVectorTrunc(LLT::fixed_vector(4, 16), {Reg1, Reg2, Reg1, Reg2}); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR_TRUNC, BuildVecTrunc1->getOpcode()); EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR_TRUNC, BuildVecTrunc2->getOpcode()); EXPECT_TRUE(&*BuildVecTrunc1 == &*BuildVecTrunc2); // Check G_IMPLICIT_DEF auto Undef0 = CSEB.buildUndef(s32); auto Undef1 = CSEB.buildUndef(s32); EXPECT_EQ(&*Undef0, &*Undef1); // If the observer is installed to the MF, CSE can also // track new instructions built without the CSEBuilder and // the newly built instructions are available for CSEing next // time a build call is made through the CSEMIRBuilder. // Additionally, the CSE implementation lazily hashes instructions // (every build call) to give chance for the instruction to be fully // built (say using .addUse().addDef().. so on). GISelObserverWrapper WrapperObserver(&CSEInfo); RAIIMFObsDelInstaller Installer(*MF, WrapperObserver); MachineIRBuilder RegularBuilder(*MF); RegularBuilder.setInsertPt(*EntryMBB, EntryMBB->begin()); auto NonCSEFMul = RegularBuilder.buildInstr(TargetOpcode::G_AND) .addDef(MRI->createGenericVirtualRegister(s32)) .addUse(Copies[0]) .addUse(Copies[1]); auto CSEFMul = CSEB.buildInstr(TargetOpcode::G_AND, {s32}, {Copies[0], Copies[1]}); EXPECT_EQ(&*CSEFMul, &*NonCSEFMul); auto ExtractMIB = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, {Copies[0], static_cast(0)}); auto ExtractMIB1 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, {Copies[0], static_cast(0)}); auto ExtractMIB2 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, {Copies[0], static_cast(1)}); EXPECT_EQ(&*ExtractMIB, &*ExtractMIB1); EXPECT_NE(&*ExtractMIB, &*ExtractMIB2); auto SextInRegMIB = CSEB.buildSExtInReg(s16, Copies[0], 0); auto SextInRegMIB1 = CSEB.buildSExtInReg(s16, Copies[0], 0); auto SextInRegMIB2 = CSEB.buildSExtInReg(s16, Copies[0], 1); EXPECT_EQ(&*SextInRegMIB, &*SextInRegMIB1); EXPECT_NE(&*SextInRegMIB, &*SextInRegMIB2); } TEST_F(AArch64GISelMITest, TestCSEConstantConfig) { setUp(); if (!TM) GTEST_SKIP(); LLT s16{LLT::scalar(16)}; auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); auto MIBZero = B.buildConstant(s16, 0); GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); auto MIBAdd1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); // We should CSE constants only. Adds should not be CSEd. EXPECT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY); EXPECT_TRUE(&*MIBAdd1 != &*MIBAdd); // We should CSE constant. auto MIBZeroTmp = CSEB.buildConstant(s16, 0); EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp); // Check G_IMPLICIT_DEF auto Undef0 = CSEB.buildUndef(s16); auto Undef1 = CSEB.buildUndef(s16); EXPECT_EQ(&*Undef0, &*Undef1); } TEST_F(AArch64GISelMITest, TestCSEImmediateNextCSE) { setUp(); if (!TM) GTEST_SKIP(); LLT s32{LLT::scalar(32)}; // We want to check that when the CSE hit is on the next instruction, i.e. at // the current insert pt, that the insertion point is moved ahead of the // instruction. GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); CSEB.buildConstant(s32, 0); auto MIBCst2 = CSEB.buildConstant(s32, 2); // Move the insert point before the second constant. CSEB.setInsertPt(CSEB.getMBB(), --CSEB.getInsertPt()); auto MIBCst3 = CSEB.buildConstant(s32, 2); EXPECT_TRUE(&*MIBCst2 == &*MIBCst3); EXPECT_TRUE(CSEB.getInsertPt() == CSEB.getMBB().end()); } TEST_F(AArch64GISelMITest, TestConstantFoldCTL) { setUp(); if (!TM) GTEST_SKIP(); LLT s32 = LLT::scalar(32); GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); auto Cst8 = CSEB.buildConstant(s32, 8); auto *CtlzDef = &*CSEB.buildCTLZ(s32, Cst8); EXPECT_TRUE(CtlzDef->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(CtlzDef->getOperand(1).getCImm()->getZExtValue() == 28); // Test vector. auto Cst16 = CSEB.buildConstant(s32, 16); auto Cst32 = CSEB.buildConstant(s32, 32); auto Cst64 = CSEB.buildConstant(s32, 64); LLT VecTy = LLT::fixed_vector(4, s32); auto BV = CSEB.buildBuildVector(VecTy, {Cst8.getReg(0), Cst16.getReg(0), Cst32.getReg(0), Cst64.getReg(0)}); CSEB.buildCTLZ(VecTy, BV); auto CheckStr = R"( ; CHECK: [[CST8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 ; CHECK: [[CST28:%[0-9]+]]:_(s32) = G_CONSTANT i32 28 ; CHECK: [[CST16:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; CHECK: [[CST32:%[0-9]+]]:_(s32) = G_CONSTANT i32 32 ; CHECK: [[CST64:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 ; CHECK: [[BV1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST8]]:_(s32), [[CST16]]:_(s32), [[CST32]]:_(s32), [[CST64]]:_(s32) ; CHECK: [[CST27:%[0-9]+]]:_(s32) = G_CONSTANT i32 27 ; CHECK: [[CST26:%[0-9]+]]:_(s32) = G_CONSTANT i32 26 ; CHECK: [[CST25:%[0-9]+]]:_(s32) = G_CONSTANT i32 25 ; CHECK: [[BV2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST28]]:_(s32), [[CST27]]:_(s32), [[CST26]]:_(s32), [[CST25]]:_(s32) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, TestConstantFoldCTT) { setUp(); if (!TM) GTEST_SKIP(); LLT s32 = LLT::scalar(32); GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); auto Cst8 = CSEB.buildConstant(s32, 8); auto *CttzDef = &*CSEB.buildCTTZ(s32, Cst8); EXPECT_TRUE(CttzDef->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(CttzDef->getOperand(1).getCImm()->getZExtValue() == 3); // Test vector. auto Cst16 = CSEB.buildConstant(s32, 16); auto Cst32 = CSEB.buildConstant(s32, 32); auto Cst64 = CSEB.buildConstant(s32, 64); LLT VecTy = LLT::fixed_vector(4, s32); auto BV = CSEB.buildBuildVector(VecTy, {Cst8.getReg(0), Cst16.getReg(0), Cst32.getReg(0), Cst64.getReg(0)}); CSEB.buildCTTZ(VecTy, BV); auto CheckStr = R"( ; CHECK: [[CST8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 ; CHECK: [[CST3:%[0-9]+]]:_(s32) = G_CONSTANT i32 3 ; CHECK: [[CST16:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 ; CHECK: [[CST32:%[0-9]+]]:_(s32) = G_CONSTANT i32 32 ; CHECK: [[CST64:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 ; CHECK: [[BV1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST8]]:_(s32), [[CST16]]:_(s32), [[CST32]]:_(s32), [[CST64]]:_(s32) ; CHECK: [[CST27:%[0-9]+]]:_(s32) = G_CONSTANT i32 4 ; CHECK: [[CST26:%[0-9]+]]:_(s32) = G_CONSTANT i32 5 ; CHECK: [[CST25:%[0-9]+]]:_(s32) = G_CONSTANT i32 6 ; CHECK: [[BV2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST3]]:_(s32), [[CST27]]:_(s32), [[CST26]]:_(s32), [[CST25]]:_(s32) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } TEST_F(AArch64GISelMITest, TestConstantFoldICMP) { setUp(); if (!TM) GTEST_SKIP(); LLT s32 = LLT::scalar(32); LLT s1 = LLT::scalar(1); GISelCSEInfo CSEInfo; CSEInfo.setCSEConfig(std::make_unique()); CSEInfo.analyze(*MF); B.setCSEInfo(&CSEInfo); CSEMIRBuilder CSEB(B.getState()); auto One = CSEB.buildConstant(s32, 1); auto Two = CSEB.buildConstant(s32, 2); auto MinusOne = CSEB.buildConstant(s32, -1); auto MinusTwo = CSEB.buildConstant(s32, -2); // ICMP_EQ { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, s1, One, One); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_NE { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_NE, s1, One, Two); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_UGT { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_UGT, s1, Two, One); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_UGE { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_UGE, s1, One, One); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_ULT { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_ULT, s1, One, Two); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_ULE { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_ULE, s1, Two, Two); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_SGT { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_SGT, s1, MinusOne, MinusTwo); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_SGE { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_SGE, s1, MinusOne, MinusOne); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_SLT { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_SLT, s1, MinusTwo, MinusOne); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } // ICMP_SLE { auto I = CSEB.buildICmp(CmpInst::Predicate::ICMP_SLE, s1, MinusTwo, MinusOne); EXPECT_TRUE(I->getOpcode() == TargetOpcode::G_CONSTANT); EXPECT_TRUE(I->getOperand(1).getCImm()->getZExtValue()); } LLT VecTy = LLT::fixed_vector(2, s32); LLT DstTy = LLT::fixed_vector(2, s1); auto Three = CSEB.buildConstant(s32, 3); auto MinusThree = CSEB.buildConstant(s32, -3); auto OneOne = CSEB.buildBuildVector(VecTy, {One.getReg(0), One.getReg(0)}); auto OneTwo = CSEB.buildBuildVector(VecTy, {One.getReg(0), Two.getReg(0)}); auto TwoThree = CSEB.buildBuildVector(VecTy, {Two.getReg(0), Three.getReg(0)}); auto MinusOneOne = CSEB.buildBuildVector(VecTy, {MinusOne.getReg(0), MinusOne.getReg(0)}); auto MinusOneTwo = CSEB.buildBuildVector(VecTy, {MinusOne.getReg(0), MinusTwo.getReg(0)}); auto MinusTwoThree = CSEB.buildBuildVector(VecTy, {MinusTwo.getReg(0), MinusThree.getReg(0)}); // ICMP_EQ CSEB.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, OneOne, OneOne); // ICMP_NE CSEB.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, OneOne, OneTwo); // ICMP_UGT CSEB.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, TwoThree, OneTwo); // ICMP_UGE CSEB.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, OneTwo, OneOne); // ICMP_ULT CSEB.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, OneOne, OneTwo); // ICMP_ULE CSEB.buildICmp(CmpInst::Predicate::ICMP_ULE, DstTy, OneTwo, OneOne); // ICMP_SGT CSEB.buildICmp(CmpInst::Predicate::ICMP_SGT, DstTy, MinusOneTwo, MinusTwoThree); // ICMP_SGE CSEB.buildICmp(CmpInst::Predicate::ICMP_SGE, DstTy, MinusOneTwo, MinusOneOne); // ICMP_SLT CSEB.buildICmp(CmpInst::Predicate::ICMP_SLT, DstTy, MinusTwoThree, MinusOneTwo); // ICMP_SLE CSEB.buildICmp(CmpInst::Predicate::ICMP_SLE, DstTy, MinusOneTwo, MinusOneOne); auto CheckStr = R"( ; CHECK: [[One:%[0-9]+]]:_(s32) = G_CONSTANT i32 1 ; CHECK: [[Two:%[0-9]+]]:_(s32) = G_CONSTANT i32 2 ; CHECK: [[MinusOne:%[0-9]+]]:_(s32) = G_CONSTANT i32 -1 ; CHECK: [[MinusTwo:%[0-9]+]]:_(s32) = G_CONSTANT i32 -2 ; CHECK: [[True:%[0-9]+]]:_(s1) = G_CONSTANT i1 true ; CHECK: [[Three:%[0-9]+]]:_(s32) = G_CONSTANT i32 3 ; CHECK: [[MinusThree:%[0-9]+]]:_(s32) = G_CONSTANT i32 -3 ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[One]]:_(s32), [[One]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[One]]:_(s32), [[Two]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[Two]]:_(s32), [[Three]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusOne]]:_(s32), [[MinusOne]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusOne]]:_(s32), [[MinusTwo]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s32>) = G_BUILD_VECTOR [[MinusTwo]]:_(s32), [[MinusThree]]:_(s32) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) ; CHECK: [[False:%[0-9]+]]:_(s1) = G_CONSTANT i1 false ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[False]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[False]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[False]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[False]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) ; CHECK: {{%[0-9]+}}:_(<2 x s1>) = G_BUILD_VECTOR [[True]]:_(s1), [[True]]:_(s1) )"; EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } } // namespace