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 15 #define DEBUG_TYPE "cseinfo" 16 17 using namespace llvm; 18 char llvm::GISelCSEAnalysisWrapperPass::ID = 0; 19 GISelCSEAnalysisWrapperPass::GISelCSEAnalysisWrapperPass() 20 : MachineFunctionPass(ID) { 21 initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry()); 22 } 23 INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, 24 "Analysis containing CSE Info", false, true) 25 INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass, DEBUG_TYPE, 26 "Analysis containing CSE Info", false, true) 27 28 /// -------- UniqueMachineInstr -------------// 29 30 void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) { 31 GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI); 32 } 33 /// ----------------------------------------- 34 35 /// --------- CSEConfigFull ---------- /// 36 bool CSEConfigFull::shouldCSEOpc(unsigned Opc) { 37 switch (Opc) { 38 default: 39 break; 40 case TargetOpcode::G_ADD: 41 case TargetOpcode::G_AND: 42 case TargetOpcode::G_ASHR: 43 case TargetOpcode::G_LSHR: 44 case TargetOpcode::G_MUL: 45 case TargetOpcode::G_OR: 46 case TargetOpcode::G_SHL: 47 case TargetOpcode::G_SUB: 48 case TargetOpcode::G_XOR: 49 case TargetOpcode::G_UDIV: 50 case TargetOpcode::G_SDIV: 51 case TargetOpcode::G_UREM: 52 case TargetOpcode::G_SREM: 53 case TargetOpcode::G_CONSTANT: 54 case TargetOpcode::G_FCONSTANT: 55 case TargetOpcode::G_IMPLICIT_DEF: 56 case TargetOpcode::G_ZEXT: 57 case TargetOpcode::G_SEXT: 58 case TargetOpcode::G_ANYEXT: 59 case TargetOpcode::G_UNMERGE_VALUES: 60 case TargetOpcode::G_TRUNC: 61 case TargetOpcode::G_PTR_ADD: 62 return true; 63 } 64 return false; 65 } 66 67 bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) { 68 return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_IMPLICIT_DEF; 69 } 70 71 std::unique_ptr<CSEConfigBase> 72 llvm::getStandardCSEConfigForOpt(CodeGenOpt::Level Level) { 73 std::unique_ptr<CSEConfigBase> Config; 74 if (Level == CodeGenOpt::None) 75 Config = std::make_unique<CSEConfigConstantOnly>(); 76 else 77 Config = std::make_unique<CSEConfigFull>(); 78 return Config; 79 } 80 81 /// ----------------------------------------- 82 83 /// -------- GISelCSEInfo -------------// 84 void GISelCSEInfo::setMF(MachineFunction &MF) { 85 this->MF = &MF; 86 this->MRI = &MF.getRegInfo(); 87 } 88 89 GISelCSEInfo::~GISelCSEInfo() {} 90 91 bool GISelCSEInfo::isUniqueMachineInstValid( 92 const UniqueMachineInstr &UMI) const { 93 // Should we check here and assert that the instruction has been fully 94 // constructed? 95 // FIXME: Any other checks required to be done here? Remove this method if 96 // none. 97 return true; 98 } 99 100 void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) { 101 bool Removed = CSEMap.RemoveNode(UMI); 102 (void)Removed; 103 assert(Removed && "Invalidation called on invalid UMI"); 104 // FIXME: Should UMI be deallocated/destroyed? 105 } 106 107 UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID, 108 MachineBasicBlock *MBB, 109 void *&InsertPos) { 110 auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos); 111 if (Node) { 112 if (!isUniqueMachineInstValid(*Node)) { 113 invalidateUniqueMachineInstr(Node); 114 return nullptr; 115 } 116 117 if (Node->MI->getParent() != MBB) 118 return nullptr; 119 } 120 return Node; 121 } 122 123 void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) { 124 handleRecordedInsts(); 125 assert(UMI); 126 UniqueMachineInstr *MaybeNewNode = UMI; 127 if (InsertPos) 128 CSEMap.InsertNode(UMI, InsertPos); 129 else 130 MaybeNewNode = CSEMap.GetOrInsertNode(UMI); 131 if (MaybeNewNode != UMI) { 132 // A similar node exists in the folding set. Let's ignore this one. 133 return; 134 } 135 assert(InstrMapping.count(UMI->MI) == 0 && 136 "This instruction should not be in the map"); 137 InstrMapping[UMI->MI] = MaybeNewNode; 138 } 139 140 UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) { 141 assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node"); 142 auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI); 143 return Node; 144 } 145 146 void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) { 147 assert(MI); 148 // If it exists in temporary insts, remove it. 149 TemporaryInsts.remove(MI); 150 auto *Node = getUniqueInstrForMI(MI); 151 insertNode(Node, InsertPos); 152 } 153 154 MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID, 155 MachineBasicBlock *MBB, 156 void *&InsertPos) { 157 handleRecordedInsts(); 158 if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) { 159 LLVM_DEBUG(dbgs() << "CSEInfo::Found Instr " << *Inst->MI;); 160 return const_cast<MachineInstr *>(Inst->MI); 161 } 162 return nullptr; 163 } 164 165 void GISelCSEInfo::countOpcodeHit(unsigned Opc) { 166 #ifndef NDEBUG 167 if (OpcodeHitTable.count(Opc)) 168 OpcodeHitTable[Opc] += 1; 169 else 170 OpcodeHitTable[Opc] = 1; 171 #endif 172 // Else do nothing. 173 } 174 175 void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) { 176 if (shouldCSE(MI->getOpcode())) { 177 TemporaryInsts.insert(MI); 178 LLVM_DEBUG(dbgs() << "CSEInfo::Recording new MI " << *MI); 179 } 180 } 181 182 void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) { 183 assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE"); 184 auto *UMI = InstrMapping.lookup(MI); 185 LLVM_DEBUG(dbgs() << "CSEInfo::Handling recorded MI " << *MI); 186 if (UMI) { 187 // Invalidate this MI. 188 invalidateUniqueMachineInstr(UMI); 189 InstrMapping.erase(MI); 190 } 191 /// Now insert the new instruction. 192 if (UMI) { 193 /// We'll reuse the same UniqueMachineInstr to avoid the new 194 /// allocation. 195 *UMI = UniqueMachineInstr(MI); 196 insertNode(UMI, nullptr); 197 } else { 198 /// This is a new instruction. Allocate a new UniqueMachineInstr and 199 /// Insert. 200 insertInstr(MI); 201 } 202 } 203 204 void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) { 205 if (auto *UMI = InstrMapping.lookup(MI)) { 206 invalidateUniqueMachineInstr(UMI); 207 InstrMapping.erase(MI); 208 } 209 TemporaryInsts.remove(MI); 210 } 211 212 void GISelCSEInfo::handleRecordedInsts() { 213 while (!TemporaryInsts.empty()) { 214 auto *MI = TemporaryInsts.pop_back_val(); 215 handleRecordedInst(MI); 216 } 217 } 218 219 bool GISelCSEInfo::shouldCSE(unsigned Opc) const { 220 // Only GISel opcodes are CSEable 221 if (!isPreISelGenericOpcode(Opc)) 222 return false; 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 void GISelCSEInfo::print() { 265 LLVM_DEBUG(for (auto &It 266 : OpcodeHitTable) { 267 dbgs() << "CSEInfo::CSE Hit for Opc " << It.first << " : " << It.second 268 << "\n"; 269 };); 270 } 271 /// ----------------------------------------- 272 // ---- Profiling methods for FoldingSetNode --- // 273 const GISelInstProfileBuilder & 274 GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const { 275 addNodeIDMBB(MI->getParent()); 276 addNodeIDOpcode(MI->getOpcode()); 277 for (auto &Op : MI->operands()) 278 addNodeIDMachineOperand(Op); 279 addNodeIDFlag(MI->getFlags()); 280 return *this; 281 } 282 283 const GISelInstProfileBuilder & 284 GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const { 285 ID.AddInteger(Opc); 286 return *this; 287 } 288 289 const GISelInstProfileBuilder & 290 GISelInstProfileBuilder::addNodeIDRegType(const LLT &Ty) const { 291 uint64_t Val = Ty.getUniqueRAWLLTData(); 292 ID.AddInteger(Val); 293 return *this; 294 } 295 296 const GISelInstProfileBuilder & 297 GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const { 298 ID.AddPointer(RC); 299 return *this; 300 } 301 302 const GISelInstProfileBuilder & 303 GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const { 304 ID.AddPointer(RB); 305 return *this; 306 } 307 308 const GISelInstProfileBuilder & 309 GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const { 310 ID.AddInteger(Imm); 311 return *this; 312 } 313 314 const GISelInstProfileBuilder & 315 GISelInstProfileBuilder::addNodeIDRegNum(unsigned Reg) const { 316 ID.AddInteger(Reg); 317 return *this; 318 } 319 320 const GISelInstProfileBuilder & 321 GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg) const { 322 addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false)); 323 return *this; 324 } 325 326 const GISelInstProfileBuilder & 327 GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const { 328 ID.AddPointer(MBB); 329 return *this; 330 } 331 332 const GISelInstProfileBuilder & 333 GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag) const { 334 if (Flag) 335 ID.AddInteger(Flag); 336 return *this; 337 } 338 339 const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand( 340 const MachineOperand &MO) const { 341 if (MO.isReg()) { 342 Register Reg = MO.getReg(); 343 if (!MO.isDef()) 344 addNodeIDRegNum(Reg); 345 LLT Ty = MRI.getType(Reg); 346 if (Ty.isValid()) 347 addNodeIDRegType(Ty); 348 auto *RB = MRI.getRegBankOrNull(Reg); 349 if (RB) 350 addNodeIDRegType(RB); 351 auto *RC = MRI.getRegClassOrNull(Reg); 352 if (RC) 353 addNodeIDRegType(RC); 354 assert(!MO.isImplicit() && "Unhandled case"); 355 } else if (MO.isImm()) 356 ID.AddInteger(MO.getImm()); 357 else if (MO.isCImm()) 358 ID.AddPointer(MO.getCImm()); 359 else if (MO.isFPImm()) 360 ID.AddPointer(MO.getFPImm()); 361 else if (MO.isPredicate()) 362 ID.AddInteger(MO.getPredicate()); 363 else 364 llvm_unreachable("Unhandled operand type"); 365 // Handle other types 366 return *this; 367 } 368 369 GISelCSEInfo & 370 GISelCSEAnalysisWrapper::get(std::unique_ptr<CSEConfigBase> CSEOpt, 371 bool Recompute) { 372 if (!AlreadyComputed || Recompute) { 373 Info.setCSEConfig(std::move(CSEOpt)); 374 Info.analyze(*MF); 375 AlreadyComputed = true; 376 } 377 return Info; 378 } 379 void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 380 AU.setPreservesAll(); 381 MachineFunctionPass::getAnalysisUsage(AU); 382 } 383 384 bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) { 385 releaseMemory(); 386 Wrapper.setMF(MF); 387 return false; 388 } 389