LLVM 24.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 "Analysis containing CSE Info", false, true)
24
25/// -------- UniqueMachineInstr -------------//
26
28 GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI);
29}
30/// -----------------------------------------
31
32/// --------- CSEConfigFull ---------- ///
34 switch (Opc) {
35 default:
36 break;
37 case TargetOpcode::G_ADD:
38 case TargetOpcode::G_AND:
39 case TargetOpcode::G_ASHR:
40 case TargetOpcode::G_LSHR:
41 case TargetOpcode::G_MUL:
42 case TargetOpcode::G_OR:
43 case TargetOpcode::G_SHL:
44 case TargetOpcode::G_SUB:
45 case TargetOpcode::G_XOR:
46 case TargetOpcode::G_UDIV:
47 case TargetOpcode::G_SDIV:
48 case TargetOpcode::G_UREM:
49 case TargetOpcode::G_SREM:
50 case TargetOpcode::G_CONSTANT:
51 case TargetOpcode::G_FCONSTANT:
52 case TargetOpcode::G_IMPLICIT_DEF:
53 case TargetOpcode::G_ZEXT:
54 case TargetOpcode::G_SEXT:
55 case TargetOpcode::G_ANYEXT:
56 case TargetOpcode::G_UNMERGE_VALUES:
57 case TargetOpcode::G_TRUNC:
58 case TargetOpcode::G_PTR_ADD:
59 case TargetOpcode::G_EXTRACT:
60 case TargetOpcode::G_SELECT:
61 case TargetOpcode::G_BUILD_VECTOR:
62 case TargetOpcode::G_BUILD_VECTOR_TRUNC:
63 case TargetOpcode::G_SEXT_INREG:
64 case TargetOpcode::G_FADD:
65 case TargetOpcode::G_FSUB:
66 case TargetOpcode::G_FMUL:
67 case TargetOpcode::G_FDIV:
68 case TargetOpcode::G_FABS:
69 // TODO: support G_FNEG.
70 case TargetOpcode::G_FMAXNUM:
71 case TargetOpcode::G_FMINNUM:
72 case TargetOpcode::G_FMAXNUM_IEEE:
73 case TargetOpcode::G_FMINNUM_IEEE:
74 return true;
75 }
76 return false;
77}
78
80 return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT ||
81 Opc == TargetOpcode::G_IMPLICIT_DEF;
82}
83
84std::unique_ptr<CSEConfigBase>
86 std::unique_ptr<CSEConfigBase> Config;
87 if (Level == CodeGenOptLevel::None)
88 Config = std::make_unique<CSEConfigConstantOnly>();
89 else
90 Config = std::make_unique<CSEConfigFull>();
91 return Config;
92}
93
94/// -----------------------------------------
95
96/// -------- GISelCSEInfo -------------//
98 this->MF = &MF;
99 this->MRI = &MF.getRegInfo();
100}
101
103
104bool GISelCSEInfo::isUniqueMachineInstValid(
105 const UniqueMachineInstr &UMI) const {
106 // Should we check here and assert that the instruction has been fully
107 // constructed?
108 // FIXME: Any other checks required to be done here? Remove this method if
109 // none.
110 return true;
111}
112
113void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) {
114 bool Removed = CSEMap.erase(UMI);
115 (void)Removed;
116 assert(Removed && "Invalidation called on invalid UMI");
117 // FIXME: Should UMI be deallocated/destroyed?
118}
119
121GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID, MachineBasicBlock *MBB,
122 FoldingSetInsertToken &Token) {
123 auto *Node = CSEMap.lookup(ID, Token);
124 if (Node) {
125 if (!isUniqueMachineInstValid(*Node)) {
126 invalidateUniqueMachineInstr(Node);
127 return nullptr;
128 }
129
130 if (Node->MI->getParent() != MBB)
131 return nullptr;
132 }
133 return Node;
134}
135
136void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI,
137 FoldingSetInsertToken Token) {
139 assert(UMI);
140 UniqueMachineInstr *MaybeNewNode = UMI;
141 if (Token)
142 CSEMap.insert(UMI, Token);
143 else
144 MaybeNewNode = CSEMap.getOrInsert(UMI);
145 if (MaybeNewNode != UMI) {
146 // A similar node exists in the folding set. Let's ignore this one.
147 return;
148 }
149 assert(InstrMapping.count(UMI->MI) == 0 &&
150 "This instruction should not be in the map");
151 InstrMapping[UMI->MI] = MaybeNewNode;
152}
153
154UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) {
155 assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node");
156 auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI);
157 return Node;
158}
159
160void GISelCSEInfo::insertInstr(MachineInstr *MI, FoldingSetInsertToken Token) {
161 assert(MI);
162 // If it exists in temporary insts, remove it.
163 TemporaryInsts.remove(MI);
164 auto *Node = getUniqueInstrForMI(MI);
165 insertNode(Node, Token);
166}
167
169GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID,
171 FoldingSetInsertToken &Token) {
173 if (auto *Inst = getNodeIfExists(ID, MBB, Token)) {
174 LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst->MI);
175 return const_cast<MachineInstr *>(Inst->MI);
176 }
177 return nullptr;
178}
179
181#ifndef NDEBUG
182 ++OpcodeHitTable[Opc];
183#endif
184 // Else do nothing.
185}
186
188 if (shouldCSE(MI->getOpcode())) {
189 TemporaryInsts.insert(MI);
190 LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI);
191 }
192}
193
195 assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE");
196 auto *UMI = InstrMapping.lookup(MI);
197 LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI);
198 if (UMI) {
199 // Invalidate this MI.
200 invalidateUniqueMachineInstr(UMI);
201 InstrMapping.erase(MI);
202 }
203 /// Now insert the new instruction.
204 if (UMI) {
205 /// We'll reuse the same UniqueMachineInstr to avoid the new
206 /// allocation.
207 *UMI = UniqueMachineInstr(MI);
208 insertNode(UMI);
209 } else {
210 /// This is a new instruction. Allocate a new UniqueMachineInstr and
211 /// Insert.
212 insertInstr(MI);
213 }
214}
215
217 if (auto *UMI = InstrMapping.lookup(MI)) {
218 invalidateUniqueMachineInstr(UMI);
219 InstrMapping.erase(MI);
220 }
221 TemporaryInsts.remove(MI);
222}
223
225 if (HandlingRecordedInstrs)
226 return;
227 HandlingRecordedInstrs = true;
228 while (!TemporaryInsts.empty()) {
229 auto *MI = TemporaryInsts.pop_back_val();
231 }
232 HandlingRecordedInstrs = false;
233}
234
235bool GISelCSEInfo::shouldCSE(unsigned Opc) const {
236 assert(CSEOpt.get() && "CSEConfig not set");
237 return CSEOpt->shouldCSEOpc(Opc);
238}
239
243 // For now, perform erase, followed by insert.
246}
248
250 setMF(MF);
251 for (auto &MBB : MF) {
252 for (MachineInstr &MI : MBB) {
253 if (!shouldCSE(MI.getOpcode()))
254 continue;
255 LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI);
256 insertInstr(&MI);
257 }
258 }
259}
260
262 print();
263 CSEMap.clear();
264 InstrMapping.clear();
265 UniqueInstrAllocator.Reset();
266 TemporaryInsts.clear();
267 CSEOpt.reset();
268 MRI = nullptr;
269 MF = nullptr;
270#ifndef NDEBUG
271 OpcodeHitTable.clear();
272#endif
273}
274
275#ifndef NDEBUG
276static const char *stringify(const MachineInstr *MI, std::string &S) {
277 raw_string_ostream OS(S);
278 OS << *MI;
279 return OS.str().c_str();
280}
281#endif
282
284#ifndef NDEBUG
285 std::string S1, S2;
287 // For each instruction in map from MI -> UMI,
288 // Profile(MI) and make sure UMI is found for that profile.
289 for (auto &It : InstrMapping) {
290 FoldingSetNodeID TmpID;
291 GISelInstProfileBuilder(TmpID, *MRI).addNodeID(It.first);
293 UniqueMachineInstr *FoundNode = CSEMap.lookup(TmpID, Token);
294 if (FoundNode != It.second)
295 return createStringError(std::errc::not_supported,
296 "CSEMap mismatch, InstrMapping has MIs without "
297 "corresponding Nodes in CSEMap:\n%s",
298 stringify(It.second->MI, S1));
299 }
300
301 // For every node in the CSEMap, make sure that the InstrMapping
302 // points to it.
303 for (const UniqueMachineInstr &UMI : CSEMap) {
304 if (!InstrMapping.count(UMI.MI))
305 return createStringError(std::errc::not_supported,
306 "Node in CSE without InstrMapping:\n%s",
307 stringify(UMI.MI, S1));
308
309 if (InstrMapping[UMI.MI] != &UMI)
310 return createStringError(std::make_error_code(std::errc::not_supported),
311 "Mismatch in CSE mapping:\n%s\n%s",
312 stringify(InstrMapping[UMI.MI]->MI, S1),
313 stringify(UMI.MI, S2));
314 }
315#endif
316 return Error::success();
317}
318
320 LLVM_DEBUG({
321 for (auto &It : OpcodeHitTable)
322 dbgs() << "CSEInfo::CSE Hit for Opc " << It.first << " : " << It.second
323 << "\n";
324 });
325}
326/// -----------------------------------------
327// ---- Profiling methods for FoldingSetNode --- //
330 addNodeIDMBB(MI->getParent());
331 addNodeIDOpcode(MI->getOpcode());
332 for (const auto &Op : MI->operands())
334 addNodeIDFlag(MI->getFlags());
335 return *this;
336}
337
340 ID.AddInteger(Opc);
341 return *this;
342}
343
346 uint64_t Val = Ty.getUniqueRAWLLTData();
347 ID.AddInteger(Val);
348 return *this;
349}
350
353 ID.AddPointer(RC);
354 return *this;
355}
356
359 ID.AddPointer(RB);
360 return *this;
361}
362
364 MachineRegisterInfo::VRegAttrs Attrs) const {
365 addNodeIDRegType(Attrs.Ty);
366
367 const RegClassOrRegBank &RCOrRB = Attrs.RCOrRB;
368 if (RCOrRB) {
369 if (const auto *RB = dyn_cast_if_present<const RegisterBank *>(RCOrRB))
371 else
373 }
374 return *this;
375}
376
379 ID.AddInteger(Imm);
380 return *this;
381}
382
385 ID.AddInteger(Reg.id());
386 return *this;
387}
388
394
397 ID.AddPointer(MBB);
398 return *this;
399}
400
403 if (Flag)
404 ID.AddInteger(Flag);
405 return *this;
406}
407
410 addNodeIDRegType(MRI.getVRegAttrs(Reg));
411 return *this;
412}
413
415 const MachineOperand &MO) const {
416 if (MO.isReg()) {
417 Register Reg = MO.getReg();
418 if (!MO.isDef())
419 addNodeIDRegNum(Reg);
420
421 // Profile the register properties.
422 addNodeIDReg(Reg);
423 assert(!MO.isImplicit() && "Unhandled case");
424 } else if (MO.isImm())
425 ID.AddInteger(MO.getImm());
426 else if (MO.isCImm())
427 ID.AddPointer(MO.getCImm());
428 else if (MO.isFPImm())
429 ID.AddPointer(MO.getFPImm());
430 else if (MO.isPredicate())
431 ID.AddInteger(MO.getPredicate());
432 else
433 llvm_unreachable("Unhandled operand type");
434 // Handle other types
435 return *this;
436}
437
439GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfigBase> CSEOpt) {
440 if (!AlreadyComputed) {
441 Info.releaseMemory();
442 Info.setCSEConfig(std::move(CSEOpt));
443 Info.analyze(*MF);
444 AlreadyComputed = true;
445 }
446 return Info;
447}
448
449AnalysisKey GISelCSEAnalysis::Key;
450
454 std::unique_ptr<GISelCSEInfo> Info = std::make_unique<GISelCSEInfo>();
455 Info->setCSEConfig(getStandardCSEConfigForOpt(TM->getOptLevel()));
456 Info->analyze(MF);
457 return Info;
458}
459
464
467 Wrapper.setMF(MF);
468 return false;
469}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
constexpr LLT S1
MachineBasicBlock & MBB
static const char * stringify(const MachineInstr *MI, std::string &S)
Definition CSEInfo.cpp:276
Provides analysis for continuously CSEing during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
Load MIR Sample Profile
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
bool shouldCSEOpc(unsigned Opc) override
Definition CSEInfo.cpp:79
bool shouldCSEOpc(unsigned Opc) override
------— CSEConfigFull -------— ///
Definition CSEInfo.cpp:33
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Insertion token: a failed lookup fills it in, the matching insert consumes it.
Definition FoldingSet.h:300
This class is used to gather all the unique data bits of a node.
Definition FoldingSet.h:214
The actual analysis pass wrapper.
Definition CSEInfo.h:244
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:258
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition CSEInfo.cpp:460
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Definition CSEInfo.cpp:465
LLVM_ABI GISelCSEInfo & get(std::unique_ptr< CSEConfigBase > CSEOpt)
Takes a CSEConfigBase object that defines what opcodes get CSEd.
Definition CSEInfo.cpp:439
LLVM_ABI Result run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
Definition CSEInfo.cpp:452
std::unique_ptr< GISelCSEInfo > Result
Definition CSEInfo.h:236
The CSE Analysis object.
Definition CSEInfo.h:72
bool shouldCSE(unsigned Opc) const
Definition CSEInfo.cpp:235
~GISelCSEInfo() override
void changingInstr(MachineInstr &MI) override
This instruction is about to be mutated in some way.
Definition CSEInfo.cpp:242
void analyze(MachineFunction &MF)
Definition CSEInfo.cpp:249
void changedInstr(MachineInstr &MI) override
This instruction was mutated in some way.
Definition CSEInfo.cpp:247
void recordNewInstruction(MachineInstr *MI)
Records a newly created inst in a list and lazily insert it to the CSEMap.
Definition CSEInfo.cpp:187
void setMF(MachineFunction &MF)
-----— GISelCSEInfo ----------—//
Definition CSEInfo.cpp:97
void erasingInstr(MachineInstr &MI) override
An instruction is about to be erased.
Definition CSEInfo.cpp:240
void countOpcodeHit(unsigned Opc)
Definition CSEInfo.cpp:180
void handleRecordedInsts()
Use this callback to insert all the recorded instructions.
Definition CSEInfo.cpp:224
void handleRecordedInst(MachineInstr *MI)
Use this callback to inform CSE about a newly fully created instruction.
Definition CSEInfo.cpp:194
void handleRemoveInst(MachineInstr *MI)
Remove this inst from the CSE map.
Definition CSEInfo.cpp:216
void createdInstr(MachineInstr &MI) override
An instruction has been created and inserted into the function.
Definition CSEInfo.cpp:241
LLVM_ABI const GISelInstProfileBuilder & addNodeIDOpcode(unsigned Opc) const
Definition CSEInfo.cpp:339
LLVM_ABI const GISelInstProfileBuilder & addNodeIDRegNum(Register Reg) const
Definition CSEInfo.cpp:384
LLVM_ABI const GISelInstProfileBuilder & addNodeIDFlag(unsigned Flag) const
Definition CSEInfo.cpp:402
LLVM_ABI const GISelInstProfileBuilder & addNodeIDImmediate(int64_t Imm) const
Definition CSEInfo.cpp:378
LLVM_ABI const GISelInstProfileBuilder & addNodeIDReg(Register Reg) const
Definition CSEInfo.cpp:409
LLVM_ABI const GISelInstProfileBuilder & addNodeID(const MachineInstr *MI) const
Definition CSEInfo.cpp:329
LLVM_ABI const GISelInstProfileBuilder & addNodeIDMBB(const MachineBasicBlock *MBB) const
Definition CSEInfo.cpp:396
GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI)
Definition CSEInfo.h:179
LLVM_ABI const GISelInstProfileBuilder & addNodeIDRegType(const LLT Ty) const
Definition CSEInfo.cpp:345
LLVM_ABI const GISelInstProfileBuilder & addNodeIDMachineOperand(const MachineOperand &MO) const
Definition CSEInfo.cpp:414
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.
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 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.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
A class that wraps MachineInstrs and derives from FoldingSetNode in order to be uniqued in a CSEMap.
Definition CSEInfo.h:32
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
PointerUnion< const TargetRegisterClass *, const RegisterBank * > RegClassOrRegBank
Convenient type to represent either a register class or a register bank.
auto dyn_cast_if_present(const Y &Val)
dyn_cast_if_present<X> - Functionally identical to dyn_cast, except that a null (or none in the case ...
Definition Casting.h:732
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
LLVM_ABI std::unique_ptr< CSEConfigBase > getStandardCSEConfigForOpt(CodeGenOptLevel Level)
Definition CSEInfo.cpp:85
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
CodeGenOptLevel
Code generation optimization level.
Definition CodeGen.h:149
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29
All attributes(register class or bank and low-level type) a virtual register can have.