LLVM 24.0.0git
CSEMIRBuilder.cpp
Go to the documentation of this file.
1//===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- C++ -*-==//
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/// \file
9/// This file implements the CSEMIRBuilder class which CSEs as it builds
10/// instructions.
11//===----------------------------------------------------------------------===//
12//
13
19
20using namespace llvm;
21
22bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A,
24 auto MBBEnd = getMBB().end();
25 if (B == MBBEnd)
26 return true;
27 assert(A->getParent() == B->getParent() &&
28 "Iterators should be in same block");
29 const MachineBasicBlock *BBA = A->getParent();
31 for (; &*I != A && &*I != B; ++I)
32 ;
33 return &*I == A;
34}
35
37CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID,
38 FoldingSetInsertToken &Token) {
39 GISelCSEInfo *CSEInfo = getCSEInfo();
40 assert(CSEInfo && "Can't get here without setting CSEInfo");
41 MachineBasicBlock *CurMBB = &getMBB();
42 MachineInstr *MI = CSEInfo->getMachineInstrIfExists(ID, CurMBB, Token);
43 if (MI) {
44 CSEInfo->countOpcodeHit(MI->getOpcode());
45 auto CurrPos = getInsertPt();
47 if (MII == CurrPos) {
48 // Move the insert point ahead of the instruction so any future uses of
49 // this builder will have the def ready.
50 setInsertPt(*CurMBB, std::next(MII));
51 } else if (!dominates(MI, CurrPos)) {
52 // Update the spliced machineinstr's debug location by merging it with the
53 // debug location of the instruction at the insertion point.
54 auto Loc = DebugLoc::getMergedLocation(getDebugLoc(), MI->getDebugLoc());
55 MI->setDebugLoc(Loc);
56 CurMBB->splice(CurrPos, CurMBB, MI);
57 }
58 return MachineInstrBuilder(getMF(), MI);
59 }
60 return MachineInstrBuilder();
61}
62
63bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const {
64 const GISelCSEInfo *CSEInfo = getCSEInfo();
65 if (!CSEInfo || !CSEInfo->shouldCSE(Opc))
66 return false;
67 return true;
68}
69
70void CSEMIRBuilder::profileDstOp(const DstOp &Op,
72 switch (Op.getDstOpKind()) {
74 B.addNodeIDRegType(Op.getRegClass());
75 break;
76 }
78 // Regs can have LLT&(RB|RC). If those exist, profile them as well.
79 B.addNodeIDReg(Op.getReg());
80 break;
81 }
83 B.addNodeIDRegType(Op.getLLTTy(*getMRI()));
84 break;
85 }
87 B.addNodeIDRegType(Op.getVRegAttrs());
88 break;
89 }
90 }
91}
92
93void CSEMIRBuilder::profileSrcOp(const SrcOp &Op,
95 switch (Op.getSrcOpKind()) {
97 B.addNodeIDImmediate(Op.getImm());
98 break;
100 B.addNodeIDImmediate(static_cast<int64_t>(Op.getPredicate()));
101 break;
102 default:
103 B.addNodeIDRegType(Op.getReg());
104 break;
105 }
106}
107
108void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B,
109 unsigned Opc) const {
110 // First add the MBB (Local CSE).
111 B.addNodeIDMBB(&getMBB());
112 // Then add the opcode.
113 B.addNodeIDOpcode(Opc);
114}
115
116void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps,
117 ArrayRef<SrcOp> SrcOps,
118 std::optional<unsigned> Flags,
119 GISelInstProfileBuilder &B) const {
120
121 profileMBBOpcode(B, Opc);
122 // Then add the DstOps.
123 profileDstOps(DstOps, B);
124 // Then add the SrcOps.
125 profileSrcOps(SrcOps, B);
126 // Add Flags if passed in.
127 if (Flags)
128 B.addNodeIDFlag(*Flags);
129}
130
131MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB,
132 FoldingSetInsertToken Token) {
133 assert(canPerformCSEForOpc(MIB->getOpcode()) &&
134 "Attempting to CSE illegal op");
135 MachineInstr *MIBInstr = MIB;
136 getCSEInfo()->insertInstr(MIBInstr, Token);
137 return MIB;
138}
139
140bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef<DstOp> DstOps) {
141 if (DstOps.size() == 1)
142 return true; // always possible to emit copy to just 1 vreg.
143
144 return llvm::all_of(DstOps, [](const DstOp &Op) {
145 DstOp::DstType DT = Op.getDstOpKind();
146 return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC;
147 });
148}
149
151CSEMIRBuilder::generateCopiesIfRequired(ArrayRef<DstOp> DstOps,
152 MachineInstrBuilder &MIB) {
153 assert(checkCopyToDefsPossible(DstOps) &&
154 "Impossible return a single MIB with copies to multiple defs");
155 if (DstOps.size() == 1) {
156 const DstOp &Op = DstOps[0];
157 if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg)
158 return buildCopy(Op.getReg(), MIB.getReg(0));
159 }
160
161 // If we didn't generate a copy then we're re-using an existing node directly
162 // instead of emitting any code. Merge the debug location we wanted to emit
163 // into the instruction we're CSE'ing with. Debug locations arent part of the
164 // profile so we don't need to recompute it.
165 if (getDebugLoc()) {
166 GISelChangeObserver *Observer = getState().Observer;
167 if (Observer)
168 Observer->changingInstr(*MIB);
169 MIB->setDebugLoc(
171 if (Observer)
172 Observer->changedInstr(*MIB);
173 }
174
175 return MIB;
176}
177
179 ArrayRef<DstOp> DstOps,
180 ArrayRef<SrcOp> SrcOps,
181 std::optional<unsigned> Flag) {
182 switch (Opc) {
183 default:
184 break;
185 case TargetOpcode::G_ICMP: {
186 assert(SrcOps.size() == 3 && "Invalid sources");
187 assert(DstOps.size() == 1 && "Invalid dsts");
188 LLT SrcTy = SrcOps[1].getLLTTy(*getMRI());
189 LLT DstTy = DstOps[0].getLLTTy(*getMRI());
190 auto BoolExtOp = getBoolExtOp(SrcTy.isVector(), false);
191
192 if (std::optional<SmallVector<APInt>> Cst = ConstantFoldICmp(
193 SrcOps[0].getPredicate(), SrcOps[1].getReg(), SrcOps[2].getReg(),
194 DstTy.getScalarSizeInBits(), BoolExtOp, *getMRI())) {
195 if (SrcTy.isVector())
196 return buildBuildVectorConstant(DstOps[0], *Cst);
197 return buildConstant(DstOps[0], Cst->front());
198 }
199 break;
200 }
201 case TargetOpcode::G_ADD:
202 case TargetOpcode::G_PTR_ADD:
203 case TargetOpcode::G_AND:
204 case TargetOpcode::G_ASHR:
205 case TargetOpcode::G_LSHR:
206 case TargetOpcode::G_MUL:
207 case TargetOpcode::G_OR:
208 case TargetOpcode::G_SHL:
209 case TargetOpcode::G_SUB:
210 case TargetOpcode::G_XOR:
211 case TargetOpcode::G_UDIV:
212 case TargetOpcode::G_SDIV:
213 case TargetOpcode::G_UREM:
214 case TargetOpcode::G_SREM:
215 case TargetOpcode::G_SMIN:
216 case TargetOpcode::G_SMAX:
217 case TargetOpcode::G_UMIN:
218 case TargetOpcode::G_UMAX: {
219 // Try to constant fold these.
220 assert(SrcOps.size() == 2 && "Invalid sources");
221 assert(DstOps.size() == 1 && "Invalid dsts");
222 LLT SrcTy = SrcOps[0].getLLTTy(*getMRI());
223
224 if (Opc == TargetOpcode::G_PTR_ADD &&
225 getDataLayout().isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
226 break;
227
228 if (SrcTy.isVector()) {
229 // Try to constant fold vector constants.
231 Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI());
232 if (!VecCst.empty())
233 return buildBuildVectorConstant(DstOps[0], VecCst);
234 break;
235 }
236
237 if (std::optional<APInt> Cst = ConstantFoldBinOp(
238 Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI()))
239 return buildConstant(DstOps[0], *Cst);
240 break;
241 }
242 case TargetOpcode::G_FADD:
243 case TargetOpcode::G_FSUB:
244 case TargetOpcode::G_FMUL:
245 case TargetOpcode::G_FDIV:
246 case TargetOpcode::G_FREM:
247 case TargetOpcode::G_FMINNUM:
248 case TargetOpcode::G_FMAXNUM:
249 case TargetOpcode::G_FMINNUM_IEEE:
250 case TargetOpcode::G_FMAXNUM_IEEE:
251 case TargetOpcode::G_FMINIMUM:
252 case TargetOpcode::G_FMAXIMUM:
253 case TargetOpcode::G_FCOPYSIGN: {
254 // Try to constant fold these.
255 assert(SrcOps.size() == 2 && "Invalid sources");
256 assert(DstOps.size() == 1 && "Invalid dsts");
257 if (std::optional<APFloat> Cst = ConstantFoldFPBinOp(
258 Opc, SrcOps[0].getReg(), SrcOps[1].getReg(), *getMRI()))
259 return buildFConstant(DstOps[0], *Cst);
260 break;
261 }
262 case TargetOpcode::G_SEXT_INREG: {
263 assert(DstOps.size() == 1 && "Invalid dst ops");
264 assert(SrcOps.size() == 2 && "Invalid src ops");
265 const DstOp &Dst = DstOps[0];
266 const SrcOp &Src0 = SrcOps[0];
267 const SrcOp &Src1 = SrcOps[1];
268 if (auto MaybeCst =
269 ConstantFoldExtOp(Opc, Src0.getReg(), Src1.getImm(), *getMRI()))
270 return buildConstant(Dst, *MaybeCst);
271 break;
272 }
273 case TargetOpcode::G_SITOFP:
274 case TargetOpcode::G_UITOFP: {
275 // Try to constant fold these.
276 assert(SrcOps.size() == 1 && "Invalid sources");
277 assert(DstOps.size() == 1 && "Invalid dsts");
278 if (std::optional<APFloat> Cst = ConstantFoldIntToFloat(
279 Opc, DstOps[0].getLLTTy(*getMRI()), SrcOps[0].getReg(), *getMRI()))
280 return buildFConstant(DstOps[0], *Cst);
281 break;
282 }
283 case TargetOpcode::G_CTLZ:
284 case TargetOpcode::G_CTLZ_ZERO_POISON:
285 case TargetOpcode::G_CTTZ:
286 case TargetOpcode::G_CTTZ_ZERO_POISON:
287 case TargetOpcode::G_CTPOP:
288 case TargetOpcode::G_ABS:
289 case TargetOpcode::G_BSWAP:
290 case TargetOpcode::G_BITREVERSE: {
291 assert(SrcOps.size() == 1 && "Expected one source");
292 assert(DstOps.size() == 1 && "Expected one dest");
293 auto Csts = ConstantFoldUnaryIntOp(Opc, DstOps[0].getLLTTy(*getMRI()),
294 SrcOps[0].getReg(), *getMRI());
295 if (Csts.empty())
296 break;
297 if (Csts.size() == 1)
298 return buildConstant(DstOps[0], Csts[0]);
299 return buildBuildVectorConstant(DstOps[0], Csts);
300 }
301 case TargetOpcode::G_BITCAST: {
302 assert(SrcOps.size() == 1 && "Expected one source");
303 assert(DstOps.size() == 1 && "Expected one dest");
304
305 LLT SrcTy = SrcOps[0].getLLTTy(*getMRI());
306 LLT DstTy = DstOps[0].getLLTTy(*getMRI());
307
308 if (SrcTy.isVector() || DstTy.isVector())
309 break;
310 auto ConstantSrc = getAnyConstantVRegValWithLookThrough(
311 SrcOps[0].getReg(), *getMRI(), /*LookThroughInstrs=*/false);
312 if (!ConstantSrc.has_value())
313 break;
314
315 if (DstTy.isFloat()) {
316 return buildFConstant(
317 DstOps[0],
318 APFloat(llvm::getFltSemanticForLLT(DstTy), ConstantSrc->Value));
319 }
320 return buildConstant(DstOps[0], ConstantSrc->Value);
321 }
322 }
323 bool CanCopy = checkCopyToDefsPossible(DstOps);
324 if (!canPerformCSEForOpc(Opc))
325 return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
326 // If we can CSE this instruction, but involves generating copies to multiple
327 // regs, give up. This frequently happens to UNMERGEs.
328 if (!CanCopy) {
329 auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
330 // CSEInfo would have tracked this instruction. Remove it from the temporary
331 // insts.
333 return MIB;
334 }
336 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
338 profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder);
339 MachineInstrBuilder MIB = getDominatingInstrForID(ID, Token);
340 if (MIB) {
341 // Handle generating copies here.
342 return generateCopiesIfRequired(DstOps, MIB);
343 }
344 // This instruction does not exist in the CSEInfo. Build it and CSE it.
345 MachineInstrBuilder NewMIB =
346 MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
347 return memoizeMI(NewMIB, Token);
348}
349
351 const ConstantInt &Val) {
352 constexpr unsigned Opc = TargetOpcode::G_CONSTANT;
353 if (!canPerformCSEForOpc(Opc))
354 return MachineIRBuilder::buildConstant(Res, Val);
355
356 // For vectors, CSE the element only for now.
357 LLT Ty = Res.getLLTTy(*getMRI());
358 if (Ty.isFixedVector())
359 return buildSplatBuildVector(Res, buildConstant(Ty.getElementType(), Val));
360 if (Ty.isScalableVector())
361 return buildSplatVector(Res, buildConstant(Ty.getElementType(), Val));
362
364 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
366 profileMBBOpcode(ProfBuilder, Opc);
367 profileDstOp(Res, ProfBuilder);
369 MachineInstrBuilder MIB = getDominatingInstrForID(ID, Token);
370 if (MIB) {
371 // Handle generating copies here.
372 return generateCopiesIfRequired({Res}, MIB);
373 }
374
376 return memoizeMI(NewMIB, Token);
377}
378
380 const ConstantFP &Val) {
381 constexpr unsigned Opc = TargetOpcode::G_FCONSTANT;
382 if (!canPerformCSEForOpc(Opc))
383 return MachineIRBuilder::buildFConstant(Res, Val);
384
385 // For vectors, CSE the element only for now.
386 LLT Ty = Res.getLLTTy(*getMRI());
387 if (Ty.isFixedVector())
388 return buildSplatBuildVector(Res, buildFConstant(Ty.getElementType(), Val));
389 if (Ty.isScalableVector())
390 return buildSplatVector(Res, buildFConstant(Ty.getElementType(), Val));
391
393 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
395 profileMBBOpcode(ProfBuilder, Opc);
396 profileDstOp(Res, ProfBuilder);
398 MachineInstrBuilder MIB = getDominatingInstrForID(ID, Token);
399 if (MIB) {
400 // Handle generating copies here.
401 return generateCopiesIfRequired({Res}, MIB);
402 }
404 return memoizeMI(NewMIB, Token);
405}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.
This contains common code to allow clients to notify changes to machine instr.
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef< DstOp > DstOps, ArrayRef< SrcOp > SrcOps, std::optional< unsigned > Flag=std::nullopt) override
MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val) override
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val) override
Build and insert Res = G_CONSTANT Val.
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
This is the shared class of boolean and integer constants.
Definition Constants.h:87
static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
Definition DebugLoc.cpp:172
LLT getLLTTy(const MachineRegisterInfo &MRI) const
Insertion token: a failed lookup fills it in, the matching insert consumes it.
Definition FoldingSet.h:301
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:215
bool shouldCSE(unsigned Opc) const
Definition CSEInfo.cpp:235
void countOpcodeHit(unsigned Opc)
Definition CSEInfo.cpp:180
void handleRemoveInst(MachineInstr *MI)
Remove this inst from the CSE map.
Definition CSEInfo.cpp:216
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
LLVM_ABI const GISelInstProfileBuilder & addNodeIDMachineOperand(const MachineOperand &MO) const
Definition CSEInfo.cpp:414
constexpr unsigned getScalarSizeInBits() const
constexpr bool isFloat() const
constexpr bool isVector() const
MachineInstrBundleIterator< const MachineInstr > const_iterator
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
GISelCSEInfo * getCSEInfo()
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)
Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.
unsigned getBoolExtOp(bool IsVec, bool IsFP) const
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildBuildVectorConstant(const DstOp &Res, ArrayRef< APInt > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ... where each OpN is built with G_CONSTANT.
MachineFunction & getMF()
Getter for the function we currently build.
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
const DebugLoc & getDebugLoc()
Get the current instruction's debug location.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineIRBuilderState & getState()
Getter for the State.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildSplatVector(const DstOp &Res, const SrcOp &Val)
Build and insert Res = G_SPLAT_VECTOR Val.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
void setDebugLoc(DebugLoc DL)
Replace current source information with new such.
static MachineOperand CreateFPImm(const ConstantFP *CFP)
static MachineOperand CreateCImm(const ConstantInt *CI)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
int64_t getImm() const
Register getReg() const
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI std::optional< SmallVector< APInt > > ConstantFoldICmp(unsigned Pred, const Register Op1, const Register Op2, unsigned DstScalarSizeInBits, unsigned ExtOp, const MachineRegisterInfo &MRI)
Definition Utils.cpp:983
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1739
LLVM_ABI std::optional< APFloat > ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Definition Utils.cpp:922
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI std::optional< APFloat > ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
Definition Utils.cpp:731
LLVM_ABI std::optional< APInt > ConstantFoldExtOp(unsigned Opcode, const Register Op1, uint64_t Imm, const MachineRegisterInfo &MRI)
Definition Utils.cpp:881
LLVM_ABI std::optional< APInt > ConstantFoldBinOp(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
Definition Utils.cpp:662
LLVM_ABI std::optional< ValueAndVReg > getAnyConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true, bool LookThroughAnyExt=false)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT or G_FCONST...
Definition Utils.cpp:442
LLVM_ABI SmallVector< APInt > ConstantFoldVectorBinop(unsigned Opcode, const Register Op1, const Register Op2, const MachineRegisterInfo &MRI)
Tries to constant fold a vector binop with sources Op1 and Op2.
Definition Utils.cpp:809
DWARFExpression::Operation Op
LLVM_ABI SmallVector< APInt > ConstantFoldUnaryIntOp(unsigned Opcode, LLT DstTy, Register Src, const MachineRegisterInfo &MRI)
Tries to constant fold a unary integer operation (G_CTLZ, G_CTTZ, G_CTPOP and their _ZERO_POISON vari...
Definition Utils.cpp:935
GISelChangeObserver * Observer