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 //===----------------------------------------------------------------------===//
11 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
12 #include "llvm/CodeGen/MachineRegisterInfo.h"
13 #include "llvm/InitializePasses.h"
14 #include "llvm/Support/Error.h"
15 
16 #define DEBUG_TYPE "cseinfo"
17 
18 using namespace llvm;
19 char llvm::GISelCSEAnalysisWrapperPass::ID = 0;
20 GISelCSEAnalysisWrapperPass::GISelCSEAnalysisWrapperPass()
21     : MachineFunctionPass(ID) {
22   initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry());
23 }
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)
28 
29 /// -------- UniqueMachineInstr -------------//
30 
31 void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) {
32   GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI);
33 }
34 /// -----------------------------------------
35 
36 /// --------- CSEConfigFull ---------- ///
37 bool 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     return true;
65   }
66   return false;
67 }
68 
69 bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) {
70   return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT ||
71          Opc == TargetOpcode::G_IMPLICIT_DEF;
72 }
73 
74 std::unique_ptr<CSEConfigBase>
75 llvm::getStandardCSEConfigForOpt(CodeGenOpt::Level Level) {
76   std::unique_ptr<CSEConfigBase> Config;
77   if (Level == CodeGenOpt::None)
78     Config = std::make_unique<CSEConfigConstantOnly>();
79   else
80     Config = std::make_unique<CSEConfigFull>();
81   return Config;
82 }
83 
84 /// -----------------------------------------
85 
86 /// -------- GISelCSEInfo -------------//
87 void GISelCSEInfo::setMF(MachineFunction &MF) {
88   this->MF = &MF;
89   this->MRI = &MF.getRegInfo();
90 }
91 
92 GISelCSEInfo::~GISelCSEInfo() = default;
93 
94 bool GISelCSEInfo::isUniqueMachineInstValid(
95     const UniqueMachineInstr &UMI) const {
96   // Should we check here and assert that the instruction has been fully
97   // constructed?
98   // FIXME: Any other checks required to be done here? Remove this method if
99   // none.
100   return true;
101 }
102 
103 void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) {
104   bool Removed = CSEMap.RemoveNode(UMI);
105   (void)Removed;
106   assert(Removed && "Invalidation called on invalid UMI");
107   // FIXME: Should UMI be deallocated/destroyed?
108 }
109 
110 UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID,
111                                                   MachineBasicBlock *MBB,
112                                                   void *&InsertPos) {
113   auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos);
114   if (Node) {
115     if (!isUniqueMachineInstValid(*Node)) {
116       invalidateUniqueMachineInstr(Node);
117       return nullptr;
118     }
119 
120     if (Node->MI->getParent() != MBB)
121       return nullptr;
122   }
123   return Node;
124 }
125 
126 void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) {
127   handleRecordedInsts();
128   assert(UMI);
129   UniqueMachineInstr *MaybeNewNode = UMI;
130   if (InsertPos)
131     CSEMap.InsertNode(UMI, InsertPos);
132   else
133     MaybeNewNode = CSEMap.GetOrInsertNode(UMI);
134   if (MaybeNewNode != UMI) {
135     // A similar node exists in the folding set. Let's ignore this one.
136     return;
137   }
138   assert(InstrMapping.count(UMI->MI) == 0 &&
139          "This instruction should not be in the map");
140   InstrMapping[UMI->MI] = MaybeNewNode;
141 }
142 
143 UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) {
144   assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node");
145   auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI);
146   return Node;
147 }
148 
149 void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) {
150   assert(MI);
151   // If it exists in temporary insts, remove it.
152   TemporaryInsts.remove(MI);
153   auto *Node = getUniqueInstrForMI(MI);
154   insertNode(Node, InsertPos);
155 }
156 
157 MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID,
158                                                     MachineBasicBlock *MBB,
159                                                     void *&InsertPos) {
160   handleRecordedInsts();
161   if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) {
162     LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst->MI;);
163     return const_cast<MachineInstr *>(Inst->MI);
164   }
165   return nullptr;
166 }
167 
168 void GISelCSEInfo::countOpcodeHit(unsigned Opc) {
169 #ifndef NDEBUG
170   if (OpcodeHitTable.count(Opc))
171     OpcodeHitTable[Opc] += 1;
172   else
173     OpcodeHitTable[Opc] = 1;
174 #endif
175   // Else do nothing.
176 }
177 
178 void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) {
179   if (shouldCSE(MI->getOpcode())) {
180     TemporaryInsts.insert(MI);
181     LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI);
182   }
183 }
184 
185 void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) {
186   assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE");
187   auto *UMI = InstrMapping.lookup(MI);
188   LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI);
189   if (UMI) {
190     // Invalidate this MI.
191     invalidateUniqueMachineInstr(UMI);
192     InstrMapping.erase(MI);
193   }
194   /// Now insert the new instruction.
195   if (UMI) {
196     /// We'll reuse the same UniqueMachineInstr to avoid the new
197     /// allocation.
198     *UMI = UniqueMachineInstr(MI);
199     insertNode(UMI, nullptr);
200   } else {
201     /// This is a new instruction. Allocate a new UniqueMachineInstr and
202     /// Insert.
203     insertInstr(MI);
204   }
205 }
206 
207 void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) {
208   if (auto *UMI = InstrMapping.lookup(MI)) {
209     invalidateUniqueMachineInstr(UMI);
210     InstrMapping.erase(MI);
211   }
212   TemporaryInsts.remove(MI);
213 }
214 
215 void GISelCSEInfo::handleRecordedInsts() {
216   while (!TemporaryInsts.empty()) {
217     auto *MI = TemporaryInsts.pop_back_val();
218     handleRecordedInst(MI);
219   }
220 }
221 
222 bool GISelCSEInfo::shouldCSE(unsigned Opc) const {
223   assert(CSEOpt.get() && "CSEConfig not set");
224   return CSEOpt->shouldCSEOpc(Opc);
225 }
226 
227 void GISelCSEInfo::erasingInstr(MachineInstr &MI) { handleRemoveInst(&MI); }
228 void GISelCSEInfo::createdInstr(MachineInstr &MI) { recordNewInstruction(&MI); }
229 void GISelCSEInfo::changingInstr(MachineInstr &MI) {
230   // For now, perform erase, followed by insert.
231   erasingInstr(MI);
232   createdInstr(MI);
233 }
234 void GISelCSEInfo::changedInstr(MachineInstr &MI) { changingInstr(MI); }
235 
236 void GISelCSEInfo::analyze(MachineFunction &MF) {
237   setMF(MF);
238   for (auto &MBB : MF) {
239     if (MBB.empty())
240       continue;
241     for (MachineInstr &MI : MBB) {
242       if (!shouldCSE(MI.getOpcode()))
243         continue;
244       LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI);
245       insertInstr(&MI);
246     }
247   }
248 }
249 
250 void GISelCSEInfo::releaseMemory() {
251   print();
252   CSEMap.clear();
253   InstrMapping.clear();
254   UniqueInstrAllocator.Reset();
255   TemporaryInsts.clear();
256   CSEOpt.reset();
257   MRI = nullptr;
258   MF = nullptr;
259 #ifndef NDEBUG
260   OpcodeHitTable.clear();
261 #endif
262 }
263 
264 #ifndef NDEBUG
265 static const char *stringify(const MachineInstr *MI, std::string &S) {
266   raw_string_ostream OS(S);
267   OS << *MI;
268   return OS.str().c_str();
269 }
270 #endif
271 
272 Error GISelCSEInfo::verify() {
273 #ifndef NDEBUG
274   std::string S1, S2;
275   handleRecordedInsts();
276   // For each instruction in map from MI -> UMI,
277   // Profile(MI) and make sure UMI is found for that profile.
278   for (auto &It : InstrMapping) {
279     FoldingSetNodeID TmpID;
280     GISelInstProfileBuilder(TmpID, *MRI).addNodeID(It.first);
281     void *InsertPos;
282     UniqueMachineInstr *FoundNode =
283         CSEMap.FindNodeOrInsertPos(TmpID, InsertPos);
284     if (FoundNode != It.second)
285       return createStringError(std::errc::not_supported,
286                                "CSEMap mismatch, InstrMapping has MIs without "
287                                "corresponding Nodes in CSEMap:\n%s",
288                                stringify(It.second->MI, S1));
289   }
290 
291   // For every node in the CSEMap, make sure that the InstrMapping
292   // points to it.
293   for (const UniqueMachineInstr &UMI : CSEMap) {
294     if (!InstrMapping.count(UMI.MI))
295       return createStringError(std::errc::not_supported,
296                                "Node in CSE without InstrMapping:\n%s",
297                                stringify(UMI.MI, S1));
298 
299     if (InstrMapping[UMI.MI] != &UMI)
300       return createStringError(std::make_error_code(std::errc::not_supported),
301                                "Mismatch in CSE mapping:\n%s\n%s",
302                                stringify(InstrMapping[UMI.MI]->MI, S1),
303                                stringify(UMI.MI, S2));
304   }
305 #endif
306   return Error::success();
307 }
308 
309 void GISelCSEInfo::print() {
310   LLVM_DEBUG(for (auto &It
311                   : OpcodeHitTable) {
312     dbgs() << "CSEInfo::CSE Hit for Opc " << It.first << " : " << It.second
313            << "\n";
314   };);
315 }
316 /// -----------------------------------------
317 // ---- Profiling methods for FoldingSetNode --- //
318 const GISelInstProfileBuilder &
319 GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const {
320   addNodeIDMBB(MI->getParent());
321   addNodeIDOpcode(MI->getOpcode());
322   for (const auto &Op : MI->operands())
323     addNodeIDMachineOperand(Op);
324   addNodeIDFlag(MI->getFlags());
325   return *this;
326 }
327 
328 const GISelInstProfileBuilder &
329 GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const {
330   ID.AddInteger(Opc);
331   return *this;
332 }
333 
334 const GISelInstProfileBuilder &
335 GISelInstProfileBuilder::addNodeIDRegType(const LLT Ty) const {
336   uint64_t Val = Ty.getUniqueRAWLLTData();
337   ID.AddInteger(Val);
338   return *this;
339 }
340 
341 const GISelInstProfileBuilder &
342 GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const {
343   ID.AddPointer(RC);
344   return *this;
345 }
346 
347 const GISelInstProfileBuilder &
348 GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const {
349   ID.AddPointer(RB);
350   return *this;
351 }
352 
353 const GISelInstProfileBuilder &
354 GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const {
355   ID.AddInteger(Imm);
356   return *this;
357 }
358 
359 const GISelInstProfileBuilder &
360 GISelInstProfileBuilder::addNodeIDRegNum(Register Reg) const {
361   ID.AddInteger(Reg);
362   return *this;
363 }
364 
365 const GISelInstProfileBuilder &
366 GISelInstProfileBuilder::addNodeIDRegType(const Register Reg) const {
367   addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false));
368   return *this;
369 }
370 
371 const GISelInstProfileBuilder &
372 GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const {
373   ID.AddPointer(MBB);
374   return *this;
375 }
376 
377 const GISelInstProfileBuilder &
378 GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag) const {
379   if (Flag)
380     ID.AddInteger(Flag);
381   return *this;
382 }
383 
384 const GISelInstProfileBuilder &
385 GISelInstProfileBuilder::addNodeIDReg(Register Reg) const {
386   LLT Ty = MRI.getType(Reg);
387   if (Ty.isValid())
388     addNodeIDRegType(Ty);
389 
390   if (const RegClassOrRegBank &RCOrRB = MRI.getRegClassOrRegBank(Reg)) {
391     if (const auto *RB = RCOrRB.dyn_cast<const RegisterBank *>())
392       addNodeIDRegType(RB);
393     else if (const auto *RC = RCOrRB.dyn_cast<const TargetRegisterClass *>())
394       addNodeIDRegType(RC);
395   }
396   return *this;
397 }
398 
399 const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand(
400     const MachineOperand &MO) const {
401   if (MO.isReg()) {
402     Register Reg = MO.getReg();
403     if (!MO.isDef())
404       addNodeIDRegNum(Reg);
405 
406     // Profile the register properties.
407     addNodeIDReg(Reg);
408     assert(!MO.isImplicit() && "Unhandled case");
409   } else if (MO.isImm())
410     ID.AddInteger(MO.getImm());
411   else if (MO.isCImm())
412     ID.AddPointer(MO.getCImm());
413   else if (MO.isFPImm())
414     ID.AddPointer(MO.getFPImm());
415   else if (MO.isPredicate())
416     ID.AddInteger(MO.getPredicate());
417   else
418     llvm_unreachable("Unhandled operand type");
419   // Handle other types
420   return *this;
421 }
422 
423 GISelCSEInfo &
424 GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfigBase> CSEOpt,
425                              bool Recompute) {
426   if (!AlreadyComputed || Recompute) {
427     Info.releaseMemory();
428     Info.setCSEConfig(std::move(CSEOpt));
429     Info.analyze(*MF);
430     AlreadyComputed = true;
431   }
432   return Info;
433 }
434 void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
435   AU.setPreservesAll();
436   MachineFunctionPass::getAnalysisUsage(AU);
437 }
438 
439 bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) {
440   releaseMemory();
441   Wrapper.setMF(MF);
442   return false;
443 }
444