1 //===- CSETest.cpp -----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "GISelMITest.h" 10 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" 11 12 namespace { 13 14 TEST_F(AArch64GISelMITest, TestCSE) { 15 setUp(); 16 if (!TM) 17 return; 18 19 LLT s16{LLT::scalar(16)}; 20 LLT s32{LLT::scalar(32)}; 21 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); 22 auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[1]}); 23 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 24 GISelCSEInfo CSEInfo; 25 CSEInfo.setCSEConfig(std::make_unique<CSEConfigFull>()); 26 CSEInfo.analyze(*MF); 27 B.setCSEInfo(&CSEInfo); 28 CSEMIRBuilder CSEB(B.getState()); 29 30 CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); 31 unsigned AddReg = MRI->createGenericVirtualRegister(s16); 32 auto MIBAddCopy = 33 CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput}); 34 EXPECT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); 35 auto MIBAdd2 = 36 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 37 EXPECT_TRUE(&*MIBAdd == &*MIBAdd2); 38 auto MIBAdd4 = 39 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 40 EXPECT_TRUE(&*MIBAdd == &*MIBAdd4); 41 auto MIBAdd5 = 42 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1}); 43 EXPECT_TRUE(&*MIBAdd != &*MIBAdd5); 44 45 // Try building G_CONSTANTS. 46 auto MIBCst = CSEB.buildConstant(s32, 0); 47 auto MIBCst1 = CSEB.buildConstant(s32, 0); 48 EXPECT_TRUE(&*MIBCst == &*MIBCst1); 49 // Try the CFing of BinaryOps. 50 auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst}); 51 EXPECT_TRUE(&*MIBCF1 == &*MIBCst); 52 53 // Try out building FCONSTANTs. 54 auto MIBFP0 = CSEB.buildFConstant(s32, 1.0); 55 auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0); 56 EXPECT_TRUE(&*MIBFP0 == &*MIBFP0_1); 57 CSEInfo.print(); 58 59 // Make sure buildConstant with a vector type doesn't crash, and the elements 60 // CSE. 61 auto Splat0 = CSEB.buildConstant(LLT::vector(2, s32), 0); 62 EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, Splat0->getOpcode()); 63 EXPECT_EQ(Splat0.getReg(1), Splat0.getReg(2)); 64 EXPECT_EQ(&*MIBCst, MRI->getVRegDef(Splat0.getReg(1))); 65 66 auto FSplat = CSEB.buildFConstant(LLT::vector(2, s32), 1.0); 67 EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, FSplat->getOpcode()); 68 EXPECT_EQ(FSplat.getReg(1), FSplat.getReg(2)); 69 EXPECT_EQ(&*MIBFP0, MRI->getVRegDef(FSplat.getReg(1))); 70 71 // Check G_UNMERGE_VALUES 72 auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]); 73 auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]); 74 EXPECT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); 75 76 // Check G_IMPLICIT_DEF 77 auto Undef0 = CSEB.buildUndef(s32); 78 auto Undef1 = CSEB.buildUndef(s32); 79 EXPECT_EQ(&*Undef0, &*Undef1); 80 81 // If the observer is installed to the MF, CSE can also 82 // track new instructions built without the CSEBuilder and 83 // the newly built instructions are available for CSEing next 84 // time a build call is made through the CSEMIRBuilder. 85 // Additionally, the CSE implementation lazily hashes instructions 86 // (every build call) to give chance for the instruction to be fully 87 // built (say using .addUse().addDef().. so on). 88 GISelObserverWrapper WrapperObserver(&CSEInfo); 89 RAIIMFObsDelInstaller Installer(*MF, WrapperObserver); 90 MachineIRBuilder RegularBuilder(*MF); 91 RegularBuilder.setInsertPt(*EntryMBB, EntryMBB->begin()); 92 auto NonCSEFMul = RegularBuilder.buildInstr(TargetOpcode::G_AND) 93 .addDef(MRI->createGenericVirtualRegister(s32)) 94 .addUse(Copies[0]) 95 .addUse(Copies[1]); 96 auto CSEFMul = 97 CSEB.buildInstr(TargetOpcode::G_AND, {s32}, {Copies[0], Copies[1]}); 98 EXPECT_EQ(&*CSEFMul, &*NonCSEFMul); 99 100 auto ExtractMIB = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 101 {Copies[0], static_cast<uint64_t>(0)}); 102 auto ExtractMIB1 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 103 {Copies[0], static_cast<uint64_t>(0)}); 104 auto ExtractMIB2 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 105 {Copies[0], static_cast<uint64_t>(1)}); 106 EXPECT_EQ(&*ExtractMIB, &*ExtractMIB1); 107 EXPECT_NE(&*ExtractMIB, &*ExtractMIB2); 108 } 109 110 TEST_F(AArch64GISelMITest, TestCSEConstantConfig) { 111 setUp(); 112 if (!TM) 113 return; 114 115 LLT s16{LLT::scalar(16)}; 116 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); 117 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 118 auto MIBZero = B.buildConstant(s16, 0); 119 GISelCSEInfo CSEInfo; 120 CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>()); 121 CSEInfo.analyze(*MF); 122 B.setCSEInfo(&CSEInfo); 123 CSEMIRBuilder CSEB(B.getState()); 124 CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); 125 auto MIBAdd1 = 126 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 127 // We should CSE constants only. Adds should not be CSEd. 128 EXPECT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY); 129 EXPECT_TRUE(&*MIBAdd1 != &*MIBAdd); 130 // We should CSE constant. 131 auto MIBZeroTmp = CSEB.buildConstant(s16, 0); 132 EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp); 133 134 // Check G_IMPLICIT_DEF 135 auto Undef0 = CSEB.buildUndef(s16); 136 auto Undef1 = CSEB.buildUndef(s16); 137 EXPECT_EQ(&*Undef0, &*Undef1); 138 } 139 } // namespace 140