1 //===--------------------- RegisterFile.cpp ---------------------*- C++ -*-===// 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 /// \file 9 /// 10 /// This file defines a register mapping file class. This class is responsible 11 /// for managing hardware register files and the tracking of data dependencies 12 /// between registers. 13 /// 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/MCA/HardwareUnits/RegisterFile.h" 17 #include "llvm/MCA/Instruction.h" 18 #include "llvm/Support/Debug.h" 19 20 #define DEBUG_TYPE "llvm-mca" 21 22 namespace llvm { 23 namespace mca { 24 25 RegisterFile::RegisterFile(const MCSchedModel &SM, const MCRegisterInfo &mri, 26 unsigned NumRegs) 27 : MRI(mri), 28 RegisterMappings(mri.getNumRegs(), {WriteRef(), RegisterRenamingInfo()}), 29 ZeroRegisters(mri.getNumRegs(), false) { 30 initialize(SM, NumRegs); 31 } 32 33 void RegisterFile::initialize(const MCSchedModel &SM, unsigned NumRegs) { 34 // Create a default register file that "sees" all the machine registers 35 // declared by the target. The number of physical registers in the default 36 // register file is set equal to `NumRegs`. A value of zero for `NumRegs` 37 // means: this register file has an unbounded number of physical registers. 38 RegisterFiles.emplace_back(NumRegs); 39 if (!SM.hasExtraProcessorInfo()) 40 return; 41 42 // For each user defined register file, allocate a RegisterMappingTracker 43 // object. The size of every register file, as well as the mapping between 44 // register files and register classes is specified via tablegen. 45 const MCExtraProcessorInfo &Info = SM.getExtraProcessorInfo(); 46 47 // Skip invalid register file at index 0. 48 for (unsigned I = 1, E = Info.NumRegisterFiles; I < E; ++I) { 49 const MCRegisterFileDesc &RF = Info.RegisterFiles[I]; 50 assert(RF.NumPhysRegs && "Invalid PRF with zero physical registers!"); 51 52 // The cost of a register definition is equivalent to the number of 53 // physical registers that are allocated at register renaming stage. 54 unsigned Length = RF.NumRegisterCostEntries; 55 const MCRegisterCostEntry *FirstElt = 56 &Info.RegisterCostTable[RF.RegisterCostEntryIdx]; 57 addRegisterFile(RF, ArrayRef<MCRegisterCostEntry>(FirstElt, Length)); 58 } 59 } 60 61 void RegisterFile::cycleStart() { 62 for (RegisterMappingTracker &RMT : RegisterFiles) 63 RMT.NumMoveEliminated = 0; 64 } 65 66 void RegisterFile::addRegisterFile(const MCRegisterFileDesc &RF, 67 ArrayRef<MCRegisterCostEntry> Entries) { 68 // A default register file is always allocated at index #0. That register file 69 // is mainly used to count the total number of mappings created by all 70 // register files at runtime. Users can limit the number of available physical 71 // registers in register file #0 through the command line flag 72 // `-register-file-size`. 73 unsigned RegisterFileIndex = RegisterFiles.size(); 74 RegisterFiles.emplace_back(RF.NumPhysRegs, RF.MaxMovesEliminatedPerCycle, 75 RF.AllowZeroMoveEliminationOnly); 76 77 // Special case where there is no register class identifier in the set. 78 // An empty set of register classes means: this register file contains all 79 // the physical registers specified by the target. 80 // We optimistically assume that a register can be renamed at the cost of a 81 // single physical register. The constructor of RegisterFile ensures that 82 // a RegisterMapping exists for each logical register defined by the Target. 83 if (Entries.empty()) 84 return; 85 86 // Now update the cost of individual registers. 87 for (const MCRegisterCostEntry &RCE : Entries) { 88 const MCRegisterClass &RC = MRI.getRegClass(RCE.RegisterClassID); 89 for (const MCPhysReg Reg : RC) { 90 RegisterRenamingInfo &Entry = RegisterMappings[Reg].second; 91 IndexPlusCostPairTy &IPC = Entry.IndexPlusCost; 92 if (IPC.first && IPC.first != RegisterFileIndex) { 93 // The only register file that is allowed to overlap is the default 94 // register file at index #0. The analysis is inaccurate if register 95 // files overlap. 96 errs() << "warning: register " << MRI.getName(Reg) 97 << " defined in multiple register files."; 98 } 99 IPC = std::make_pair(RegisterFileIndex, RCE.Cost); 100 Entry.RenameAs = Reg; 101 Entry.AllowMoveElimination = RCE.AllowMoveElimination; 102 103 // Assume the same cost for each sub-register. 104 for (MCSubRegIterator I(Reg, &MRI); I.isValid(); ++I) { 105 RegisterRenamingInfo &OtherEntry = RegisterMappings[*I].second; 106 if (!OtherEntry.IndexPlusCost.first && 107 (!OtherEntry.RenameAs || 108 MRI.isSuperRegister(*I, OtherEntry.RenameAs))) { 109 OtherEntry.IndexPlusCost = IPC; 110 OtherEntry.RenameAs = Reg; 111 } 112 } 113 } 114 } 115 } 116 117 void RegisterFile::allocatePhysRegs(const RegisterRenamingInfo &Entry, 118 MutableArrayRef<unsigned> UsedPhysRegs) { 119 unsigned RegisterFileIndex = Entry.IndexPlusCost.first; 120 unsigned Cost = Entry.IndexPlusCost.second; 121 if (RegisterFileIndex) { 122 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; 123 RMT.NumUsedPhysRegs += Cost; 124 UsedPhysRegs[RegisterFileIndex] += Cost; 125 } 126 127 // Now update the default register mapping tracker. 128 RegisterFiles[0].NumUsedPhysRegs += Cost; 129 UsedPhysRegs[0] += Cost; 130 } 131 132 void RegisterFile::freePhysRegs(const RegisterRenamingInfo &Entry, 133 MutableArrayRef<unsigned> FreedPhysRegs) { 134 unsigned RegisterFileIndex = Entry.IndexPlusCost.first; 135 unsigned Cost = Entry.IndexPlusCost.second; 136 if (RegisterFileIndex) { 137 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; 138 RMT.NumUsedPhysRegs -= Cost; 139 FreedPhysRegs[RegisterFileIndex] += Cost; 140 } 141 142 // Now update the default register mapping tracker. 143 RegisterFiles[0].NumUsedPhysRegs -= Cost; 144 FreedPhysRegs[0] += Cost; 145 } 146 147 void RegisterFile::addRegisterWrite(WriteRef Write, 148 MutableArrayRef<unsigned> UsedPhysRegs) { 149 WriteState &WS = *Write.getWriteState(); 150 MCPhysReg RegID = WS.getRegisterID(); 151 assert(RegID && "Adding an invalid register definition?"); 152 153 LLVM_DEBUG({ 154 dbgs() << "RegisterFile: addRegisterWrite [ " << Write.getSourceIndex() 155 << ", " << MRI.getName(RegID) << "]\n"; 156 }); 157 158 // If RenameAs is equal to RegID, then RegID is subject to register renaming 159 // and false dependencies on RegID are all eliminated. 160 161 // If RenameAs references the invalid register, then we optimistically assume 162 // that it can be renamed. In the absence of tablegen descriptors for register 163 // files, RenameAs is always set to the invalid register ID. In all other 164 // cases, RenameAs must be either equal to RegID, or it must reference a 165 // super-register of RegID. 166 167 // If RenameAs is a super-register of RegID, then a write to RegID has always 168 // a false dependency on RenameAs. The only exception is for when the write 169 // implicitly clears the upper portion of the underlying register. 170 // If a write clears its super-registers, then it is renamed as `RenameAs`. 171 bool IsWriteZero = WS.isWriteZero(); 172 bool IsEliminated = WS.isEliminated(); 173 bool ShouldAllocatePhysRegs = !IsWriteZero && !IsEliminated; 174 const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second; 175 WS.setPRF(RRI.IndexPlusCost.first); 176 177 if (RRI.RenameAs && RRI.RenameAs != RegID) { 178 RegID = RRI.RenameAs; 179 WriteRef &OtherWrite = RegisterMappings[RegID].first; 180 181 if (!WS.clearsSuperRegisters()) { 182 // The processor keeps the definition of `RegID` together with register 183 // `RenameAs`. Since this partial write is not renamed, no physical 184 // register is allocated. 185 ShouldAllocatePhysRegs = false; 186 187 WriteState *OtherWS = OtherWrite.getWriteState(); 188 if (OtherWS && (OtherWrite.getSourceIndex() != Write.getSourceIndex())) { 189 // This partial write has a false dependency on RenameAs. 190 assert(!IsEliminated && "Unexpected partial update!"); 191 OtherWS->addUser(OtherWrite.getSourceIndex(), &WS); 192 } 193 } 194 } 195 196 // Update zero registers. 197 MCPhysReg ZeroRegisterID = 198 WS.clearsSuperRegisters() ? RegID : WS.getRegisterID(); 199 ZeroRegisters.setBitVal(ZeroRegisterID, IsWriteZero); 200 for (MCSubRegIterator I(ZeroRegisterID, &MRI); I.isValid(); ++I) 201 ZeroRegisters.setBitVal(*I, IsWriteZero); 202 203 // If this is move has been eliminated, then the call to tryEliminateMove 204 // should have already updated all the register mappings. 205 if (!IsEliminated) { 206 // Update the mapping for register RegID including its sub-registers. 207 RegisterMappings[RegID].first = Write; 208 RegisterMappings[RegID].second.AliasRegID = 0U; 209 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) { 210 RegisterMappings[*I].first = Write; 211 RegisterMappings[*I].second.AliasRegID = 0U; 212 } 213 214 // No physical registers are allocated for instructions that are optimized 215 // in hardware. For example, zero-latency data-dependency breaking 216 // instructions don't consume physical registers. 217 if (ShouldAllocatePhysRegs) 218 allocatePhysRegs(RegisterMappings[RegID].second, UsedPhysRegs); 219 } 220 221 if (!WS.clearsSuperRegisters()) 222 return; 223 224 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) { 225 if (!IsEliminated) { 226 RegisterMappings[*I].first = Write; 227 RegisterMappings[*I].second.AliasRegID = 0U; 228 } 229 230 ZeroRegisters.setBitVal(*I, IsWriteZero); 231 } 232 } 233 234 void RegisterFile::removeRegisterWrite( 235 const WriteState &WS, MutableArrayRef<unsigned> FreedPhysRegs) { 236 // Early exit if this write was eliminated. A write eliminated at register 237 // renaming stage generates an alias, and it is not added to the PRF. 238 if (WS.isEliminated()) 239 return; 240 241 MCPhysReg RegID = WS.getRegisterID(); 242 243 assert(RegID != 0 && "Invalidating an already invalid register?"); 244 assert(WS.getCyclesLeft() != UNKNOWN_CYCLES && 245 "Invalidating a write of unknown cycles!"); 246 assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!"); 247 248 bool ShouldFreePhysRegs = !WS.isWriteZero(); 249 MCPhysReg RenameAs = RegisterMappings[RegID].second.RenameAs; 250 if (RenameAs && RenameAs != RegID) { 251 RegID = RenameAs; 252 253 if (!WS.clearsSuperRegisters()) { 254 // Keep the definition of `RegID` together with register `RenameAs`. 255 ShouldFreePhysRegs = false; 256 } 257 } 258 259 if (ShouldFreePhysRegs) 260 freePhysRegs(RegisterMappings[RegID].second, FreedPhysRegs); 261 262 WriteRef &WR = RegisterMappings[RegID].first; 263 if (WR.getWriteState() == &WS) 264 WR.invalidate(); 265 266 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) { 267 WriteRef &OtherWR = RegisterMappings[*I].first; 268 if (OtherWR.getWriteState() == &WS) 269 OtherWR.invalidate(); 270 } 271 272 if (!WS.clearsSuperRegisters()) 273 return; 274 275 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) { 276 WriteRef &OtherWR = RegisterMappings[*I].first; 277 if (OtherWR.getWriteState() == &WS) 278 OtherWR.invalidate(); 279 } 280 } 281 282 bool RegisterFile::tryEliminateMove(WriteState &WS, ReadState &RS) { 283 const RegisterMapping &RMFrom = RegisterMappings[RS.getRegisterID()]; 284 const RegisterMapping &RMTo = RegisterMappings[WS.getRegisterID()]; 285 286 // From and To must be owned by the same PRF. 287 const RegisterRenamingInfo &RRIFrom = RMFrom.second; 288 const RegisterRenamingInfo &RRITo = RMTo.second; 289 unsigned RegisterFileIndex = RRIFrom.IndexPlusCost.first; 290 if (RegisterFileIndex != RRITo.IndexPlusCost.first) 291 return false; 292 293 // We only allow move elimination for writes that update a full physical 294 // register. On X86, move elimination is possible with 32-bit general purpose 295 // registers because writes to those registers are not partial writes. If a 296 // register move is a partial write, then we conservatively assume that move 297 // elimination fails, since it would either trigger a partial update, or the 298 // issue of a merge opcode. 299 // 300 // Note that this constraint may be lifted in future. For example, we could 301 // make this model more flexible, and let users customize the set of registers 302 // (i.e. register classes) that allow move elimination. 303 // 304 // For now, we assume that there is a strong correlation between registers 305 // that allow move elimination, and how those same registers are renamed in 306 // hardware. 307 if (RRITo.RenameAs && RRITo.RenameAs != WS.getRegisterID()) { 308 // Early exit if the PRF doesn't support move elimination for this register. 309 if (!RegisterMappings[RRITo.RenameAs].second.AllowMoveElimination) 310 return false; 311 if (!WS.clearsSuperRegisters()) 312 return false; 313 } 314 315 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex]; 316 if (RMT.MaxMoveEliminatedPerCycle && 317 RMT.NumMoveEliminated == RMT.MaxMoveEliminatedPerCycle) 318 return false; 319 320 bool IsZeroMove = ZeroRegisters[RS.getRegisterID()]; 321 if (RMT.AllowZeroMoveEliminationOnly && !IsZeroMove) 322 return false; 323 324 // Construct an alias. 325 MCPhysReg AliasedReg = 326 RRIFrom.RenameAs ? RRIFrom.RenameAs : RS.getRegisterID(); 327 MCPhysReg AliasReg = RRITo.RenameAs ? RRITo.RenameAs : WS.getRegisterID(); 328 329 const RegisterRenamingInfo &RMAlias = RegisterMappings[AliasedReg].second; 330 if (RMAlias.AliasRegID) 331 AliasedReg = RMAlias.AliasRegID; 332 333 RegisterMappings[AliasReg].second.AliasRegID = AliasedReg; 334 for (MCSubRegIterator I(AliasReg, &MRI); I.isValid(); ++I) 335 RegisterMappings[*I].second.AliasRegID = AliasedReg; 336 337 if (IsZeroMove) { 338 WS.setWriteZero(); 339 RS.setReadZero(); 340 } 341 WS.setEliminated(); 342 RMT.NumMoveEliminated++; 343 344 return true; 345 } 346 347 void RegisterFile::collectWrites(const ReadState &RS, 348 SmallVectorImpl<WriteRef> &Writes) const { 349 MCPhysReg RegID = RS.getRegisterID(); 350 assert(RegID && RegID < RegisterMappings.size()); 351 LLVM_DEBUG(dbgs() << "RegisterFile: collecting writes for register " 352 << MRI.getName(RegID) << '\n'); 353 354 // Check if this is an alias. 355 const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second; 356 if (RRI.AliasRegID) 357 RegID = RRI.AliasRegID; 358 359 const WriteRef &WR = RegisterMappings[RegID].first; 360 if (WR.isValid()) 361 Writes.push_back(WR); 362 363 // Handle potential partial register updates. 364 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) { 365 const WriteRef &WR = RegisterMappings[*I].first; 366 if (WR.isValid()) 367 Writes.push_back(WR); 368 } 369 370 // Remove duplicate entries and resize the input vector. 371 if (Writes.size() > 1) { 372 sort(Writes, [](const WriteRef &Lhs, const WriteRef &Rhs) { 373 return Lhs.getWriteState() < Rhs.getWriteState(); 374 }); 375 auto It = std::unique(Writes.begin(), Writes.end()); 376 Writes.resize(std::distance(Writes.begin(), It)); 377 } 378 379 LLVM_DEBUG({ 380 for (const WriteRef &WR : Writes) { 381 const WriteState &WS = *WR.getWriteState(); 382 dbgs() << "[PRF] Found a dependent use of Register " 383 << MRI.getName(WS.getRegisterID()) << " (defined by instruction #" 384 << WR.getSourceIndex() << ")\n"; 385 } 386 }); 387 } 388 389 void RegisterFile::addRegisterRead(ReadState &RS, 390 const MCSubtargetInfo &STI) const { 391 MCPhysReg RegID = RS.getRegisterID(); 392 const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second; 393 RS.setPRF(RRI.IndexPlusCost.first); 394 if (RS.isIndependentFromDef()) 395 return; 396 397 if (ZeroRegisters[RS.getRegisterID()]) 398 RS.setReadZero(); 399 400 SmallVector<WriteRef, 4> DependentWrites; 401 collectWrites(RS, DependentWrites); 402 RS.setDependentWrites(DependentWrites.size()); 403 404 // We know that this read depends on all the writes in DependentWrites. 405 // For each write, check if we have ReadAdvance information, and use it 406 // to figure out in how many cycles this read becomes available. 407 const ReadDescriptor &RD = RS.getDescriptor(); 408 const MCSchedModel &SM = STI.getSchedModel(); 409 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID); 410 for (WriteRef &WR : DependentWrites) { 411 WriteState &WS = *WR.getWriteState(); 412 unsigned WriteResID = WS.getWriteResourceID(); 413 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID); 414 WS.addUser(WR.getSourceIndex(), &RS, ReadAdvance); 415 } 416 } 417 418 unsigned RegisterFile::isAvailable(ArrayRef<MCPhysReg> Regs) const { 419 SmallVector<unsigned, 4> NumPhysRegs(getNumRegisterFiles()); 420 421 // Find how many new mappings must be created for each register file. 422 for (const MCPhysReg RegID : Regs) { 423 const RegisterRenamingInfo &RRI = RegisterMappings[RegID].second; 424 const IndexPlusCostPairTy &Entry = RRI.IndexPlusCost; 425 if (Entry.first) 426 NumPhysRegs[Entry.first] += Entry.second; 427 NumPhysRegs[0] += Entry.second; 428 } 429 430 unsigned Response = 0; 431 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { 432 unsigned NumRegs = NumPhysRegs[I]; 433 if (!NumRegs) 434 continue; 435 436 const RegisterMappingTracker &RMT = RegisterFiles[I]; 437 if (!RMT.NumPhysRegs) { 438 // The register file has an unbounded number of microarchitectural 439 // registers. 440 continue; 441 } 442 443 if (RMT.NumPhysRegs < NumRegs) { 444 // The current register file is too small. This may occur if the number of 445 // microarchitectural registers in register file #0 was changed by the 446 // users via flag -reg-file-size. Alternatively, the scheduling model 447 // specified a too small number of registers for this register file. 448 LLVM_DEBUG(dbgs() << "Not enough registers in the register file.\n"); 449 450 // FIXME: Normalize the instruction register count to match the 451 // NumPhysRegs value. This is a highly unusual case, and is not expected 452 // to occur. This normalization is hiding an inconsistency in either the 453 // scheduling model or in the value that the user might have specified 454 // for NumPhysRegs. 455 NumRegs = RMT.NumPhysRegs; 456 } 457 458 if (RMT.NumPhysRegs < (RMT.NumUsedPhysRegs + NumRegs)) 459 Response |= (1U << I); 460 } 461 462 return Response; 463 } 464 465 #ifndef NDEBUG 466 void RegisterFile::dump() const { 467 for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) { 468 const RegisterMapping &RM = RegisterMappings[I]; 469 const RegisterRenamingInfo &RRI = RM.second; 470 if (ZeroRegisters[I]) { 471 dbgs() << MRI.getName(I) << ", " << I 472 << ", PRF=" << RRI.IndexPlusCost.first 473 << ", Cost=" << RRI.IndexPlusCost.second 474 << ", RenameAs=" << RRI.RenameAs << ", IsZero=" << ZeroRegisters[I] 475 << ","; 476 RM.first.dump(); 477 dbgs() << '\n'; 478 } 479 } 480 481 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) { 482 dbgs() << "Register File #" << I; 483 const RegisterMappingTracker &RMT = RegisterFiles[I]; 484 dbgs() << "\n TotalMappings: " << RMT.NumPhysRegs 485 << "\n NumUsedMappings: " << RMT.NumUsedPhysRegs << '\n'; 486 } 487 } 488 #endif 489 490 } // namespace mca 491 } // namespace llvm 492