LLVM 21.0.0git
CSEInfo.cpp
Go to the documentation of this file.
1//===- CSEInfo.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//
10//===----------------------------------------------------------------------===//
14#include "llvm/Support/Error.h"
15
16#define DEBUG_TYPE "cseinfo"
17
18using namespace llvm;
23}
25 "Analysis containing CSE Info", false, true)
27 "Analysis containing CSE Info", false, true)
28
29/// -------- UniqueMachineInstr -------------//
30
32 GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI);
33}
34/// -----------------------------------------
35
36/// --------- CSEConfigFull ---------- ///
37bool CSEConfigFull::shouldCSEOpc(unsigned Opc) {
38 switch (Opc) {
39 default:
40 break;
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:
68 case TargetOpcode::G_FADD:
69 case TargetOpcode::G_FSUB:
70 case TargetOpcode::G_FMUL:
71 case TargetOpcode::G_FDIV:
72 case TargetOpcode::G_FABS:
73 // TODO: support G_FNEG.
74 case TargetOpcode::G_FMAXNUM:
75 case TargetOpcode::G_FMINNUM:
76 case TargetOpcode::G_FMAXNUM_IEEE:
77 case TargetOpcode::G_FMINNUM_IEEE:
78 return true;
79 }
80 return false;
81}
82
84 return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT ||
85 Opc == TargetOpcode::G_IMPLICIT_DEF;
86}
87
88std::unique_ptr<CSEConfigBase>
90 std::unique_ptr<CSEConfigBase> Config;
91 if (Level == CodeGenOptLevel::None)
92 Config = std::make_unique<CSEConfigConstantOnly>();
93 else
94 Config = std::make_unique<CSEConfigFull>();
95 return Config;
96}
97
98/// -----------------------------------------
99
100/// -------- GISelCSEInfo -------------//
102 this->MF = &MF;
103 this->MRI = &MF.getRegInfo();
104}
105
107
108bool GISelCSEInfo::isUniqueMachineInstValid(
109 const UniqueMachineInstr &UMI) const {
110 // Should we check here and assert that the instruction has been fully
111 // constructed?
112 // FIXME: Any other checks required to be done here? Remove this method if
113 // none.
114 return true;
115}
116
117void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) {
118 bool Removed = CSEMap.RemoveNode(UMI);
119 (void)Removed;
120 assert(Removed && "Invalidation called on invalid UMI");
121 // FIXME: Should UMI be deallocated/destroyed?
122}
123
124UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID,
126 void *&InsertPos) {
127 auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos);
128 if (Node) {
129 if (!isUniqueMachineInstValid(*Node)) {
130 invalidateUniqueMachineInstr(Node);
131 return nullptr;
132 }
133
134 if (Node->MI->getParent() != MBB)
135 return nullptr;
136 }
137 return Node;
138}
139
140void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) {
142 assert(UMI);
143 UniqueMachineInstr *MaybeNewNode = UMI;
144 if (InsertPos)
145 CSEMap.InsertNode(UMI, InsertPos);
146 else
147 MaybeNewNode = CSEMap.GetOrInsertNode(UMI);
148 if (MaybeNewNode != UMI) {
149 // A similar node exists in the folding set. Let's ignore this one.
150 return;
151 }
152 assert(InstrMapping.count(UMI->MI) == 0 &&
153 "This instruction should not be in the map");
154 InstrMapping[UMI->MI] = MaybeNewNode;
155}
156
157UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) {
158 assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node");
159 auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI);
160 return Node;
161}
162
163void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) {
164 assert(MI);
165 // If it exists in temporary insts, remove it.
166 TemporaryInsts.remove(MI);
167 auto *Node = getUniqueInstrForMI(MI);
168 insertNode(Node, InsertPos);
169}
170
171MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID,
173 void *&InsertPos) {
175 if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) {
176 LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst->MI);
177 return const_cast<MachineInstr *>(Inst->MI);
178 }
179 return nullptr;
180}
181
183#ifndef NDEBUG
184 ++OpcodeHitTable[Opc];
185#endif
186 // Else do nothing.
187}
188
190 if (shouldCSE(MI->getOpcode())) {
191 TemporaryInsts.insert(MI);
192 LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI);
193 }
194}
195
197 assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE");
198 auto *UMI = InstrMapping.lookup(MI);
199 LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI);
200 if (UMI) {
201 // Invalidate this MI.
202 invalidateUniqueMachineInstr(UMI);
203 InstrMapping.erase(MI);
204 }
205 /// Now insert the new instruction.
206 if (UMI) {
207 /// We'll reuse the same UniqueMachineInstr to avoid the new
208 /// allocation.
209 *UMI = UniqueMachineInstr(MI);
210 insertNode(UMI, nullptr);
211 } else {
212 /// This is a new instruction. Allocate a new UniqueMachineInstr and
213 /// Insert.
214 insertInstr(MI);
215 }
216}
217
219 if (auto *UMI = InstrMapping.lookup(MI)) {
220 invalidateUniqueMachineInstr(UMI);
221 InstrMapping.erase(MI);
222 }
223 TemporaryInsts.remove(MI);
224}
225
227 if (HandlingRecordedInstrs)
228 return;
229 HandlingRecordedInstrs = true;
230 while (!TemporaryInsts.empty()) {
231 auto *MI = TemporaryInsts.pop_back_val();
233 }
234 HandlingRecordedInstrs = false;
235}
236
237bool GISelCSEInfo::shouldCSE(unsigned Opc) const {
238 assert(CSEOpt.get() && "CSEConfig not set");
239 return CSEOpt->shouldCSEOpc(Opc);
240}
241
245 // For now, perform erase, followed by insert.
248}
250
252 setMF(MF);
253 for (auto &MBB : MF) {
254 for (MachineInstr &MI : MBB) {
255 if (!shouldCSE(MI.getOpcode()))
256 continue;
257 LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI);
258 insertInstr(&MI);
259 }
260 }
261}
262
264 print();
265 CSEMap.clear();
266 InstrMapping.clear();
267 UniqueInstrAllocator.Reset();
268 TemporaryInsts.clear();
269 CSEOpt.reset();
270 MRI = nullptr;
271 MF = nullptr;
272#ifndef NDEBUG
273 OpcodeHitTable.clear();
274#endif
275}
276
277#ifndef NDEBUG
278static const char *stringify(const MachineInstr *MI, std::string &S) {
280 OS << *MI;
281 return OS.str().c_str();
282}
283#endif
284
286#ifndef NDEBUG
287 std::string S1, S2;
289 // For each instruction in map from MI -> UMI,
290 // Profile(MI) and make sure UMI is found for that profile.
291 for (auto &It : InstrMapping) {
292 FoldingSetNodeID TmpID;
293 GISelInstProfileBuilder(TmpID, *MRI).addNodeID(It.first);
294 void *InsertPos;
295 UniqueMachineInstr *FoundNode =
296 CSEMap.FindNodeOrInsertPos(TmpID, InsertPos);
297 if (FoundNode != It.second)
298 return createStringError(std::errc::not_supported,
299 "CSEMap mismatch, InstrMapping has MIs without "
300 "corresponding Nodes in CSEMap:\n%s",
301 stringify(It.second->MI, S1));
302 }
303
304 // For every node in the CSEMap, make sure that the InstrMapping
305 // points to it.
306 for (const UniqueMachineInstr &UMI : CSEMap) {
307 if (!InstrMapping.count(UMI.MI))
308 return createStringError(std::errc::not_supported,
309 "Node in CSE without InstrMapping:\n%s",
310 stringify(UMI.MI, S1));
311
312 if (InstrMapping[UMI.MI] != &UMI)
313 return createStringError(std::make_error_code(std::errc::not_supported),
314 "Mismatch in CSE mapping:\n%s\n%s",
315 stringify(InstrMapping[UMI.MI]->MI, S1),
316 stringify(UMI.MI, S2));
317 }
318#endif
319 return Error::success();
320}
321
323 LLVM_DEBUG({
324 for (auto &It : OpcodeHitTable)
325 dbgs() << "CSEInfo::CSE Hit for Opc " << It.first << " : " << It.second
326 << "\n";
327 });
328}
329/// -----------------------------------------
330// ---- Profiling methods for FoldingSetNode --- //
333 addNodeIDMBB(MI->getParent());
334 addNodeIDOpcode(MI->getOpcode());
335 for (const auto &Op : MI->operands())
337 addNodeIDFlag(MI->getFlags());
338 return *this;
339}
340
343 ID.AddInteger(Opc);
344 return *this;
345}
346
349 uint64_t Val = Ty.getUniqueRAWLLTData();
350 ID.AddInteger(Val);
351 return *this;
352}
353
356 ID.AddPointer(RC);
357 return *this;
358}
359
362 ID.AddPointer(RB);
363 return *this;
364}
365
367 MachineRegisterInfo::VRegAttrs Attrs) const {
368 addNodeIDRegType(Attrs.Ty);
369
370 const RegClassOrRegBank &RCOrRB = Attrs.RCOrRB;
371 if (RCOrRB) {
372 if (const auto *RB = dyn_cast_if_present<const RegisterBank *>(RCOrRB))
374 else
375 addNodeIDRegType(cast<const TargetRegisterClass *>(RCOrRB));
376 }
377 return *this;
378}
379
382 ID.AddInteger(Imm);
383 return *this;
384}
385
388 ID.AddInteger(Reg);
389 return *this;
390}
391
395 return *this;
396}
397
400 ID.AddPointer(MBB);
401 return *this;
402}
403
406 if (Flag)
407 ID.AddInteger(Flag);
408 return *this;
409}
410
414 return *this;
415}
416
418 const MachineOperand &MO) const {
419 if (MO.isReg()) {
420 Register Reg = MO.getReg();
421 if (!MO.isDef())
422 addNodeIDRegNum(Reg);
423
424 // Profile the register properties.
425 addNodeIDReg(Reg);
426 assert(!MO.isImplicit() && "Unhandled case");
427 } else if (MO.isImm())
428 ID.AddInteger(MO.getImm());
429 else if (MO.isCImm())
430 ID.AddPointer(MO.getCImm());
431 else if (MO.isFPImm())
432 ID.AddPointer(MO.getFPImm());
433 else if (MO.isPredicate())
434 ID.AddInteger(MO.getPredicate());
435 else
436 llvm_unreachable("Unhandled operand type");
437 // Handle other types
438 return *this;
439}
440
442GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfigBase> CSEOpt,
443 bool Recompute) {
444 if (!AlreadyComputed || Recompute) {
445 Info.releaseMemory();
446 Info.setCSEConfig(std::move(CSEOpt));
447 Info.analyze(*MF);
448 AlreadyComputed = true;
449 }
450 return Info;
451}
453 AU.setPreservesAll();
455}
456
459 Wrapper.setMF(MF);
460 return false;
461}
static const LLT S1
MachineBasicBlock & MBB
basic Basic Alias true
block Block Frequency Analysis
static const char * stringify(const MachineInstr *MI, std::string &S)
Definition: CSEInfo.cpp:278
Provides analysis for continuously CSEing during GISel passes.
#define LLVM_DEBUG(...)
Definition: Debug.h:106
RelaxConfig Config
Definition: ELF_riscv.cpp:506
#define DEBUG_TYPE
IRTranslator LLVM IR MI
Load MIR Sample Profile
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:57
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
separate const offset from Split GEPs to a variadic base and a constant offset for better CSE
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
void Reset()
Deallocate all but the current slab and reset the current pointer to the beginning of it,...
Definition: Allocator.h:123
bool shouldCSEOpc(unsigned Opc) override
Definition: CSEInfo.cpp:83
bool shouldCSEOpc(unsigned Opc) override
------— CSEConfigFull -------— ///
Definition: CSEInfo.cpp:37
This class represents an Operation in the Expression.
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
FoldingSetNodeID - This class is used to gather all the unique data bits of a node.
Definition: FoldingSet.h:327
The actual analysis pass wrapper.
Definition: CSEInfo.h:225
void releaseMemory() override
releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...
Definition: CSEInfo.h:239
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: CSEInfo.cpp:452
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Definition: CSEInfo.cpp:457
void setMF(MachineFunction &MFunc)
Definition: CSEInfo.h:219
GISelCSEInfo & get(std::unique_ptr< CSEConfigBase > CSEOpt, bool ReCompute=false)
Takes a CSEConfigBase object that defines what opcodes get CSEd.
Definition: CSEInfo.cpp:442
The CSE Analysis object.
Definition: CSEInfo.h:70
bool shouldCSE(unsigned Opc) const
Definition: CSEInfo.cpp:237
void changingInstr(MachineInstr &MI) override
This instruction is about to be mutated in some way.
Definition: CSEInfo.cpp:244
void analyze(MachineFunction &MF)
Definition: CSEInfo.cpp:251
void changedInstr(MachineInstr &MI) override
This instruction was mutated in some way.
Definition: CSEInfo.cpp:249
void recordNewInstruction(MachineInstr *MI)
Records a newly created inst in a list and lazily insert it to the CSEMap.
Definition: CSEInfo.cpp:189
void setMF(MachineFunction &MF)
-----— GISelCSEInfo ----------—//
Definition: CSEInfo.cpp:101
virtual ~GISelCSEInfo()
void erasingInstr(MachineInstr &MI) override
An instruction is about to be erased.
Definition: CSEInfo.cpp:242
void countOpcodeHit(unsigned Opc)
Definition: CSEInfo.cpp:182
void setCSEConfig(std::unique_ptr< CSEConfigBase > Opt)
Definition: CSEInfo.h:147
void handleRecordedInsts()
Use this callback to insert all the recorded instructions.
Definition: CSEInfo.cpp:226
void handleRecordedInst(MachineInstr *MI)
Use this callback to inform CSE about a newly fully created instruction.
Definition: CSEInfo.cpp:196
void handleRemoveInst(MachineInstr *MI)
Remove this inst from the CSE map.
Definition: CSEInfo.cpp:218
void releaseMemory()
Definition: CSEInfo.cpp:263
void createdInstr(MachineInstr &MI) override
An instruction has been created and inserted into the function.
Definition: CSEInfo.cpp:243
const GISelInstProfileBuilder & addNodeIDOpcode(unsigned Opc) const
Definition: CSEInfo.cpp:342
const GISelInstProfileBuilder & addNodeIDRegNum(Register Reg) const
Definition: CSEInfo.cpp:387
const GISelInstProfileBuilder & addNodeIDFlag(unsigned Flag) const
Definition: CSEInfo.cpp:405
const GISelInstProfileBuilder & addNodeIDImmediate(int64_t Imm) const
Definition: CSEInfo.cpp:381
const GISelInstProfileBuilder & addNodeIDReg(Register Reg) const
Definition: CSEInfo.cpp:412
const GISelInstProfileBuilder & addNodeID(const MachineInstr *MI) const
Definition: CSEInfo.cpp:332
const GISelInstProfileBuilder & addNodeIDMBB(const MachineBasicBlock *MBB) const
Definition: CSEInfo.cpp:399
const GISelInstProfileBuilder & addNodeIDRegType(const LLT Ty) const
Definition: CSEInfo.cpp:348
const GISelInstProfileBuilder & addNodeIDMachineOperand(const MachineOperand &MO) const
Definition: CSEInfo.cpp:417
void insert(MachineInstr *I)
Add the specified instruction to the worklist if it isn't already in it.
Definition: GISelWorkList.h:74
MachineInstr * pop_back_val()
bool empty() const
Definition: GISelWorkList.h:38
void remove(const MachineInstr *I)
Remove I from the worklist if it exists.
Definition: GISelWorkList.h:83
constexpr uint64_t getUniqueRAWLLTData() const
Definition: LowLevelType.h:404
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Representation of each machine instruction.
Definition: MachineInstr.h:71
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
int64_t getImm() const
bool isImplicit() const
bool isPredicate() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
bool isFPImm() const
isFPImm - Tests if this is a MO_FPImmediate operand.
VRegAttrs getVRegAttrs(Register Reg) const
Returns register class or bank and low level type of Reg.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
This class implements the register bank concept.
Definition: RegisterBank.h:28
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
A class that wraps MachineInstrs and derives from FoldingSetNode in order to be uniqued in a CSEMap.
Definition: CSEInfo.h:30
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1291
std::unique_ptr< CSEConfigBase > getStandardCSEConfigForOpt(CodeGenOptLevel Level)
Definition: CSEInfo.cpp:89
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
CodeGenOptLevel
Code generation optimization level.
Definition: CodeGen.h:54
void initializeGISelCSEAnalysisWrapperPassPass(PassRegistry &)
All attributes(register class or bank and low-level type) a virtual register can have.