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