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/CSEInfo.h" 11 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" 12 #include "gtest/gtest.h" 13 14 namespace { 15 16 TEST_F(AArch64GISelMITest, TestCSE) { 17 setUp(); 18 if (!TM) 19 return; 20 21 LLT s16{LLT::scalar(16)}; 22 LLT s32{LLT::scalar(32)}; 23 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); 24 auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[1]}); 25 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 26 GISelCSEInfo CSEInfo; 27 CSEInfo.setCSEConfig(std::make_unique<CSEConfigFull>()); 28 CSEInfo.analyze(*MF); 29 B.setCSEInfo(&CSEInfo); 30 CSEMIRBuilder CSEB(B.getState()); 31 32 CSEB.setInsertPt(B.getMBB(), B.getInsertPt()); 33 Register AddReg = MRI->createGenericVirtualRegister(s16); 34 auto MIBAddCopy = 35 CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput}); 36 EXPECT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY); 37 auto MIBAdd2 = 38 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 39 EXPECT_TRUE(&*MIBAdd == &*MIBAdd2); 40 auto MIBAdd4 = 41 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 42 EXPECT_TRUE(&*MIBAdd == &*MIBAdd4); 43 auto MIBAdd5 = 44 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1}); 45 EXPECT_TRUE(&*MIBAdd != &*MIBAdd5); 46 47 // Try building G_CONSTANTS. 48 auto MIBCst = CSEB.buildConstant(s32, 0); 49 auto MIBCst1 = CSEB.buildConstant(s32, 0); 50 EXPECT_TRUE(&*MIBCst == &*MIBCst1); 51 // Try the CFing of BinaryOps. 52 auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst}); 53 EXPECT_TRUE(&*MIBCF1 == &*MIBCst); 54 55 // Try out building FCONSTANTs. 56 auto MIBFP0 = CSEB.buildFConstant(s32, 1.0); 57 auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0); 58 EXPECT_TRUE(&*MIBFP0 == &*MIBFP0_1); 59 CSEInfo.print(); 60 61 // Make sure buildConstant with a vector type doesn't crash, and the elements 62 // CSE. 63 auto Splat0 = CSEB.buildConstant(LLT::fixed_vector(2, s32), 0); 64 EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, Splat0->getOpcode()); 65 EXPECT_EQ(Splat0.getReg(1), Splat0.getReg(2)); 66 EXPECT_EQ(&*MIBCst, MRI->getVRegDef(Splat0.getReg(1))); 67 68 auto FSplat = CSEB.buildFConstant(LLT::fixed_vector(2, s32), 1.0); 69 EXPECT_EQ(TargetOpcode::G_BUILD_VECTOR, FSplat->getOpcode()); 70 EXPECT_EQ(FSplat.getReg(1), FSplat.getReg(2)); 71 EXPECT_EQ(&*MIBFP0, MRI->getVRegDef(FSplat.getReg(1))); 72 73 // Check G_UNMERGE_VALUES 74 auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]); 75 auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]); 76 EXPECT_TRUE(&*MIBUnmerge == &*MIBUnmerge2); 77 78 // Check G_IMPLICIT_DEF 79 auto Undef0 = CSEB.buildUndef(s32); 80 auto Undef1 = CSEB.buildUndef(s32); 81 EXPECT_EQ(&*Undef0, &*Undef1); 82 83 // If the observer is installed to the MF, CSE can also 84 // track new instructions built without the CSEBuilder and 85 // the newly built instructions are available for CSEing next 86 // time a build call is made through the CSEMIRBuilder. 87 // Additionally, the CSE implementation lazily hashes instructions 88 // (every build call) to give chance for the instruction to be fully 89 // built (say using .addUse().addDef().. so on). 90 GISelObserverWrapper WrapperObserver(&CSEInfo); 91 RAIIMFObsDelInstaller Installer(*MF, WrapperObserver); 92 MachineIRBuilder RegularBuilder(*MF); 93 RegularBuilder.setInsertPt(*EntryMBB, EntryMBB->begin()); 94 auto NonCSEFMul = RegularBuilder.buildInstr(TargetOpcode::G_AND) 95 .addDef(MRI->createGenericVirtualRegister(s32)) 96 .addUse(Copies[0]) 97 .addUse(Copies[1]); 98 auto CSEFMul = 99 CSEB.buildInstr(TargetOpcode::G_AND, {s32}, {Copies[0], Copies[1]}); 100 EXPECT_EQ(&*CSEFMul, &*NonCSEFMul); 101 102 auto ExtractMIB = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 103 {Copies[0], static_cast<uint64_t>(0)}); 104 auto ExtractMIB1 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 105 {Copies[0], static_cast<uint64_t>(0)}); 106 auto ExtractMIB2 = CSEB.buildInstr(TargetOpcode::G_EXTRACT, {s16}, 107 {Copies[0], static_cast<uint64_t>(1)}); 108 EXPECT_EQ(&*ExtractMIB, &*ExtractMIB1); 109 EXPECT_NE(&*ExtractMIB, &*ExtractMIB2); 110 } 111 112 TEST_F(AArch64GISelMITest, TestCSEConstantConfig) { 113 setUp(); 114 if (!TM) 115 return; 116 117 LLT s16{LLT::scalar(16)}; 118 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]}); 119 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 120 auto MIBZero = B.buildConstant(s16, 0); 121 GISelCSEInfo CSEInfo; 122 CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>()); 123 CSEInfo.analyze(*MF); 124 B.setCSEInfo(&CSEInfo); 125 CSEMIRBuilder CSEB(B.getState()); 126 CSEB.setInsertPt(*EntryMBB, EntryMBB->begin()); 127 auto MIBAdd1 = 128 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput}); 129 // We should CSE constants only. Adds should not be CSEd. 130 EXPECT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY); 131 EXPECT_TRUE(&*MIBAdd1 != &*MIBAdd); 132 // We should CSE constant. 133 auto MIBZeroTmp = CSEB.buildConstant(s16, 0); 134 EXPECT_TRUE(&*MIBZero == &*MIBZeroTmp); 135 136 // Check G_IMPLICIT_DEF 137 auto Undef0 = CSEB.buildUndef(s16); 138 auto Undef1 = CSEB.buildUndef(s16); 139 EXPECT_EQ(&*Undef0, &*Undef1); 140 } 141 142 TEST_F(AArch64GISelMITest, TestCSEImmediateNextCSE) { 143 setUp(); 144 if (!TM) 145 return; 146 147 LLT s32{LLT::scalar(32)}; 148 // We want to check that when the CSE hit is on the next instruction, i.e. at 149 // the current insert pt, that the insertion point is moved ahead of the 150 // instruction. 151 152 GISelCSEInfo CSEInfo; 153 CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>()); 154 CSEInfo.analyze(*MF); 155 B.setCSEInfo(&CSEInfo); 156 CSEMIRBuilder CSEB(B.getState()); 157 CSEB.buildConstant(s32, 0); 158 auto MIBCst2 = CSEB.buildConstant(s32, 2); 159 160 // Move the insert point before the second constant. 161 CSEB.setInsertPt(CSEB.getMBB(), --CSEB.getInsertPt()); 162 auto MIBCst3 = CSEB.buildConstant(s32, 2); 163 EXPECT_TRUE(&*MIBCst2 == &*MIBCst3); 164 EXPECT_TRUE(CSEB.getInsertPt() == CSEB.getMBB().end()); 165 } 166 167 TEST_F(AArch64GISelMITest, TestConstantFoldCTL) { 168 setUp(); 169 if (!TM) 170 return; 171 172 LLT s32 = LLT::scalar(32); 173 174 GISelCSEInfo CSEInfo; 175 CSEInfo.setCSEConfig(std::make_unique<CSEConfigConstantOnly>()); 176 CSEInfo.analyze(*MF); 177 B.setCSEInfo(&CSEInfo); 178 CSEMIRBuilder CSEB(B.getState()); 179 auto Cst8 = CSEB.buildConstant(s32, 8); 180 auto *CtlzDef = &*CSEB.buildCTLZ(s32, Cst8); 181 EXPECT_TRUE(CtlzDef->getOpcode() == TargetOpcode::G_CONSTANT); 182 EXPECT_TRUE(CtlzDef->getOperand(1).getCImm()->getZExtValue() == 28); 183 184 // Test vector. 185 auto Cst16 = CSEB.buildConstant(s32, 16); 186 auto Cst32 = CSEB.buildConstant(s32, 32); 187 auto Cst64 = CSEB.buildConstant(s32, 64); 188 LLT VecTy = LLT::fixed_vector(4, s32); 189 auto BV = CSEB.buildBuildVector(VecTy, {Cst8.getReg(0), Cst16.getReg(0), 190 Cst32.getReg(0), Cst64.getReg(0)}); 191 CSEB.buildCTLZ(VecTy, BV); 192 193 auto CheckStr = R"( 194 ; CHECK: [[CST8:%[0-9]+]]:_(s32) = G_CONSTANT i32 8 195 ; CHECK: [[CST28:%[0-9]+]]:_(s32) = G_CONSTANT i32 28 196 ; CHECK: [[CST16:%[0-9]+]]:_(s32) = G_CONSTANT i32 16 197 ; CHECK: [[CST32:%[0-9]+]]:_(s32) = G_CONSTANT i32 32 198 ; CHECK: [[CST64:%[0-9]+]]:_(s32) = G_CONSTANT i32 64 199 ; CHECK: [[BV1:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST8]]:_(s32), [[CST16]]:_(s32), [[CST32]]:_(s32), [[CST64]]:_(s32) 200 ; CHECK: [[CST27:%[0-9]+]]:_(s32) = G_CONSTANT i32 27 201 ; CHECK: [[CST26:%[0-9]+]]:_(s32) = G_CONSTANT i32 26 202 ; CHECK: [[CST25:%[0-9]+]]:_(s32) = G_CONSTANT i32 25 203 ; CHECK: [[BV2:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[CST28]]:_(s32), [[CST27]]:_(s32), [[CST26]]:_(s32), [[CST25]]:_(s32) 204 )"; 205 206 EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; 207 } 208 209 } // namespace 210