1 //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- C++ -*-==//
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 /// This file implements the CSEMIRBuilder class which CSEs as it builds
11 //===----------------------------------------------------------------------===//
14 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
15 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
19 bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A
,
20 MachineBasicBlock::const_iterator B
) const {
21 auto MBBEnd
= getMBB().end();
24 assert(A
->getParent() == B
->getParent() &&
25 "Iterators should be in same block");
26 const MachineBasicBlock
*BBA
= A
->getParent();
27 MachineBasicBlock::const_iterator I
= BBA
->begin();
28 for (; &*I
!= A
&& &*I
!= B
; ++I
)
34 CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID
&ID
,
35 void *&NodeInsertPos
) {
36 GISelCSEInfo
*CSEInfo
= getCSEInfo();
37 assert(CSEInfo
&& "Can't get here without setting CSEInfo");
38 MachineBasicBlock
*CurMBB
= &getMBB();
40 CSEInfo
->getMachineInstrIfExists(ID
, CurMBB
, NodeInsertPos
);
42 CSEInfo
->countOpcodeHit(MI
->getOpcode());
43 auto CurrPos
= getInsertPt();
44 if (!dominates(MI
, CurrPos
))
45 CurMBB
->splice(CurrPos
, CurMBB
, MI
);
46 return MachineInstrBuilder(getMF(), MI
);
48 return MachineInstrBuilder();
51 bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc
) const {
52 const GISelCSEInfo
*CSEInfo
= getCSEInfo();
53 if (!CSEInfo
|| !CSEInfo
->shouldCSE(Opc
))
58 void CSEMIRBuilder::profileDstOp(const DstOp
&Op
,
59 GISelInstProfileBuilder
&B
) const {
60 switch (Op
.getDstOpKind()) {
61 case DstOp::DstType::Ty_RC
:
62 B
.addNodeIDRegType(Op
.getRegClass());
65 B
.addNodeIDRegType(Op
.getLLTTy(*getMRI()));
70 void CSEMIRBuilder::profileSrcOp(const SrcOp
&Op
,
71 GISelInstProfileBuilder
&B
) const {
72 switch (Op
.getSrcOpKind()) {
73 case SrcOp::SrcType::Ty_Predicate
:
74 B
.addNodeIDImmediate(static_cast<int64_t>(Op
.getPredicate()));
77 B
.addNodeIDRegType(Op
.getReg());
82 void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder
&B
,
84 // First add the MBB (Local CSE).
85 B
.addNodeIDMBB(&getMBB());
86 // Then add the opcode.
87 B
.addNodeIDOpcode(Opc
);
90 void CSEMIRBuilder::profileEverything(unsigned Opc
, ArrayRef
<DstOp
> DstOps
,
91 ArrayRef
<SrcOp
> SrcOps
,
92 Optional
<unsigned> Flags
,
93 GISelInstProfileBuilder
&B
) const {
95 profileMBBOpcode(B
, Opc
);
96 // Then add the DstOps.
97 profileDstOps(DstOps
, B
);
98 // Then add the SrcOps.
99 profileSrcOps(SrcOps
, B
);
100 // Add Flags if passed in.
102 B
.addNodeIDFlag(*Flags
);
105 MachineInstrBuilder
CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB
,
106 void *NodeInsertPos
) {
107 assert(canPerformCSEForOpc(MIB
->getOpcode()) &&
108 "Attempting to CSE illegal op");
109 MachineInstr
*MIBInstr
= MIB
;
110 getCSEInfo()->insertInstr(MIBInstr
, NodeInsertPos
);
114 bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef
<DstOp
> DstOps
) {
115 if (DstOps
.size() == 1)
116 return true; // always possible to emit copy to just 1 vreg.
118 return std::all_of(DstOps
.begin(), DstOps
.end(), [](const DstOp
&Op
) {
119 DstOp::DstType DT
= Op
.getDstOpKind();
120 return DT
== DstOp::DstType::Ty_LLT
|| DT
== DstOp::DstType::Ty_RC
;
125 CSEMIRBuilder::generateCopiesIfRequired(ArrayRef
<DstOp
> DstOps
,
126 MachineInstrBuilder
&MIB
) {
127 assert(checkCopyToDefsPossible(DstOps
) &&
128 "Impossible return a single MIB with copies to multiple defs");
129 if (DstOps
.size() == 1) {
130 const DstOp
&Op
= DstOps
[0];
131 if (Op
.getDstOpKind() == DstOp::DstType::Ty_Reg
)
132 return buildCopy(Op
.getReg(), MIB
->getOperand(0).getReg());
137 MachineInstrBuilder
CSEMIRBuilder::buildInstr(unsigned Opc
,
138 ArrayRef
<DstOp
> DstOps
,
139 ArrayRef
<SrcOp
> SrcOps
,
140 Optional
<unsigned> Flag
) {
144 case TargetOpcode::G_ADD
:
145 case TargetOpcode::G_AND
:
146 case TargetOpcode::G_ASHR
:
147 case TargetOpcode::G_LSHR
:
148 case TargetOpcode::G_MUL
:
149 case TargetOpcode::G_OR
:
150 case TargetOpcode::G_SHL
:
151 case TargetOpcode::G_SUB
:
152 case TargetOpcode::G_XOR
:
153 case TargetOpcode::G_UDIV
:
154 case TargetOpcode::G_SDIV
:
155 case TargetOpcode::G_UREM
:
156 case TargetOpcode::G_SREM
: {
157 // Try to constant fold these.
158 assert(SrcOps
.size() == 2 && "Invalid sources");
159 assert(DstOps
.size() == 1 && "Invalid dsts");
160 if (Optional
<APInt
> Cst
= ConstantFoldBinOp(Opc
, SrcOps
[0].getReg(),
161 SrcOps
[1].getReg(), *getMRI()))
162 return buildConstant(DstOps
[0], Cst
->getSExtValue());
166 bool CanCopy
= checkCopyToDefsPossible(DstOps
);
167 if (!canPerformCSEForOpc(Opc
))
168 return MachineIRBuilder::buildInstr(Opc
, DstOps
, SrcOps
, Flag
);
169 // If we can CSE this instruction, but involves generating copies to multiple
170 // regs, give up. This frequently happens to UNMERGEs.
172 auto MIB
= MachineIRBuilder::buildInstr(Opc
, DstOps
, SrcOps
, Flag
);
173 // CSEInfo would have tracked this instruction. Remove it from the temporary
175 getCSEInfo()->handleRemoveInst(&*MIB
);
179 GISelInstProfileBuilder
ProfBuilder(ID
, *getMRI());
180 void *InsertPos
= nullptr;
181 profileEverything(Opc
, DstOps
, SrcOps
, Flag
, ProfBuilder
);
182 MachineInstrBuilder MIB
= getDominatingInstrForID(ID
, InsertPos
);
184 // Handle generating copies here.
185 return generateCopiesIfRequired(DstOps
, MIB
);
187 // This instruction does not exist in the CSEInfo. Build it and CSE it.
188 MachineInstrBuilder NewMIB
=
189 MachineIRBuilder::buildInstr(Opc
, DstOps
, SrcOps
, Flag
);
190 return memoizeMI(NewMIB
, InsertPos
);
193 MachineInstrBuilder
CSEMIRBuilder::buildConstant(const DstOp
&Res
,
194 const ConstantInt
&Val
) {
195 constexpr unsigned Opc
= TargetOpcode::G_CONSTANT
;
196 if (!canPerformCSEForOpc(Opc
))
197 return MachineIRBuilder::buildConstant(Res
, Val
);
199 // For vectors, CSE the element only for now.
200 LLT Ty
= Res
.getLLTTy(*getMRI());
202 return buildSplatVector(Res
, buildConstant(Ty
.getElementType(), Val
));
205 GISelInstProfileBuilder
ProfBuilder(ID
, *getMRI());
206 void *InsertPos
= nullptr;
207 profileMBBOpcode(ProfBuilder
, Opc
);
208 profileDstOp(Res
, ProfBuilder
);
209 ProfBuilder
.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val
));
210 MachineInstrBuilder MIB
= getDominatingInstrForID(ID
, InsertPos
);
212 // Handle generating copies here.
213 return generateCopiesIfRequired({Res
}, MIB
);
216 MachineInstrBuilder NewMIB
= MachineIRBuilder::buildConstant(Res
, Val
);
217 return memoizeMI(NewMIB
, InsertPos
);
220 MachineInstrBuilder
CSEMIRBuilder::buildFConstant(const DstOp
&Res
,
221 const ConstantFP
&Val
) {
222 constexpr unsigned Opc
= TargetOpcode::G_FCONSTANT
;
223 if (!canPerformCSEForOpc(Opc
))
224 return MachineIRBuilder::buildFConstant(Res
, Val
);
226 // For vectors, CSE the element only for now.
227 LLT Ty
= Res
.getLLTTy(*getMRI());
229 return buildSplatVector(Res
, buildFConstant(Ty
.getElementType(), Val
));
232 GISelInstProfileBuilder
ProfBuilder(ID
, *getMRI());
233 void *InsertPos
= nullptr;
234 profileMBBOpcode(ProfBuilder
, Opc
);
235 profileDstOp(Res
, ProfBuilder
);
236 ProfBuilder
.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val
));
237 MachineInstrBuilder MIB
= getDominatingInstrForID(ID
, InsertPos
);
239 // Handle generating copies here.
240 return generateCopiesIfRequired({Res
}, MIB
);
242 MachineInstrBuilder NewMIB
= MachineIRBuilder::buildFConstant(Res
, Val
);
243 return memoizeMI(NewMIB
, InsertPos
);