Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/DFAPacketizerEmitter.cpp
35258 views
//===- DFAPacketizerEmitter.cpp - Packetization DFA for a VLIW machine ----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This class parses the Schedule.td file and produces an API that can be used9// to reason about whether an instruction can be added to a packet on a VLIW10// architecture. The class internally generates a deterministic finite11// automaton (DFA) that models all possible mappings of machine instructions12// to functional units as instructions are added to a packet.13//14//===----------------------------------------------------------------------===//1516#include "Common/CodeGenSchedule.h"17#include "Common/CodeGenTarget.h"18#include "DFAEmitter.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/Support/Debug.h"21#include "llvm/Support/raw_ostream.h"22#include "llvm/TableGen/Record.h"23#include "llvm/TableGen/TableGenBackend.h"24#include <cassert>25#include <cstdint>26#include <deque>27#include <map>28#include <set>29#include <string>30#include <unordered_map>31#include <vector>3233#define DEBUG_TYPE "dfa-emitter"3435using namespace llvm;3637// We use a uint64_t to represent a resource bitmask.38#define DFA_MAX_RESOURCES 643940namespace {41using ResourceVector = SmallVector<uint64_t, 4>;4243struct ScheduleClass {44/// The parent itinerary index (processor model ID).45unsigned ItineraryID;4647/// Index within this itinerary of the schedule class.48unsigned Idx;4950/// The index within the uniqued set of required resources of Resources.51unsigned ResourcesIdx;5253/// Conjunctive list of resource requirements:54/// {a|b, b|c} => (a OR b) AND (b or c).55/// Resources are unique across all itineraries.56ResourceVector Resources;57};5859// Generates and prints out the DFA for resource tracking.60class DFAPacketizerEmitter {61private:62std::string TargetName;63RecordKeeper &Records;6465UniqueVector<ResourceVector> UniqueResources;66std::vector<ScheduleClass> ScheduleClasses;67std::map<std::string, uint64_t> FUNameToBitsMap;68std::map<unsigned, uint64_t> ComboBitToBitsMap;6970public:71DFAPacketizerEmitter(RecordKeeper &R);7273// Construct a map of function unit names to bits.74int collectAllFuncUnits(ArrayRef<const CodeGenProcModel *> ProcModels);7576// Construct a map from a combo function unit bit to the bits of all included77// functional units.78int collectAllComboFuncs(ArrayRef<Record *> ComboFuncList);7980ResourceVector getResourcesForItinerary(Record *Itinerary);81void createScheduleClasses(unsigned ItineraryIdx, const RecVec &Itineraries);8283// Emit code for a subset of itineraries.84void emitForItineraries(raw_ostream &OS,85std::vector<const CodeGenProcModel *> &ProcItinList,86std::string DFAName);8788void run(raw_ostream &OS);89};90} // end anonymous namespace9192DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R)93: TargetName(std::string(CodeGenTarget(R).getName())), Records(R) {}9495int DFAPacketizerEmitter::collectAllFuncUnits(96ArrayRef<const CodeGenProcModel *> ProcModels) {97LLVM_DEBUG(dbgs() << "-------------------------------------------------------"98"----------------------\n");99LLVM_DEBUG(dbgs() << "collectAllFuncUnits");100LLVM_DEBUG(dbgs() << " (" << ProcModels.size() << " itineraries)\n");101102std::set<Record *> ProcItinList;103for (const CodeGenProcModel *Model : ProcModels)104ProcItinList.insert(Model->ItinsDef);105106int totalFUs = 0;107// Parse functional units for all the itineraries.108for (Record *Proc : ProcItinList) {109std::vector<Record *> FUs = Proc->getValueAsListOfDefs("FU");110111LLVM_DEBUG(dbgs() << " FU:"112<< " (" << FUs.size() << " FUs) " << Proc->getName());113114// Convert macros to bits for each stage.115unsigned numFUs = FUs.size();116for (unsigned j = 0; j < numFUs; ++j) {117assert((j < DFA_MAX_RESOURCES) &&118"Exceeded maximum number of representable resources");119uint64_t FuncResources = 1ULL << j;120FUNameToBitsMap[std::string(FUs[j]->getName())] = FuncResources;121LLVM_DEBUG(dbgs() << " " << FUs[j]->getName() << ":0x"122<< Twine::utohexstr(FuncResources));123}124totalFUs += numFUs;125LLVM_DEBUG(dbgs() << "\n");126}127return totalFUs;128}129130int DFAPacketizerEmitter::collectAllComboFuncs(131ArrayRef<Record *> ComboFuncList) {132LLVM_DEBUG(dbgs() << "-------------------------------------------------------"133"----------------------\n");134LLVM_DEBUG(dbgs() << "collectAllComboFuncs");135LLVM_DEBUG(dbgs() << " (" << ComboFuncList.size() << " sets)\n");136137int numCombos = 0;138for (unsigned i = 0, N = ComboFuncList.size(); i < N; ++i) {139Record *Func = ComboFuncList[i];140std::vector<Record *> FUs = Func->getValueAsListOfDefs("CFD");141142LLVM_DEBUG(dbgs() << " CFD:" << i << " (" << FUs.size() << " combo FUs) "143<< Func->getName() << "\n");144145// Convert macros to bits for each stage.146for (unsigned j = 0, N = FUs.size(); j < N; ++j) {147assert((j < DFA_MAX_RESOURCES) &&148"Exceeded maximum number of DFA resources");149Record *FuncData = FUs[j];150Record *ComboFunc = FuncData->getValueAsDef("TheComboFunc");151const std::vector<Record *> &FuncList =152FuncData->getValueAsListOfDefs("FuncList");153const std::string &ComboFuncName = std::string(ComboFunc->getName());154uint64_t ComboBit = FUNameToBitsMap[ComboFuncName];155uint64_t ComboResources = ComboBit;156LLVM_DEBUG(dbgs() << " combo: " << ComboFuncName << ":0x"157<< Twine::utohexstr(ComboResources) << "\n");158for (auto *K : FuncList) {159std::string FuncName = std::string(K->getName());160uint64_t FuncResources = FUNameToBitsMap[FuncName];161LLVM_DEBUG(dbgs() << " " << FuncName << ":0x"162<< Twine::utohexstr(FuncResources) << "\n");163ComboResources |= FuncResources;164}165ComboBitToBitsMap[ComboBit] = ComboResources;166numCombos++;167LLVM_DEBUG(dbgs() << " => combo bits: " << ComboFuncName << ":0x"168<< Twine::utohexstr(ComboBit) << " = 0x"169<< Twine::utohexstr(ComboResources) << "\n");170}171}172return numCombos;173}174175ResourceVector176DFAPacketizerEmitter::getResourcesForItinerary(Record *Itinerary) {177ResourceVector Resources;178assert(Itinerary);179for (Record *StageDef : Itinerary->getValueAsListOfDefs("Stages")) {180uint64_t StageResources = 0;181for (Record *Unit : StageDef->getValueAsListOfDefs("Units")) {182StageResources |= FUNameToBitsMap[std::string(Unit->getName())];183}184if (StageResources != 0)185Resources.push_back(StageResources);186}187return Resources;188}189190void DFAPacketizerEmitter::createScheduleClasses(unsigned ItineraryIdx,191const RecVec &Itineraries) {192unsigned Idx = 0;193for (Record *Itinerary : Itineraries) {194if (!Itinerary) {195ScheduleClasses.push_back({ItineraryIdx, Idx++, 0, ResourceVector{}});196continue;197}198ResourceVector Resources = getResourcesForItinerary(Itinerary);199ScheduleClasses.push_back(200{ItineraryIdx, Idx++, UniqueResources.insert(Resources), Resources});201}202}203204//205// Run the worklist algorithm to generate the DFA.206//207void DFAPacketizerEmitter::run(raw_ostream &OS) {208emitSourceFileHeader("Target DFA Packetizer Tables", OS);209OS << "\n"210<< "#include \"llvm/CodeGen/DFAPacketizer.h\"\n";211OS << "namespace llvm {\n";212213CodeGenTarget CGT(Records);214CodeGenSchedModels CGS(Records, CGT);215216std::unordered_map<std::string, std::vector<const CodeGenProcModel *>>217ItinsByNamespace;218for (const CodeGenProcModel &ProcModel : CGS.procModels()) {219if (ProcModel.hasItineraries()) {220auto NS = ProcModel.ItinsDef->getValueAsString("PacketizerNamespace");221ItinsByNamespace[std::string(NS)].push_back(&ProcModel);222}223}224225for (auto &KV : ItinsByNamespace)226emitForItineraries(OS, KV.second, KV.first);227OS << "} // end namespace llvm\n";228}229230void DFAPacketizerEmitter::emitForItineraries(231raw_ostream &OS, std::vector<const CodeGenProcModel *> &ProcModels,232std::string DFAName) {233OS << "} // end namespace llvm\n\n";234OS << "namespace {\n";235collectAllFuncUnits(ProcModels);236collectAllComboFuncs(Records.getAllDerivedDefinitions("ComboFuncUnits"));237238// Collect the itineraries.239DenseMap<const CodeGenProcModel *, unsigned> ProcModelStartIdx;240for (const CodeGenProcModel *Model : ProcModels) {241assert(Model->hasItineraries());242ProcModelStartIdx[Model] = ScheduleClasses.size();243createScheduleClasses(Model->Index, Model->ItinDefList);244}245246// Output the mapping from ScheduleClass to ResourcesIdx.247unsigned Idx = 0;248OS << "constexpr unsigned " << TargetName << DFAName249<< "ResourceIndices[] = {";250for (const ScheduleClass &SC : ScheduleClasses) {251if (Idx++ % 32 == 0)252OS << "\n ";253OS << SC.ResourcesIdx << ", ";254}255OS << "\n};\n\n";256257// And the mapping from Itinerary index into the previous table.258OS << "constexpr unsigned " << TargetName << DFAName259<< "ProcResourceIndexStart[] = {\n";260OS << " 0, // NoSchedModel\n";261for (const CodeGenProcModel *Model : ProcModels) {262OS << " " << ProcModelStartIdx[Model] << ", // " << Model->ModelName263<< "\n";264}265OS << " " << ScheduleClasses.size() << "\n};\n\n";266267// The type of a state in the nondeterministic automaton we're defining.268using NfaStateTy = uint64_t;269270// Given a resource state, return all resource states by applying271// InsnClass.272auto applyInsnClass = [&](const ResourceVector &InsnClass,273NfaStateTy State) -> std::deque<NfaStateTy> {274std::deque<NfaStateTy> V(1, State);275// Apply every stage in the class individually.276for (NfaStateTy Stage : InsnClass) {277// Apply this stage to every existing member of V in turn.278size_t Sz = V.size();279for (unsigned I = 0; I < Sz; ++I) {280NfaStateTy S = V.front();281V.pop_front();282283// For this stage, state combination, try all possible resources.284for (unsigned J = 0; J < DFA_MAX_RESOURCES; ++J) {285NfaStateTy ResourceMask = 1ULL << J;286if ((ResourceMask & Stage) == 0)287// This resource isn't required by this stage.288continue;289NfaStateTy Combo = ComboBitToBitsMap[ResourceMask];290if (Combo && ((~S & Combo) != Combo))291// This combo units bits are not available.292continue;293NfaStateTy ResultingResourceState = S | ResourceMask | Combo;294if (ResultingResourceState == S)295continue;296V.push_back(ResultingResourceState);297}298}299}300return V;301};302303// Given a resource state, return a quick (conservative) guess as to whether304// InsnClass can be applied. This is a filter for the more heavyweight305// applyInsnClass.306auto canApplyInsnClass = [](const ResourceVector &InsnClass,307NfaStateTy State) -> bool {308for (NfaStateTy Resources : InsnClass) {309if ((State | Resources) == State)310return false;311}312return true;313};314315DfaEmitter Emitter;316std::deque<NfaStateTy> Worklist(1, 0);317std::set<NfaStateTy> SeenStates;318SeenStates.insert(Worklist.front());319while (!Worklist.empty()) {320NfaStateTy State = Worklist.front();321Worklist.pop_front();322for (const ResourceVector &Resources : UniqueResources) {323if (!canApplyInsnClass(Resources, State))324continue;325unsigned ResourcesID = UniqueResources.idFor(Resources);326for (uint64_t NewState : applyInsnClass(Resources, State)) {327if (SeenStates.emplace(NewState).second)328Worklist.emplace_back(NewState);329Emitter.addTransition(State, NewState, ResourcesID);330}331}332}333334std::string TargetAndDFAName = TargetName + DFAName;335Emitter.emit(TargetAndDFAName, OS);336OS << "} // end anonymous namespace\n\n";337338std::string SubTargetClassName = TargetName + "GenSubtargetInfo";339OS << "namespace llvm {\n";340OS << "DFAPacketizer *" << SubTargetClassName << "::"341<< "create" << DFAName342<< "DFAPacketizer(const InstrItineraryData *IID) const {\n"343<< " static Automaton<uint64_t> A(ArrayRef<" << TargetAndDFAName344<< "Transition>(" << TargetAndDFAName << "Transitions), "345<< TargetAndDFAName << "TransitionInfo);\n"346<< " unsigned ProcResIdxStart = " << TargetAndDFAName347<< "ProcResourceIndexStart[IID->SchedModel.ProcID];\n"348<< " unsigned ProcResIdxNum = " << TargetAndDFAName349<< "ProcResourceIndexStart[IID->SchedModel.ProcID + 1] - "350"ProcResIdxStart;\n"351<< " return new DFAPacketizer(IID, A, {&" << TargetAndDFAName352<< "ResourceIndices[ProcResIdxStart], ProcResIdxNum});\n"353<< "\n}\n\n";354}355356static TableGen::Emitter::OptClass<DFAPacketizerEmitter>357X("gen-dfa-packetizer", "Generate DFA Packetizer for VLIW targets");358359360