1 //===- CSETest.cpp -----------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "GISelMITest.h"
10 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
11 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
12 #include "gtest/gtest.h"
16 TEST_F(AArch64GISelMITest
, TestCSE
) {
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
});
27 CSEInfo
.setCSEConfig(std::make_unique
<CSEConfigFull
>());
29 B
.setCSEInfo(&CSEInfo
);
30 CSEMIRBuilder
CSEB(B
.getState());
32 CSEB
.setInsertPt(B
.getMBB(), B
.getInsertPt());
33 Register AddReg
= MRI
->createGenericVirtualRegister(s16
);
35 CSEB
.buildInstr(TargetOpcode::G_ADD
, {AddReg
}, {MIBInput
, MIBInput
});
36 EXPECT_EQ(MIBAddCopy
->getOpcode(), TargetOpcode::COPY
);
38 CSEB
.buildInstr(TargetOpcode::G_ADD
, {s16
}, {MIBInput
, MIBInput
});
39 EXPECT_TRUE(&*MIBAdd
== &*MIBAdd2
);
41 CSEB
.buildInstr(TargetOpcode::G_ADD
, {s16
}, {MIBInput
, MIBInput
});
42 EXPECT_TRUE(&*MIBAdd
== &*MIBAdd4
);
44 CSEB
.buildInstr(TargetOpcode::G_ADD
, {s16
}, {MIBInput
, MIBInput1
});
45 EXPECT_TRUE(&*MIBAdd
!= &*MIBAdd5
);
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
);
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
);
61 // Make sure buildConstant with a vector type doesn't crash, and the elements
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)));
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)));
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
);
78 // Check G_IMPLICIT_DEF
79 auto Undef0
= CSEB
.buildUndef(s32
);
80 auto Undef1
= CSEB
.buildUndef(s32
);
81 EXPECT_EQ(&*Undef0
, &*Undef1
);
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
))
99 CSEB
.buildInstr(TargetOpcode::G_AND
, {s32
}, {Copies
[0], Copies
[1]});
100 EXPECT_EQ(&*CSEFMul
, &*NonCSEFMul
);
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
);
112 TEST_F(AArch64GISelMITest
, TestCSEConstantConfig
) {
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());
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
);
136 // Check G_IMPLICIT_DEF
137 auto Undef0
= CSEB
.buildUndef(s16
);
138 auto Undef1
= CSEB
.buildUndef(s16
);
139 EXPECT_EQ(&*Undef0
, &*Undef1
);
142 TEST_F(AArch64GISelMITest
, TestCSEImmediateNextCSE
) {
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
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);
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());
167 TEST_F(AArch64GISelMITest
, TestConstantFoldCTL
) {
172 LLT s32
= LLT::scalar(32);
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);
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
);
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)
206 EXPECT_TRUE(CheckMachineFunction(*MF
, CheckStr
)) << *MF
;