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