xref: /llvm-project/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp (revision ed98c1b37661b0795a5e34517941485f0f0688d1)
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