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