1 //===- CSEInfo.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 //===----------------------------------------------------------------------===//
10 //===----------------------------------------------------------------------===//
11 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
12 #include "llvm/CodeGen/MachineRegisterInfo.h"
13 #include "llvm/InitializePasses.h"
14 #include "llvm/Support/Error.h"
16 #define DEBUG_TYPE "cseinfo"
19 char llvm::GISelCSEAnalysisWrapperPass::ID
= 0;
20 GISelCSEAnalysisWrapperPass::GISelCSEAnalysisWrapperPass()
21 : MachineFunctionPass(ID
) {
22 initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry());
24 INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass
, DEBUG_TYPE
,
25 "Analysis containing CSE Info", false, true)
26 INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass
, DEBUG_TYPE
,
27 "Analysis containing CSE Info", false, true)
29 /// -------- UniqueMachineInstr -------------//
31 void UniqueMachineInstr::Profile(FoldingSetNodeID
&ID
) {
32 GISelInstProfileBuilder(ID
, MI
->getMF()->getRegInfo()).addNodeID(MI
);
34 /// -----------------------------------------
36 /// --------- CSEConfigFull ---------- ///
37 bool CSEConfigFull::shouldCSEOpc(unsigned Opc
) {
41 case TargetOpcode::G_ADD
:
42 case TargetOpcode::G_AND
:
43 case TargetOpcode::G_ASHR
:
44 case TargetOpcode::G_LSHR
:
45 case TargetOpcode::G_MUL
:
46 case TargetOpcode::G_OR
:
47 case TargetOpcode::G_SHL
:
48 case TargetOpcode::G_SUB
:
49 case TargetOpcode::G_XOR
:
50 case TargetOpcode::G_UDIV
:
51 case TargetOpcode::G_SDIV
:
52 case TargetOpcode::G_UREM
:
53 case TargetOpcode::G_SREM
:
54 case TargetOpcode::G_CONSTANT
:
55 case TargetOpcode::G_FCONSTANT
:
56 case TargetOpcode::G_IMPLICIT_DEF
:
57 case TargetOpcode::G_ZEXT
:
58 case TargetOpcode::G_SEXT
:
59 case TargetOpcode::G_ANYEXT
:
60 case TargetOpcode::G_UNMERGE_VALUES
:
61 case TargetOpcode::G_TRUNC
:
62 case TargetOpcode::G_PTR_ADD
:
63 case TargetOpcode::G_EXTRACT
:
64 case TargetOpcode::G_SELECT
:
65 case TargetOpcode::G_BUILD_VECTOR
:
66 case TargetOpcode::G_BUILD_VECTOR_TRUNC
:
67 case TargetOpcode::G_SEXT_INREG
:
73 bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc
) {
74 return Opc
== TargetOpcode::G_CONSTANT
|| Opc
== TargetOpcode::G_FCONSTANT
||
75 Opc
== TargetOpcode::G_IMPLICIT_DEF
;
78 std::unique_ptr
<CSEConfigBase
>
79 llvm::getStandardCSEConfigForOpt(CodeGenOptLevel Level
) {
80 std::unique_ptr
<CSEConfigBase
> Config
;
81 if (Level
== CodeGenOptLevel::None
)
82 Config
= std::make_unique
<CSEConfigConstantOnly
>();
84 Config
= std::make_unique
<CSEConfigFull
>();
88 /// -----------------------------------------
90 /// -------- GISelCSEInfo -------------//
91 void GISelCSEInfo::setMF(MachineFunction
&MF
) {
93 this->MRI
= &MF
.getRegInfo();
96 GISelCSEInfo::~GISelCSEInfo() = default;
98 bool GISelCSEInfo::isUniqueMachineInstValid(
99 const UniqueMachineInstr
&UMI
) const {
100 // Should we check here and assert that the instruction has been fully
102 // FIXME: Any other checks required to be done here? Remove this method if
107 void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr
*UMI
) {
108 bool Removed
= CSEMap
.RemoveNode(UMI
);
110 assert(Removed
&& "Invalidation called on invalid UMI");
111 // FIXME: Should UMI be deallocated/destroyed?
114 UniqueMachineInstr
*GISelCSEInfo::getNodeIfExists(FoldingSetNodeID
&ID
,
115 MachineBasicBlock
*MBB
,
117 auto *Node
= CSEMap
.FindNodeOrInsertPos(ID
, InsertPos
);
119 if (!isUniqueMachineInstValid(*Node
)) {
120 invalidateUniqueMachineInstr(Node
);
124 if (Node
->MI
->getParent() != MBB
)
130 void GISelCSEInfo::insertNode(UniqueMachineInstr
*UMI
, void *InsertPos
) {
131 handleRecordedInsts();
133 UniqueMachineInstr
*MaybeNewNode
= UMI
;
135 CSEMap
.InsertNode(UMI
, InsertPos
);
137 MaybeNewNode
= CSEMap
.GetOrInsertNode(UMI
);
138 if (MaybeNewNode
!= UMI
) {
139 // A similar node exists in the folding set. Let's ignore this one.
142 assert(InstrMapping
.count(UMI
->MI
) == 0 &&
143 "This instruction should not be in the map");
144 InstrMapping
[UMI
->MI
] = MaybeNewNode
;
147 UniqueMachineInstr
*GISelCSEInfo::getUniqueInstrForMI(const MachineInstr
*MI
) {
148 assert(shouldCSE(MI
->getOpcode()) && "Trying to CSE an unsupported Node");
149 auto *Node
= new (UniqueInstrAllocator
) UniqueMachineInstr(MI
);
153 void GISelCSEInfo::insertInstr(MachineInstr
*MI
, void *InsertPos
) {
155 // If it exists in temporary insts, remove it.
156 TemporaryInsts
.remove(MI
);
157 auto *Node
= getUniqueInstrForMI(MI
);
158 insertNode(Node
, InsertPos
);
161 MachineInstr
*GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID
&ID
,
162 MachineBasicBlock
*MBB
,
164 handleRecordedInsts();
165 if (auto *Inst
= getNodeIfExists(ID
, MBB
, InsertPos
)) {
166 LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst
->MI
;);
167 return const_cast<MachineInstr
*>(Inst
->MI
);
172 void GISelCSEInfo::countOpcodeHit(unsigned Opc
) {
174 if (OpcodeHitTable
.count(Opc
))
175 OpcodeHitTable
[Opc
] += 1;
177 OpcodeHitTable
[Opc
] = 1;
182 void GISelCSEInfo::recordNewInstruction(MachineInstr
*MI
) {
183 if (shouldCSE(MI
->getOpcode())) {
184 TemporaryInsts
.insert(MI
);
185 LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI
);
189 void GISelCSEInfo::handleRecordedInst(MachineInstr
*MI
) {
190 assert(shouldCSE(MI
->getOpcode()) && "Invalid instruction for CSE");
191 auto *UMI
= InstrMapping
.lookup(MI
);
192 LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI
);
194 // Invalidate this MI.
195 invalidateUniqueMachineInstr(UMI
);
196 InstrMapping
.erase(MI
);
198 /// Now insert the new instruction.
200 /// We'll reuse the same UniqueMachineInstr to avoid the new
202 *UMI
= UniqueMachineInstr(MI
);
203 insertNode(UMI
, nullptr);
205 /// This is a new instruction. Allocate a new UniqueMachineInstr and
211 void GISelCSEInfo::handleRemoveInst(MachineInstr
*MI
) {
212 if (auto *UMI
= InstrMapping
.lookup(MI
)) {
213 invalidateUniqueMachineInstr(UMI
);
214 InstrMapping
.erase(MI
);
216 TemporaryInsts
.remove(MI
);
219 void GISelCSEInfo::handleRecordedInsts() {
220 if (HandlingRecordedInstrs
)
222 HandlingRecordedInstrs
= true;
223 while (!TemporaryInsts
.empty()) {
224 auto *MI
= TemporaryInsts
.pop_back_val();
225 handleRecordedInst(MI
);
227 HandlingRecordedInstrs
= false;
230 bool GISelCSEInfo::shouldCSE(unsigned Opc
) const {
231 assert(CSEOpt
.get() && "CSEConfig not set");
232 return CSEOpt
->shouldCSEOpc(Opc
);
235 void GISelCSEInfo::erasingInstr(MachineInstr
&MI
) { handleRemoveInst(&MI
); }
236 void GISelCSEInfo::createdInstr(MachineInstr
&MI
) { recordNewInstruction(&MI
); }
237 void GISelCSEInfo::changingInstr(MachineInstr
&MI
) {
238 // For now, perform erase, followed by insert.
242 void GISelCSEInfo::changedInstr(MachineInstr
&MI
) { changingInstr(MI
); }
244 void GISelCSEInfo::analyze(MachineFunction
&MF
) {
246 for (auto &MBB
: MF
) {
247 for (MachineInstr
&MI
: MBB
) {
248 if (!shouldCSE(MI
.getOpcode()))
250 LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI
);
256 void GISelCSEInfo::releaseMemory() {
259 InstrMapping
.clear();
260 UniqueInstrAllocator
.Reset();
261 TemporaryInsts
.clear();
266 OpcodeHitTable
.clear();
271 static const char *stringify(const MachineInstr
*MI
, std::string
&S
) {
272 raw_string_ostream
OS(S
);
274 return OS
.str().c_str();
278 Error
GISelCSEInfo::verify() {
281 handleRecordedInsts();
282 // For each instruction in map from MI -> UMI,
283 // Profile(MI) and make sure UMI is found for that profile.
284 for (auto &It
: InstrMapping
) {
285 FoldingSetNodeID TmpID
;
286 GISelInstProfileBuilder(TmpID
, *MRI
).addNodeID(It
.first
);
288 UniqueMachineInstr
*FoundNode
=
289 CSEMap
.FindNodeOrInsertPos(TmpID
, InsertPos
);
290 if (FoundNode
!= It
.second
)
291 return createStringError(std::errc::not_supported
,
292 "CSEMap mismatch, InstrMapping has MIs without "
293 "corresponding Nodes in CSEMap:\n%s",
294 stringify(It
.second
->MI
, S1
));
297 // For every node in the CSEMap, make sure that the InstrMapping
299 for (const UniqueMachineInstr
&UMI
: CSEMap
) {
300 if (!InstrMapping
.count(UMI
.MI
))
301 return createStringError(std::errc::not_supported
,
302 "Node in CSE without InstrMapping:\n%s",
303 stringify(UMI
.MI
, S1
));
305 if (InstrMapping
[UMI
.MI
] != &UMI
)
306 return createStringError(std::make_error_code(std::errc::not_supported
),
307 "Mismatch in CSE mapping:\n%s\n%s",
308 stringify(InstrMapping
[UMI
.MI
]->MI
, S1
),
309 stringify(UMI
.MI
, S2
));
312 return Error::success();
315 void GISelCSEInfo::print() {
316 LLVM_DEBUG(for (auto &It
318 dbgs() << "CSEInfo::CSE Hit for Opc " << It
.first
<< " : " << It
.second
322 /// -----------------------------------------
323 // ---- Profiling methods for FoldingSetNode --- //
324 const GISelInstProfileBuilder
&
325 GISelInstProfileBuilder::addNodeID(const MachineInstr
*MI
) const {
326 addNodeIDMBB(MI
->getParent());
327 addNodeIDOpcode(MI
->getOpcode());
328 for (const auto &Op
: MI
->operands())
329 addNodeIDMachineOperand(Op
);
330 addNodeIDFlag(MI
->getFlags());
334 const GISelInstProfileBuilder
&
335 GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc
) const {
340 const GISelInstProfileBuilder
&
341 GISelInstProfileBuilder::addNodeIDRegType(const LLT Ty
) const {
342 uint64_t Val
= Ty
.getUniqueRAWLLTData();
347 const GISelInstProfileBuilder
&
348 GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass
*RC
) const {
353 const GISelInstProfileBuilder
&
354 GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank
*RB
) const {
359 const GISelInstProfileBuilder
&
360 GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm
) const {
365 const GISelInstProfileBuilder
&
366 GISelInstProfileBuilder::addNodeIDRegNum(Register Reg
) const {
371 const GISelInstProfileBuilder
&
372 GISelInstProfileBuilder::addNodeIDRegType(const Register Reg
) const {
373 addNodeIDMachineOperand(MachineOperand::CreateReg(Reg
, false));
377 const GISelInstProfileBuilder
&
378 GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock
*MBB
) const {
383 const GISelInstProfileBuilder
&
384 GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag
) const {
390 const GISelInstProfileBuilder
&
391 GISelInstProfileBuilder::addNodeIDReg(Register Reg
) const {
392 LLT Ty
= MRI
.getType(Reg
);
394 addNodeIDRegType(Ty
);
396 if (const RegClassOrRegBank
&RCOrRB
= MRI
.getRegClassOrRegBank(Reg
)) {
397 if (const auto *RB
= dyn_cast_if_present
<const RegisterBank
*>(RCOrRB
))
398 addNodeIDRegType(RB
);
399 else if (const auto *RC
=
400 dyn_cast_if_present
<const TargetRegisterClass
*>(RCOrRB
))
401 addNodeIDRegType(RC
);
406 const GISelInstProfileBuilder
&GISelInstProfileBuilder::addNodeIDMachineOperand(
407 const MachineOperand
&MO
) const {
409 Register Reg
= MO
.getReg();
411 addNodeIDRegNum(Reg
);
413 // Profile the register properties.
415 assert(!MO
.isImplicit() && "Unhandled case");
416 } else if (MO
.isImm())
417 ID
.AddInteger(MO
.getImm());
418 else if (MO
.isCImm())
419 ID
.AddPointer(MO
.getCImm());
420 else if (MO
.isFPImm())
421 ID
.AddPointer(MO
.getFPImm());
422 else if (MO
.isPredicate())
423 ID
.AddInteger(MO
.getPredicate());
425 llvm_unreachable("Unhandled operand type");
426 // Handle other types
431 GISelCSEAnalysisWrapper::get(std::unique_ptr
<CSEConfigBase
> CSEOpt
,
433 if (!AlreadyComputed
|| Recompute
) {
434 Info
.releaseMemory();
435 Info
.setCSEConfig(std::move(CSEOpt
));
437 AlreadyComputed
= true;
441 void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
442 AU
.setPreservesAll();
443 MachineFunctionPass::getAnalysisUsage(AU
);
446 bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction
&MF
) {