1 //===--------------------- InstrBuilder.cpp ---------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// \file 10 /// 11 /// This file implements the InstrBuilder interface. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/MCA/InstrBuilder.h" 16 #include "llvm/ADT/APInt.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/MC/MCInst.h" 19 #include "llvm/Support/Debug.h" 20 #include "llvm/Support/WithColor.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 #define DEBUG_TYPE "llvm-mca" 24 25 namespace llvm { 26 namespace mca { 27 28 InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti, 29 const llvm::MCInstrInfo &mcii, 30 const llvm::MCRegisterInfo &mri, 31 const llvm::MCInstrAnalysis *mcia) 32 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true), 33 FirstReturnInst(true) { 34 computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); 35 } 36 37 static void initializeUsedResources(InstrDesc &ID, 38 const MCSchedClassDesc &SCDesc, 39 const MCSubtargetInfo &STI, 40 ArrayRef<uint64_t> ProcResourceMasks) { 41 const MCSchedModel &SM = STI.getSchedModel(); 42 43 // Populate resources consumed. 44 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>; 45 std::vector<ResourcePlusCycles> Worklist; 46 47 // Track cycles contributed by resources that are in a "Super" relationship. 48 // This is required if we want to correctly match the behavior of method 49 // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set 50 // of "consumed" processor resources and resource cycles, the logic in 51 // ExpandProcResource() doesn't update the number of resource cycles 52 // contributed by a "Super" resource to a group. 53 // We need to take this into account when we find that a processor resource is 54 // part of a group, and it is also used as the "Super" of other resources. 55 // This map stores the number of cycles contributed by sub-resources that are 56 // part of a "Super" resource. The key value is the "Super" resource mask ID. 57 DenseMap<uint64_t, unsigned> SuperResources; 58 59 unsigned NumProcResources = SM.getNumProcResourceKinds(); 60 APInt Buffers(NumProcResources, 0); 61 62 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) { 63 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I; 64 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx); 65 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx]; 66 if (PR.BufferSize != -1) 67 Buffers.setBit(PRE->ProcResourceIdx); 68 CycleSegment RCy(0, PRE->Cycles, false); 69 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy))); 70 if (PR.SuperIdx) { 71 uint64_t Super = ProcResourceMasks[PR.SuperIdx]; 72 SuperResources[Super] += PRE->Cycles; 73 } 74 } 75 76 // Sort elements by mask popcount, so that we prioritize resource units over 77 // resource groups, and smaller groups over larger groups. 78 sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) { 79 unsigned popcntA = countPopulation(A.first); 80 unsigned popcntB = countPopulation(B.first); 81 if (popcntA < popcntB) 82 return true; 83 if (popcntA > popcntB) 84 return false; 85 return A.first < B.first; 86 }); 87 88 uint64_t UsedResourceUnits = 0; 89 90 // Remove cycles contributed by smaller resources. 91 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) { 92 ResourcePlusCycles &A = Worklist[I]; 93 if (!A.second.size()) { 94 A.second.NumUnits = 0; 95 A.second.setReserved(); 96 ID.Resources.emplace_back(A); 97 continue; 98 } 99 100 ID.Resources.emplace_back(A); 101 uint64_t NormalizedMask = A.first; 102 if (countPopulation(A.first) == 1) { 103 UsedResourceUnits |= A.first; 104 } else { 105 // Remove the leading 1 from the resource group mask. 106 NormalizedMask ^= PowerOf2Floor(NormalizedMask); 107 } 108 109 for (unsigned J = I + 1; J < E; ++J) { 110 ResourcePlusCycles &B = Worklist[J]; 111 if ((NormalizedMask & B.first) == NormalizedMask) { 112 B.second.CS.subtract(A.second.size() - SuperResources[A.first]); 113 if (countPopulation(B.first) > 1) 114 B.second.NumUnits++; 115 } 116 } 117 } 118 119 // A SchedWrite may specify a number of cycles in which a resource group 120 // is reserved. For example (on target x86; cpu Haswell): 121 // 122 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> { 123 // let ResourceCycles = [2, 2, 3]; 124 // } 125 // 126 // This means: 127 // Resource units HWPort0 and HWPort1 are both used for 2cy. 128 // Resource group HWPort01 is the union of HWPort0 and HWPort1. 129 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01 130 // will not be usable for 2 entire cycles from instruction issue. 131 // 132 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency 133 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an 134 // extra delay on top of the 2 cycles latency. 135 // During those extra cycles, HWPort01 is not usable by other instructions. 136 for (ResourcePlusCycles &RPC : ID.Resources) { 137 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) { 138 // Remove the leading 1 from the resource group mask. 139 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first); 140 if ((Mask & UsedResourceUnits) == Mask) 141 RPC.second.setReserved(); 142 } 143 } 144 145 // Identify extra buffers that are consumed through super resources. 146 for (const std::pair<uint64_t, unsigned> &SR : SuperResources) { 147 for (unsigned I = 1, E = NumProcResources; I < E; ++I) { 148 const MCProcResourceDesc &PR = *SM.getProcResource(I); 149 if (PR.BufferSize == -1) 150 continue; 151 152 uint64_t Mask = ProcResourceMasks[I]; 153 if (Mask != SR.first && ((Mask & SR.first) == SR.first)) 154 Buffers.setBit(I); 155 } 156 } 157 158 // Now set the buffers. 159 if (unsigned NumBuffers = Buffers.countPopulation()) { 160 ID.Buffers.resize(NumBuffers); 161 for (unsigned I = 0, E = NumProcResources; I < E && NumBuffers; ++I) { 162 if (Buffers[I]) { 163 --NumBuffers; 164 ID.Buffers[NumBuffers] = ProcResourceMasks[I]; 165 } 166 } 167 } 168 169 LLVM_DEBUG({ 170 for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources) 171 dbgs() << "\t\tMask=" << R.first << ", cy=" << R.second.size() << '\n'; 172 for (const uint64_t R : ID.Buffers) 173 dbgs() << "\t\tBuffer Mask=" << R << '\n'; 174 }); 175 } 176 177 static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc, 178 const MCSchedClassDesc &SCDesc, 179 const MCSubtargetInfo &STI) { 180 if (MCDesc.isCall()) { 181 // We cannot estimate how long this call will take. 182 // Artificially set an arbitrarily high latency (100cy). 183 ID.MaxLatency = 100U; 184 return; 185 } 186 187 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); 188 // If latency is unknown, then conservatively assume a MaxLatency of 100cy. 189 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency); 190 } 191 192 static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) { 193 // Count register definitions, and skip non register operands in the process. 194 unsigned I, E; 195 unsigned NumExplicitDefs = MCDesc.getNumDefs(); 196 for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) { 197 const MCOperand &Op = MCI.getOperand(I); 198 if (Op.isReg()) 199 --NumExplicitDefs; 200 } 201 202 if (NumExplicitDefs) { 203 return make_error<InstructionError<MCInst>>( 204 "Expected more register operand definitions.", MCI); 205 } 206 207 if (MCDesc.hasOptionalDef()) { 208 // Always assume that the optional definition is the last operand. 209 const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1); 210 if (I == MCI.getNumOperands() || !Op.isReg()) { 211 std::string Message = 212 "expected a register operand for an optional definition. Instruction " 213 "has not been correctly analyzed."; 214 return make_error<InstructionError<MCInst>>(Message, MCI); 215 } 216 } 217 218 return ErrorSuccess(); 219 } 220 221 void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, 222 unsigned SchedClassID) { 223 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 224 const MCSchedModel &SM = STI.getSchedModel(); 225 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 226 227 // Assumptions made by this algorithm: 228 // 1. The number of explicit and implicit register definitions in a MCInst 229 // matches the number of explicit and implicit definitions according to 230 // the opcode descriptor (MCInstrDesc). 231 // 2. Uses start at index #(MCDesc.getNumDefs()). 232 // 3. There can only be a single optional register definition, an it is 233 // always the last operand of the sequence (excluding extra operands 234 // contributed by variadic opcodes). 235 // 236 // These assumptions work quite well for most out-of-order in-tree targets 237 // like x86. This is mainly because the vast majority of instructions is 238 // expanded to MCInst using a straightforward lowering logic that preserves 239 // the ordering of the operands. 240 // 241 // About assumption 1. 242 // The algorithm allows non-register operands between register operand 243 // definitions. This helps to handle some special ARM instructions with 244 // implicit operand increment (-mtriple=armv7): 245 // 246 // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed 247 // @ <MCOperand Reg:59> 248 // @ <MCOperand Imm:0> (!!) 249 // @ <MCOperand Reg:67> 250 // @ <MCOperand Imm:0> 251 // @ <MCOperand Imm:14> 252 // @ <MCOperand Reg:0>> 253 // 254 // MCDesc reports: 255 // 6 explicit operands. 256 // 1 optional definition 257 // 2 explicit definitions (!!) 258 // 259 // The presence of an 'Imm' operand between the two register definitions 260 // breaks the assumption that "register definitions are always at the 261 // beginning of the operand sequence". 262 // 263 // To workaround this issue, this algorithm ignores (i.e. skips) any 264 // non-register operands between register definitions. The optional 265 // definition is still at index #(NumOperands-1). 266 // 267 // According to assumption 2. register reads start at #(NumExplicitDefs-1). 268 // That means, register R1 from the example is both read and written. 269 unsigned NumExplicitDefs = MCDesc.getNumDefs(); 270 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs(); 271 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries; 272 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs; 273 if (MCDesc.hasOptionalDef()) 274 TotalDefs++; 275 276 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 277 ID.Writes.resize(TotalDefs + NumVariadicOps); 278 // Iterate over the operands list, and skip non-register operands. 279 // The first NumExplictDefs register operands are expected to be register 280 // definitions. 281 unsigned CurrentDef = 0; 282 unsigned i = 0; 283 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) { 284 const MCOperand &Op = MCI.getOperand(i); 285 if (!Op.isReg()) 286 continue; 287 288 WriteDescriptor &Write = ID.Writes[CurrentDef]; 289 Write.OpIndex = i; 290 if (CurrentDef < NumWriteLatencyEntries) { 291 const MCWriteLatencyEntry &WLE = 292 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef); 293 // Conservatively default to MaxLatency. 294 Write.Latency = 295 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 296 Write.SClassOrWriteResourceID = WLE.WriteResourceID; 297 } else { 298 // Assign a default latency for this write. 299 Write.Latency = ID.MaxLatency; 300 Write.SClassOrWriteResourceID = 0; 301 } 302 Write.IsOptionalDef = false; 303 LLVM_DEBUG({ 304 dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex 305 << ", Latency=" << Write.Latency 306 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 307 }); 308 CurrentDef++; 309 } 310 311 assert(CurrentDef == NumExplicitDefs && 312 "Expected more register operand definitions."); 313 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { 314 unsigned Index = NumExplicitDefs + CurrentDef; 315 WriteDescriptor &Write = ID.Writes[Index]; 316 Write.OpIndex = ~CurrentDef; 317 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef]; 318 if (Index < NumWriteLatencyEntries) { 319 const MCWriteLatencyEntry &WLE = 320 *STI.getWriteLatencyEntry(&SCDesc, Index); 321 // Conservatively default to MaxLatency. 322 Write.Latency = 323 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 324 Write.SClassOrWriteResourceID = WLE.WriteResourceID; 325 } else { 326 // Assign a default latency for this write. 327 Write.Latency = ID.MaxLatency; 328 Write.SClassOrWriteResourceID = 0; 329 } 330 331 Write.IsOptionalDef = false; 332 assert(Write.RegisterID != 0 && "Expected a valid phys register!"); 333 LLVM_DEBUG({ 334 dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex 335 << ", PhysReg=" << MRI.getName(Write.RegisterID) 336 << ", Latency=" << Write.Latency 337 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 338 }); 339 } 340 341 if (MCDesc.hasOptionalDef()) { 342 WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs]; 343 Write.OpIndex = MCDesc.getNumOperands() - 1; 344 // Assign a default latency for this write. 345 Write.Latency = ID.MaxLatency; 346 Write.SClassOrWriteResourceID = 0; 347 Write.IsOptionalDef = true; 348 LLVM_DEBUG({ 349 dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex 350 << ", Latency=" << Write.Latency 351 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 352 }); 353 } 354 355 if (!NumVariadicOps) 356 return; 357 358 // FIXME: if an instruction opcode is flagged 'mayStore', and it has no 359 // "unmodeledSideEffects', then this logic optimistically assumes that any 360 // extra register operands in the variadic sequence is not a register 361 // definition. 362 // 363 // Otherwise, we conservatively assume that any register operand from the 364 // variadic sequence is both a register read and a register write. 365 bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() && 366 !MCDesc.hasUnmodeledSideEffects(); 367 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef(); 368 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 369 I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) { 370 const MCOperand &Op = MCI.getOperand(OpIndex); 371 if (!Op.isReg()) 372 continue; 373 374 WriteDescriptor &Write = ID.Writes[CurrentDef]; 375 Write.OpIndex = OpIndex; 376 // Assign a default latency for this write. 377 Write.Latency = ID.MaxLatency; 378 Write.SClassOrWriteResourceID = 0; 379 Write.IsOptionalDef = false; 380 ++CurrentDef; 381 LLVM_DEBUG({ 382 dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex 383 << ", Latency=" << Write.Latency 384 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 385 }); 386 } 387 388 ID.Writes.resize(CurrentDef); 389 } 390 391 void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, 392 unsigned SchedClassID) { 393 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 394 unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs(); 395 unsigned NumImplicitUses = MCDesc.getNumImplicitUses(); 396 // Remove the optional definition. 397 if (MCDesc.hasOptionalDef()) 398 --NumExplicitUses; 399 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 400 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps; 401 ID.Reads.resize(TotalUses); 402 unsigned CurrentUse = 0; 403 for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses; 404 ++I, ++OpIndex) { 405 const MCOperand &Op = MCI.getOperand(OpIndex); 406 if (!Op.isReg()) 407 continue; 408 409 ReadDescriptor &Read = ID.Reads[CurrentUse]; 410 Read.OpIndex = OpIndex; 411 Read.UseIndex = I; 412 Read.SchedClassID = SchedClassID; 413 ++CurrentUse; 414 LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex 415 << ", UseIndex=" << Read.UseIndex << '\n'); 416 } 417 418 // For the purpose of ReadAdvance, implicit uses come directly after explicit 419 // uses. The "UseIndex" must be updated according to that implicit layout. 420 for (unsigned I = 0; I < NumImplicitUses; ++I) { 421 ReadDescriptor &Read = ID.Reads[CurrentUse + I]; 422 Read.OpIndex = ~I; 423 Read.UseIndex = NumExplicitUses + I; 424 Read.RegisterID = MCDesc.getImplicitUses()[I]; 425 Read.SchedClassID = SchedClassID; 426 LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex 427 << ", UseIndex=" << Read.UseIndex << ", RegisterID=" 428 << MRI.getName(Read.RegisterID) << '\n'); 429 } 430 431 CurrentUse += NumImplicitUses; 432 433 // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no 434 // "unmodeledSideEffects", then this logic optimistically assumes that any 435 // extra register operands in the variadic sequence are not register 436 // definition. 437 438 bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() && 439 !MCDesc.hasUnmodeledSideEffects(); 440 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 441 I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) { 442 const MCOperand &Op = MCI.getOperand(OpIndex); 443 if (!Op.isReg()) 444 continue; 445 446 ReadDescriptor &Read = ID.Reads[CurrentUse]; 447 Read.OpIndex = OpIndex; 448 Read.UseIndex = NumExplicitUses + NumImplicitUses + I; 449 Read.SchedClassID = SchedClassID; 450 ++CurrentUse; 451 LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex 452 << ", UseIndex=" << Read.UseIndex << '\n'); 453 } 454 455 ID.Reads.resize(CurrentUse); 456 } 457 458 Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID, 459 const MCInst &MCI) const { 460 if (ID.NumMicroOps != 0) 461 return ErrorSuccess(); 462 463 bool UsesMemory = ID.MayLoad || ID.MayStore; 464 bool UsesBuffers = !ID.Buffers.empty(); 465 bool UsesResources = !ID.Resources.empty(); 466 if (!UsesMemory && !UsesBuffers && !UsesResources) 467 return ErrorSuccess(); 468 469 StringRef Message; 470 if (UsesMemory) { 471 Message = "found an inconsistent instruction that decodes " 472 "into zero opcodes and that consumes load/store " 473 "unit resources."; 474 } else { 475 Message = "found an inconsistent instruction that decodes " 476 "to zero opcodes and that consumes scheduler " 477 "resources."; 478 } 479 480 return make_error<InstructionError<MCInst>>(Message, MCI); 481 } 482 483 Expected<const InstrDesc &> 484 InstrBuilder::createInstrDescImpl(const MCInst &MCI) { 485 assert(STI.getSchedModel().hasInstrSchedModel() && 486 "Itineraries are not yet supported!"); 487 488 // Obtain the instruction descriptor from the opcode. 489 unsigned short Opcode = MCI.getOpcode(); 490 const MCInstrDesc &MCDesc = MCII.get(Opcode); 491 const MCSchedModel &SM = STI.getSchedModel(); 492 493 // Then obtain the scheduling class information from the instruction. 494 unsigned SchedClassID = MCDesc.getSchedClass(); 495 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant(); 496 497 // Try to solve variant scheduling classes. 498 if (IsVariant) { 499 unsigned CPUID = SM.getProcessorID(); 500 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant()) 501 SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID); 502 503 if (!SchedClassID) { 504 return make_error<InstructionError<MCInst>>( 505 "unable to resolve scheduling class for write variant.", MCI); 506 } 507 } 508 509 // Check if this instruction is supported. Otherwise, report an error. 510 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 511 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 512 return make_error<InstructionError<MCInst>>( 513 "found an unsupported instruction in the input assembly sequence.", 514 MCI); 515 } 516 517 // Create a new empty descriptor. 518 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>(); 519 ID->NumMicroOps = SCDesc.NumMicroOps; 520 521 if (MCDesc.isCall() && FirstCallInst) { 522 // We don't correctly model calls. 523 WithColor::warning() << "found a call in the input assembly sequence.\n"; 524 WithColor::note() << "call instructions are not correctly modeled. " 525 << "Assume a latency of 100cy.\n"; 526 FirstCallInst = false; 527 } 528 529 if (MCDesc.isReturn() && FirstReturnInst) { 530 WithColor::warning() << "found a return instruction in the input" 531 << " assembly sequence.\n"; 532 WithColor::note() << "program counter updates are ignored.\n"; 533 FirstReturnInst = false; 534 } 535 536 ID->MayLoad = MCDesc.mayLoad(); 537 ID->MayStore = MCDesc.mayStore(); 538 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects(); 539 ID->BeginGroup = SCDesc.BeginGroup; 540 ID->EndGroup = SCDesc.EndGroup; 541 542 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks); 543 computeMaxLatency(*ID, MCDesc, SCDesc, STI); 544 545 if (Error Err = verifyOperands(MCDesc, MCI)) 546 return std::move(Err); 547 548 populateWrites(*ID, MCI, SchedClassID); 549 populateReads(*ID, MCI, SchedClassID); 550 551 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n'); 552 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n'); 553 554 // Sanity check on the instruction descriptor. 555 if (Error Err = verifyInstrDesc(*ID, MCI)) 556 return std::move(Err); 557 558 // Now add the new descriptor. 559 SchedClassID = MCDesc.getSchedClass(); 560 bool IsVariadic = MCDesc.isVariadic(); 561 if (!IsVariadic && !IsVariant) { 562 Descriptors[MCI.getOpcode()] = std::move(ID); 563 return *Descriptors[MCI.getOpcode()]; 564 } 565 566 VariantDescriptors[&MCI] = std::move(ID); 567 return *VariantDescriptors[&MCI]; 568 } 569 570 Expected<const InstrDesc &> 571 InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) { 572 if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end()) 573 return *Descriptors[MCI.getOpcode()]; 574 575 if (VariantDescriptors.find(&MCI) != VariantDescriptors.end()) 576 return *VariantDescriptors[&MCI]; 577 578 return createInstrDescImpl(MCI); 579 } 580 581 Expected<std::unique_ptr<Instruction>> 582 InstrBuilder::createInstruction(const MCInst &MCI) { 583 Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI); 584 if (!DescOrErr) 585 return DescOrErr.takeError(); 586 const InstrDesc &D = *DescOrErr; 587 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D); 588 589 // Check if this is a dependency breaking instruction. 590 APInt Mask; 591 592 bool IsZeroIdiom = false; 593 bool IsDepBreaking = false; 594 if (MCIA) { 595 unsigned ProcID = STI.getSchedModel().getProcessorID(); 596 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID); 597 IsDepBreaking = 598 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID); 599 if (MCIA->isOptimizableRegisterMove(MCI, ProcID)) 600 NewIS->setOptimizableMove(); 601 } 602 603 // Initialize Reads first. 604 for (const ReadDescriptor &RD : D.Reads) { 605 int RegID = -1; 606 if (!RD.isImplicitRead()) { 607 // explicit read. 608 const MCOperand &Op = MCI.getOperand(RD.OpIndex); 609 // Skip non-register operands. 610 if (!Op.isReg()) 611 continue; 612 RegID = Op.getReg(); 613 } else { 614 // Implicit read. 615 RegID = RD.RegisterID; 616 } 617 618 // Skip invalid register operands. 619 if (!RegID) 620 continue; 621 622 // Okay, this is a register operand. Create a ReadState for it. 623 assert(RegID > 0 && "Invalid register ID found!"); 624 NewIS->getUses().emplace_back(RD, RegID); 625 ReadState &RS = NewIS->getUses().back(); 626 627 if (IsDepBreaking) { 628 // A mask of all zeroes means: explicit input operands are not 629 // independent. 630 if (Mask.isNullValue()) { 631 if (!RD.isImplicitRead()) 632 RS.setIndependentFromDef(); 633 } else { 634 // Check if this register operand is independent according to `Mask`. 635 // Note that Mask may not have enough bits to describe all explicit and 636 // implicit input operands. If this register operand doesn't have a 637 // corresponding bit in Mask, then conservatively assume that it is 638 // dependent. 639 if (Mask.getBitWidth() > RD.UseIndex) { 640 // Okay. This map describe register use `RD.UseIndex`. 641 if (Mask[RD.UseIndex]) 642 RS.setIndependentFromDef(); 643 } 644 } 645 } 646 } 647 648 // Early exit if there are no writes. 649 if (D.Writes.empty()) 650 return std::move(NewIS); 651 652 // Track register writes that implicitly clear the upper portion of the 653 // underlying super-registers using an APInt. 654 APInt WriteMask(D.Writes.size(), 0); 655 656 // Now query the MCInstrAnalysis object to obtain information about which 657 // register writes implicitly clear the upper portion of a super-register. 658 if (MCIA) 659 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask); 660 661 // Initialize writes. 662 unsigned WriteIndex = 0; 663 for (const WriteDescriptor &WD : D.Writes) { 664 unsigned RegID = WD.isImplicitWrite() ? WD.RegisterID 665 : MCI.getOperand(WD.OpIndex).getReg(); 666 // Check if this is a optional definition that references NoReg. 667 if (WD.IsOptionalDef && !RegID) { 668 ++WriteIndex; 669 continue; 670 } 671 672 assert(RegID && "Expected a valid register ID!"); 673 NewIS->getDefs().emplace_back(WD, RegID, 674 /* ClearsSuperRegs */ WriteMask[WriteIndex], 675 /* WritesZero */ IsZeroIdiom); 676 ++WriteIndex; 677 } 678 679 return std::move(NewIS); 680 } 681 } // namespace mca 682 } // namespace llvm 683