diff options
| author | 2019-06-23 21:36:31 +0000 | |
|---|---|---|
| committer | 2019-06-23 21:36:31 +0000 | |
| commit | 23f101f37937a1bd4a29726cab2f76e0fb038b35 (patch) | |
| tree | f7da7d6b32c2e07114da399150bfa88d72187012 /gnu/llvm/utils/TableGen/CodeGenSchedule.cpp | |
| parent | sort previous; ok deraadt (diff) | |
| download | wireguard-openbsd-23f101f37937a1bd4a29726cab2f76e0fb038b35.tar.xz wireguard-openbsd-23f101f37937a1bd4a29726cab2f76e0fb038b35.zip | |
Import LLVM 8.0.0 release including clang, lld and lldb.
Diffstat (limited to 'gnu/llvm/utils/TableGen/CodeGenSchedule.cpp')
| -rw-r--r-- | gnu/llvm/utils/TableGen/CodeGenSchedule.cpp | 327 |
1 files changed, 296 insertions, 31 deletions
diff --git a/gnu/llvm/utils/TableGen/CodeGenSchedule.cpp b/gnu/llvm/utils/TableGen/CodeGenSchedule.cpp index 9331fadf409..6d259cbb33e 100644 --- a/gnu/llvm/utils/TableGen/CodeGenSchedule.cpp +++ b/gnu/llvm/utils/TableGen/CodeGenSchedule.cpp @@ -222,9 +222,248 @@ CodeGenSchedModels::CodeGenSchedModels(RecordKeeper &RK, // Collect optional processor description. collectOptionalProcessorInfo(); + // Check MCInstPredicate definitions. + checkMCInstPredicates(); + + // Check STIPredicate definitions. + checkSTIPredicates(); + + // Find STIPredicate definitions for each processor model, and construct + // STIPredicateFunction objects. + collectSTIPredicates(); + checkCompleteness(); } +void CodeGenSchedModels::checkSTIPredicates() const { + DenseMap<StringRef, const Record *> Declarations; + + // There cannot be multiple declarations with the same name. + const RecVec Decls = Records.getAllDerivedDefinitions("STIPredicateDecl"); + for (const Record *R : Decls) { + StringRef Name = R->getValueAsString("Name"); + const auto It = Declarations.find(Name); + if (It == Declarations.end()) { + Declarations[Name] = R; + continue; + } + + PrintError(R->getLoc(), "STIPredicate " + Name + " multiply declared."); + PrintNote(It->second->getLoc(), "Previous declaration was here."); + PrintFatalError(R->getLoc(), "Invalid STIPredicateDecl found."); + } + + // Disallow InstructionEquivalenceClasses with an empty instruction list. + const RecVec Defs = + Records.getAllDerivedDefinitions("InstructionEquivalenceClass"); + for (const Record *R : Defs) { + RecVec Opcodes = R->getValueAsListOfDefs("Opcodes"); + if (Opcodes.empty()) { + PrintFatalError(R->getLoc(), "Invalid InstructionEquivalenceClass " + "defined with an empty opcode list."); + } + } +} + +// Used by function `processSTIPredicate` to construct a mask of machine +// instruction operands. +static APInt constructOperandMask(ArrayRef<int64_t> Indices) { + APInt OperandMask; + if (Indices.empty()) + return OperandMask; + + int64_t MaxIndex = *std::max_element(Indices.begin(), Indices.end()); + assert(MaxIndex >= 0 && "Invalid negative indices in input!"); + OperandMask = OperandMask.zext(MaxIndex + 1); + for (const int64_t Index : Indices) { + assert(Index >= 0 && "Invalid negative indices!"); + OperandMask.setBit(Index); + } + + return OperandMask; +} + +static void +processSTIPredicate(STIPredicateFunction &Fn, + const DenseMap<Record *, unsigned> &ProcModelMap) { + DenseMap<const Record *, unsigned> Opcode2Index; + using OpcodeMapPair = std::pair<const Record *, OpcodeInfo>; + std::vector<OpcodeMapPair> OpcodeMappings; + std::vector<std::pair<APInt, APInt>> OpcodeMasks; + + DenseMap<const Record *, unsigned> Predicate2Index; + unsigned NumUniquePredicates = 0; + + // Number unique predicates and opcodes used by InstructionEquivalenceClass + // definitions. Each unique opcode will be associated with an OpcodeInfo + // object. + for (const Record *Def : Fn.getDefinitions()) { + RecVec Classes = Def->getValueAsListOfDefs("Classes"); + for (const Record *EC : Classes) { + const Record *Pred = EC->getValueAsDef("Predicate"); + if (Predicate2Index.find(Pred) == Predicate2Index.end()) + Predicate2Index[Pred] = NumUniquePredicates++; + + RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); + for (const Record *Opcode : Opcodes) { + if (Opcode2Index.find(Opcode) == Opcode2Index.end()) { + Opcode2Index[Opcode] = OpcodeMappings.size(); + OpcodeMappings.emplace_back(Opcode, OpcodeInfo()); + } + } + } + } + + // Initialize vector `OpcodeMasks` with default values. We want to keep track + // of which processors "use" which opcodes. We also want to be able to + // identify predicates that are used by different processors for a same + // opcode. + // This information is used later on by this algorithm to sort OpcodeMapping + // elements based on their processor and predicate sets. + OpcodeMasks.resize(OpcodeMappings.size()); + APInt DefaultProcMask(ProcModelMap.size(), 0); + APInt DefaultPredMask(NumUniquePredicates, 0); + for (std::pair<APInt, APInt> &MaskPair : OpcodeMasks) + MaskPair = std::make_pair(DefaultProcMask, DefaultPredMask); + + // Construct a OpcodeInfo object for every unique opcode declared by an + // InstructionEquivalenceClass definition. + for (const Record *Def : Fn.getDefinitions()) { + RecVec Classes = Def->getValueAsListOfDefs("Classes"); + const Record *SchedModel = Def->getValueAsDef("SchedModel"); + unsigned ProcIndex = ProcModelMap.find(SchedModel)->second; + APInt ProcMask(ProcModelMap.size(), 0); + ProcMask.setBit(ProcIndex); + + for (const Record *EC : Classes) { + RecVec Opcodes = EC->getValueAsListOfDefs("Opcodes"); + + std::vector<int64_t> OpIndices = + EC->getValueAsListOfInts("OperandIndices"); + APInt OperandMask = constructOperandMask(OpIndices); + + const Record *Pred = EC->getValueAsDef("Predicate"); + APInt PredMask(NumUniquePredicates, 0); + PredMask.setBit(Predicate2Index[Pred]); + + for (const Record *Opcode : Opcodes) { + unsigned OpcodeIdx = Opcode2Index[Opcode]; + if (OpcodeMasks[OpcodeIdx].first[ProcIndex]) { + std::string Message = + "Opcode " + Opcode->getName().str() + + " used by multiple InstructionEquivalenceClass definitions."; + PrintFatalError(EC->getLoc(), Message); + } + OpcodeMasks[OpcodeIdx].first |= ProcMask; + OpcodeMasks[OpcodeIdx].second |= PredMask; + OpcodeInfo &OI = OpcodeMappings[OpcodeIdx].second; + + OI.addPredicateForProcModel(ProcMask, OperandMask, Pred); + } + } + } + + // Sort OpcodeMappings elements based on their CPU and predicate masks. + // As a last resort, order elements by opcode identifier. + llvm::sort(OpcodeMappings, + [&](const OpcodeMapPair &Lhs, const OpcodeMapPair &Rhs) { + unsigned LhsIdx = Opcode2Index[Lhs.first]; + unsigned RhsIdx = Opcode2Index[Rhs.first]; + std::pair<APInt, APInt> &LhsMasks = OpcodeMasks[LhsIdx]; + std::pair<APInt, APInt> &RhsMasks = OpcodeMasks[RhsIdx]; + + if (LhsMasks.first != RhsMasks.first) { + if (LhsMasks.first.countPopulation() < + RhsMasks.first.countPopulation()) + return true; + return LhsMasks.first.countLeadingZeros() > + RhsMasks.first.countLeadingZeros(); + } + + if (LhsMasks.second != RhsMasks.second) { + if (LhsMasks.second.countPopulation() < + RhsMasks.second.countPopulation()) + return true; + return LhsMasks.second.countLeadingZeros() > + RhsMasks.second.countLeadingZeros(); + } + + return LhsIdx < RhsIdx; + }); + + // Now construct opcode groups. Groups are used by the SubtargetEmitter when + // expanding the body of a STIPredicate function. In particular, each opcode + // group is expanded into a sequence of labels in a switch statement. + // It identifies opcodes for which different processors define same predicates + // and same opcode masks. + for (OpcodeMapPair &Info : OpcodeMappings) + Fn.addOpcode(Info.first, std::move(Info.second)); +} + +void CodeGenSchedModels::collectSTIPredicates() { + // Map STIPredicateDecl records to elements of vector + // CodeGenSchedModels::STIPredicates. + DenseMap<const Record *, unsigned> Decl2Index; + + RecVec RV = Records.getAllDerivedDefinitions("STIPredicate"); + for (const Record *R : RV) { + const Record *Decl = R->getValueAsDef("Declaration"); + + const auto It = Decl2Index.find(Decl); + if (It == Decl2Index.end()) { + Decl2Index[Decl] = STIPredicates.size(); + STIPredicateFunction Predicate(Decl); + Predicate.addDefinition(R); + STIPredicates.emplace_back(std::move(Predicate)); + continue; + } + + STIPredicateFunction &PreviousDef = STIPredicates[It->second]; + PreviousDef.addDefinition(R); + } + + for (STIPredicateFunction &Fn : STIPredicates) + processSTIPredicate(Fn, ProcModelMap); +} + +void OpcodeInfo::addPredicateForProcModel(const llvm::APInt &CpuMask, + const llvm::APInt &OperandMask, + const Record *Predicate) { + auto It = llvm::find_if( + Predicates, [&OperandMask, &Predicate](const PredicateInfo &P) { + return P.Predicate == Predicate && P.OperandMask == OperandMask; + }); + if (It == Predicates.end()) { + Predicates.emplace_back(CpuMask, OperandMask, Predicate); + return; + } + It->ProcModelMask |= CpuMask; +} + +void CodeGenSchedModels::checkMCInstPredicates() const { + RecVec MCPredicates = Records.getAllDerivedDefinitions("TIIPredicate"); + if (MCPredicates.empty()) + return; + + // A target cannot have multiple TIIPredicate definitions with a same name. + llvm::StringMap<const Record *> TIIPredicates(MCPredicates.size()); + for (const Record *TIIPred : MCPredicates) { + StringRef Name = TIIPred->getValueAsString("FunctionName"); + StringMap<const Record *>::const_iterator It = TIIPredicates.find(Name); + if (It == TIIPredicates.end()) { + TIIPredicates[Name] = TIIPred; + continue; + } + + PrintError(TIIPred->getLoc(), + "TIIPredicate " + Name + " is multiply defined."); + PrintNote(It->second->getLoc(), + " Previous definition of " + Name + " was here."); + PrintFatalError(TIIPred->getLoc(), + "Found conflicting definitions of TIIPredicate."); + } +} + void CodeGenSchedModels::collectRetireControlUnits() { RecVec Units = Records.getAllDerivedDefinitions("RetireControlUnit"); @@ -240,6 +479,35 @@ void CodeGenSchedModels::collectRetireControlUnits() { } } +void CodeGenSchedModels::collectLoadStoreQueueInfo() { + RecVec Queues = Records.getAllDerivedDefinitions("MemoryQueue"); + + for (Record *Queue : Queues) { + CodeGenProcModel &PM = getProcModel(Queue->getValueAsDef("SchedModel")); + if (Queue->isSubClassOf("LoadQueue")) { + if (PM.LoadQueue) { + PrintError(Queue->getLoc(), + "Expected a single LoadQueue definition"); + PrintNote(PM.LoadQueue->getLoc(), + "Previous definition of LoadQueue was here"); + } + + PM.LoadQueue = Queue; + } + + if (Queue->isSubClassOf("StoreQueue")) { + if (PM.StoreQueue) { + PrintError(Queue->getLoc(), + "Expected a single StoreQueue definition"); + PrintNote(PM.LoadQueue->getLoc(), + "Previous definition of StoreQueue was here"); + } + + PM.StoreQueue = Queue; + } + } +} + /// Collect optional processor information. void CodeGenSchedModels::collectOptionalProcessorInfo() { // Find register file definitions for each processor. @@ -248,8 +516,8 @@ void CodeGenSchedModels::collectOptionalProcessorInfo() { // Collect processor RetireControlUnit descriptors if available. collectRetireControlUnits(); - // Find pfm counter definitions for each processor. - collectPfmCounters(); + // Collect information about load/store queues. + collectLoadStoreQueueInfo(); checkCompleteness(); } @@ -257,7 +525,7 @@ void CodeGenSchedModels::collectOptionalProcessorInfo() { /// Gather all processor models. void CodeGenSchedModels::collectProcModels() { RecVec ProcRecords = Records.getAllDerivedDefinitions("Processor"); - llvm::sort(ProcRecords.begin(), ProcRecords.end(), LessRecordFieldName()); + llvm::sort(ProcRecords, LessRecordFieldName()); // Reserve space because we can. Reallocation would be ok. ProcModels.reserve(ProcRecords.size()+1); @@ -376,7 +644,7 @@ void CodeGenSchedModels::collectSchedRW() { // Find all ReadWrites referenced by SchedAlias. AliasDefs needs to be sorted // for the loop below that initializes Alias vectors. RecVec AliasDefs = Records.getAllDerivedDefinitions("SchedAlias"); - llvm::sort(AliasDefs.begin(), AliasDefs.end(), LessRecord()); + llvm::sort(AliasDefs, LessRecord()); for (Record *ADef : AliasDefs) { Record *MatchDef = ADef->getValueAsDef("MatchRW"); Record *AliasDef = ADef->getValueAsDef("AliasRW"); @@ -394,12 +662,12 @@ void CodeGenSchedModels::collectSchedRW() { } // Sort and add the SchedReadWrites directly referenced by instructions or // itinerary resources. Index reads and writes in separate domains. - llvm::sort(SWDefs.begin(), SWDefs.end(), LessRecord()); + llvm::sort(SWDefs, LessRecord()); for (Record *SWDef : SWDefs) { assert(!getSchedRWIdx(SWDef, /*IsRead=*/false) && "duplicate SchedWrite"); SchedWrites.emplace_back(SchedWrites.size(), SWDef); } - llvm::sort(SRDefs.begin(), SRDefs.end(), LessRecord()); + llvm::sort(SRDefs, LessRecord()); for (Record *SRDef : SRDefs) { assert(!getSchedRWIdx(SRDef, /*IsRead-*/true) && "duplicate SchedWrite"); SchedReads.emplace_back(SchedReads.size(), SRDef); @@ -619,7 +887,7 @@ void CodeGenSchedModels::collectSchedClasses() { } // Create classes for InstRW defs. RecVec InstRWDefs = Records.getAllDerivedDefinitions("InstRW"); - llvm::sort(InstRWDefs.begin(), InstRWDefs.end(), LessRecord()); + llvm::sort(InstRWDefs, LessRecord()); LLVM_DEBUG(dbgs() << "\n+++ SCHED CLASSES (createInstRWClass) +++\n"); for (Record *RWDef : InstRWDefs) createInstRWClass(RWDef); @@ -923,7 +1191,7 @@ void CodeGenSchedModels::collectProcItins() { // Gather the read/write types for each itinerary class. void CodeGenSchedModels::collectProcItinRW() { RecVec ItinRWDefs = Records.getAllDerivedDefinitions("ItinRW"); - llvm::sort(ItinRWDefs.begin(), ItinRWDefs.end(), LessRecord()); + llvm::sort(ItinRWDefs, LessRecord()); for (Record *RWDef : ItinRWDefs) { if (!RWDef->getValueInit("SchedModel")->isComplete()) PrintFatalError(RWDef->getLoc(), "SchedModel is undefined"); @@ -1520,33 +1788,33 @@ void CodeGenSchedModels::collectRegisterFiles() { CodeGenProcModel &PM = getProcModel(RF->getValueAsDef("SchedModel")); PM.RegisterFiles.emplace_back(CodeGenRegisterFile(RF->getName(),RF)); CodeGenRegisterFile &CGRF = PM.RegisterFiles.back(); + CGRF.MaxMovesEliminatedPerCycle = + RF->getValueAsInt("MaxMovesEliminatedPerCycle"); + CGRF.AllowZeroMoveEliminationOnly = + RF->getValueAsBit("AllowZeroMoveEliminationOnly"); // Now set the number of physical registers as well as the cost of registers // in each register class. CGRF.NumPhysRegs = RF->getValueAsInt("NumPhysRegs"); + if (!CGRF.NumPhysRegs) { + PrintFatalError(RF->getLoc(), + "Invalid RegisterFile with zero physical registers"); + } + RecVec RegisterClasses = RF->getValueAsListOfDefs("RegClasses"); std::vector<int64_t> RegisterCosts = RF->getValueAsListOfInts("RegCosts"); + ListInit *MoveElimInfo = RF->getValueAsListInit("AllowMoveElimination"); for (unsigned I = 0, E = RegisterClasses.size(); I < E; ++I) { int Cost = RegisterCosts.size() > I ? RegisterCosts[I] : 1; - CGRF.Costs.emplace_back(RegisterClasses[I], Cost); - } - } -} -// Collect all the RegisterFile definitions available in this target. -void CodeGenSchedModels::collectPfmCounters() { - for (Record *Def : Records.getAllDerivedDefinitions("PfmIssueCounter")) { - CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); - PM.PfmIssueCounterDefs.emplace_back(Def); - } - for (Record *Def : Records.getAllDerivedDefinitions("PfmCycleCounter")) { - CodeGenProcModel &PM = getProcModel(Def->getValueAsDef("SchedModel")); - if (PM.PfmCycleCounterDef) { - PrintFatalError(Def->getLoc(), - "multiple cycle counters for " + - Def->getValueAsDef("SchedModel")->getName()); + bool AllowMoveElim = false; + if (MoveElimInfo->size() > I) { + BitInit *Val = cast<BitInit>(MoveElimInfo->getElement(I)); + AllowMoveElim = Val->getValue(); + } + + CGRF.Costs.emplace_back(RegisterClasses[I], Cost, AllowMoveElim); } - PM.PfmCycleCounterDef = Def; } } @@ -1620,12 +1888,9 @@ void CodeGenSchedModels::collectProcResources() { } // Finalize each ProcModel by sorting the record arrays. for (CodeGenProcModel &PM : ProcModels) { - llvm::sort(PM.WriteResDefs.begin(), PM.WriteResDefs.end(), - LessRecord()); - llvm::sort(PM.ReadAdvanceDefs.begin(), PM.ReadAdvanceDefs.end(), - LessRecord()); - llvm::sort(PM.ProcResourceDefs.begin(), PM.ProcResourceDefs.end(), - LessRecord()); + llvm::sort(PM.WriteResDefs, LessRecord()); + llvm::sort(PM.ReadAdvanceDefs, LessRecord()); + llvm::sort(PM.ProcResourceDefs, LessRecord()); LLVM_DEBUG( PM.dump(); dbgs() << "WriteResDefs: "; for (RecIter RI = PM.WriteResDefs.begin(), |
