Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/CodeGenMapTable.cpp
35258 views
//===- CodeGenMapTable.cpp - Instruction Mapping Table Generator ----------===//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// CodeGenMapTable provides functionality for the TableGen to create8// relation mapping between instructions. Relation models are defined using9// InstrMapping as a base class. This file implements the functionality which10// parses these definitions and generates relation maps using the information11// specified there. These maps are emitted as tables in the XXXGenInstrInfo.inc12// file along with the functions to query them.13//14// A relationship model to relate non-predicate instructions with their15// predicated true/false forms can be defined as follows:16//17// def getPredOpcode : InstrMapping {18// let FilterClass = "PredRel";19// let RowFields = ["BaseOpcode"];20// let ColFields = ["PredSense"];21// let KeyCol = ["none"];22// let ValueCols = [["true"], ["false"]]; }23//24// CodeGenMapTable parses this map and generates a table in XXXGenInstrInfo.inc25// file that contains the instructions modeling this relationship. This table26// is defined in the function27// "int getPredOpcode(uint16_t Opcode, enum PredSense inPredSense)"28// that can be used to retrieve the predicated form of the instruction by29// passing its opcode value and the predicate sense (true/false) of the desired30// instruction as arguments.31//32// Short description of the algorithm:33//34// 1) Iterate through all the records that derive from "InstrMapping" class.35// 2) For each record, filter out instructions based on the FilterClass value.36// 3) Iterate through this set of instructions and insert them into37// RowInstrMap map based on their RowFields values. RowInstrMap is keyed by the38// vector of RowFields values and contains vectors of Records (instructions) as39// values. RowFields is a list of fields that are required to have the same40// values for all the instructions appearing in the same row of the relation41// table. All the instructions in a given row of the relation table have some42// sort of relationship with the key instruction defined by the corresponding43// relationship model.44//45// Ex: RowInstrMap(RowVal1, RowVal2, ...) -> [Instr1, Instr2, Instr3, ... ]46// Here Instr1, Instr2, Instr3 have same values (RowVal1, RowVal2) for47// RowFields. These groups of instructions are later matched against ValueCols48// to determine the column they belong to, if any.49//50// While building the RowInstrMap map, collect all the key instructions in51// KeyInstrVec. These are the instructions having the same values as KeyCol52// for all the fields listed in ColFields.53//54// For Example:55//56// Relate non-predicate instructions with their predicated true/false forms.57//58// def getPredOpcode : InstrMapping {59// let FilterClass = "PredRel";60// let RowFields = ["BaseOpcode"];61// let ColFields = ["PredSense"];62// let KeyCol = ["none"];63// let ValueCols = [["true"], ["false"]]; }64//65// Here, only instructions that have "none" as PredSense will be selected as key66// instructions.67//68// 4) For each key instruction, get the group of instructions that share the69// same key-value as the key instruction from RowInstrMap. Iterate over the list70// of columns in ValueCols (it is defined as a list<list<string> >. Therefore,71// it can specify multi-column relationships). For each column, find the72// instruction from the group that matches all the values for the column.73// Multiple matches are not allowed.74//75//===----------------------------------------------------------------------===//7677#include "Common/CodeGenInstruction.h"78#include "Common/CodeGenTarget.h"79#include "llvm/TableGen/Error.h"80#include "llvm/TableGen/Record.h"81using namespace llvm;82typedef std::map<std::string, std::vector<Record *>> InstrRelMapTy;8384typedef std::map<std::vector<Init *>, std::vector<Record *>> RowInstrMapTy;8586namespace {8788//===----------------------------------------------------------------------===//89// This class is used to represent InstrMapping class defined in Target.td file.90class InstrMap {91private:92std::string Name;93std::string FilterClass;94ListInit *RowFields;95ListInit *ColFields;96ListInit *KeyCol;97std::vector<ListInit *> ValueCols;9899public:100InstrMap(Record *MapRec) {101Name = std::string(MapRec->getName());102103// FilterClass - It's used to reduce the search space only to the104// instructions that define the kind of relationship modeled by105// this InstrMapping object/record.106const RecordVal *Filter = MapRec->getValue("FilterClass");107FilterClass = Filter->getValue()->getAsUnquotedString();108109// List of fields/attributes that need to be same across all the110// instructions in a row of the relation table.111RowFields = MapRec->getValueAsListInit("RowFields");112113// List of fields/attributes that are constant across all the instruction114// in a column of the relation table. Ex: ColFields = 'predSense'115ColFields = MapRec->getValueAsListInit("ColFields");116117// Values for the fields/attributes listed in 'ColFields'.118// Ex: KeyCol = 'noPred' -- key instruction is non-predicated119KeyCol = MapRec->getValueAsListInit("KeyCol");120121// List of values for the fields/attributes listed in 'ColFields', one for122// each column in the relation table.123//124// Ex: ValueCols = [['true'],['false']] -- it results two columns in the125// table. First column requires all the instructions to have predSense126// set to 'true' and second column requires it to be 'false'.127ListInit *ColValList = MapRec->getValueAsListInit("ValueCols");128129// Each instruction map must specify at least one column for it to be valid.130if (ColValList->empty())131PrintFatalError(MapRec->getLoc(), "InstrMapping record `" +132MapRec->getName() + "' has empty " +133"`ValueCols' field!");134135for (Init *I : ColValList->getValues()) {136auto *ColI = cast<ListInit>(I);137138// Make sure that all the sub-lists in 'ValueCols' have same number of139// elements as the fields in 'ColFields'.140if (ColI->size() != ColFields->size())141PrintFatalError(MapRec->getLoc(),142"Record `" + MapRec->getName() +143"', field `ValueCols' entries don't match with " +144" the entries in 'ColFields'!");145ValueCols.push_back(ColI);146}147}148149const std::string &getName() const { return Name; }150151const std::string &getFilterClass() const { return FilterClass; }152153ListInit *getRowFields() const { return RowFields; }154155ListInit *getColFields() const { return ColFields; }156157ListInit *getKeyCol() const { return KeyCol; }158159const std::vector<ListInit *> &getValueCols() const { return ValueCols; }160};161} // end anonymous namespace162163//===----------------------------------------------------------------------===//164// class MapTableEmitter : It builds the instruction relation maps using165// the information provided in InstrMapping records. It outputs these166// relationship maps as tables into XXXGenInstrInfo.inc file along with the167// functions to query them.168169namespace {170class MapTableEmitter {171private:172// std::string TargetName;173const CodeGenTarget &Target;174// InstrMapDesc - InstrMapping record to be processed.175InstrMap InstrMapDesc;176177// InstrDefs - list of instructions filtered using FilterClass defined178// in InstrMapDesc.179std::vector<Record *> InstrDefs;180181// RowInstrMap - maps RowFields values to the instructions. It's keyed by the182// values of the row fields and contains vector of records as values.183RowInstrMapTy RowInstrMap;184185// KeyInstrVec - list of key instructions.186std::vector<Record *> KeyInstrVec;187DenseMap<Record *, std::vector<Record *>> MapTable;188189public:190MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec)191: Target(Target), InstrMapDesc(IMRec) {192const std::string &FilterClass = InstrMapDesc.getFilterClass();193InstrDefs = Records.getAllDerivedDefinitions(FilterClass);194}195196void buildRowInstrMap();197198// Returns true if an instruction is a key instruction, i.e., its ColFields199// have same values as KeyCol.200bool isKeyColInstr(Record *CurInstr);201202// Find column instruction corresponding to a key instruction based on the203// constraints for that column.204Record *getInstrForColumn(Record *KeyInstr, ListInit *CurValueCol);205206// Find column instructions for each key instruction based207// on ValueCols and store them into MapTable.208void buildMapTable();209210void emitBinSearch(raw_ostream &OS, unsigned TableSize);211void emitTablesWithFunc(raw_ostream &OS);212unsigned emitBinSearchTable(raw_ostream &OS);213214// Lookup functions to query binary search tables.215void emitMapFuncBody(raw_ostream &OS, unsigned TableSize);216};217} // end anonymous namespace218219//===----------------------------------------------------------------------===//220// Process all the instructions that model this relation (alreday present in221// InstrDefs) and insert them into RowInstrMap which is keyed by the values of222// the fields listed as RowFields. It stores vectors of records as values.223// All the related instructions have the same values for the RowFields thus are224// part of the same key-value pair.225//===----------------------------------------------------------------------===//226227void MapTableEmitter::buildRowInstrMap() {228for (Record *CurInstr : InstrDefs) {229std::vector<Init *> KeyValue;230ListInit *RowFields = InstrMapDesc.getRowFields();231for (Init *RowField : RowFields->getValues()) {232RecordVal *RecVal = CurInstr->getValue(RowField);233if (RecVal == nullptr)234PrintFatalError(CurInstr->getLoc(),235"No value " + RowField->getAsString() + " found in \"" +236CurInstr->getName() +237"\" instruction description.");238Init *CurInstrVal = RecVal->getValue();239KeyValue.push_back(CurInstrVal);240}241242// Collect key instructions into KeyInstrVec. Later, these instructions are243// processed to assign column position to the instructions sharing244// their KeyValue in RowInstrMap.245if (isKeyColInstr(CurInstr))246KeyInstrVec.push_back(CurInstr);247248RowInstrMap[KeyValue].push_back(CurInstr);249}250}251252//===----------------------------------------------------------------------===//253// Return true if an instruction is a KeyCol instruction.254//===----------------------------------------------------------------------===//255256bool MapTableEmitter::isKeyColInstr(Record *CurInstr) {257ListInit *ColFields = InstrMapDesc.getColFields();258ListInit *KeyCol = InstrMapDesc.getKeyCol();259260// Check if the instruction is a KeyCol instruction.261bool MatchFound = true;262for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;263j++) {264RecordVal *ColFieldName = CurInstr->getValue(ColFields->getElement(j));265std::string CurInstrVal = ColFieldName->getValue()->getAsUnquotedString();266std::string KeyColValue = KeyCol->getElement(j)->getAsUnquotedString();267MatchFound = (CurInstrVal == KeyColValue);268}269return MatchFound;270}271272//===----------------------------------------------------------------------===//273// Build a map to link key instructions with the column instructions arranged274// according to their column positions.275//===----------------------------------------------------------------------===//276277void MapTableEmitter::buildMapTable() {278// Find column instructions for a given key based on the ColField279// constraints.280const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();281unsigned NumOfCols = ValueCols.size();282for (Record *CurKeyInstr : KeyInstrVec) {283std::vector<Record *> ColInstrVec(NumOfCols);284285// Find the column instruction based on the constraints for the column.286for (unsigned ColIdx = 0; ColIdx < NumOfCols; ColIdx++) {287ListInit *CurValueCol = ValueCols[ColIdx];288Record *ColInstr = getInstrForColumn(CurKeyInstr, CurValueCol);289ColInstrVec[ColIdx] = ColInstr;290}291MapTable[CurKeyInstr] = ColInstrVec;292}293}294295//===----------------------------------------------------------------------===//296// Find column instruction based on the constraints for that column.297//===----------------------------------------------------------------------===//298299Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,300ListInit *CurValueCol) {301ListInit *RowFields = InstrMapDesc.getRowFields();302std::vector<Init *> KeyValue;303304// Construct KeyValue using KeyInstr's values for RowFields.305for (Init *RowField : RowFields->getValues()) {306Init *KeyInstrVal = KeyInstr->getValue(RowField)->getValue();307KeyValue.push_back(KeyInstrVal);308}309310// Get all the instructions that share the same KeyValue as the KeyInstr311// in RowInstrMap. We search through these instructions to find a match312// for the current column, i.e., the instruction which has the same values313// as CurValueCol for all the fields in ColFields.314const std::vector<Record *> &RelatedInstrVec = RowInstrMap[KeyValue];315316ListInit *ColFields = InstrMapDesc.getColFields();317Record *MatchInstr = nullptr;318319for (llvm::Record *CurInstr : RelatedInstrVec) {320bool MatchFound = true;321for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;322j++) {323Init *ColFieldJ = ColFields->getElement(j);324Init *CurInstrInit = CurInstr->getValue(ColFieldJ)->getValue();325std::string CurInstrVal = CurInstrInit->getAsUnquotedString();326Init *ColFieldJVallue = CurValueCol->getElement(j);327MatchFound = (CurInstrVal == ColFieldJVallue->getAsUnquotedString());328}329330if (MatchFound) {331if (MatchInstr) {332// Already had a match333// Error if multiple matches are found for a column.334std::string KeyValueStr;335for (Init *Value : KeyValue) {336if (!KeyValueStr.empty())337KeyValueStr += ", ";338KeyValueStr += Value->getAsString();339}340341PrintFatalError("Multiple matches found for `" + KeyInstr->getName() +342"', for the relation `" + InstrMapDesc.getName() +343"', row fields [" + KeyValueStr + "], column `" +344CurValueCol->getAsString() + "'");345}346MatchInstr = CurInstr;347}348}349return MatchInstr;350}351352//===----------------------------------------------------------------------===//353// Emit one table per relation. Only instructions with a valid relation of a354// given type are included in the table sorted by their enum values (opcodes).355// Binary search is used for locating instructions in the table.356//===----------------------------------------------------------------------===//357358unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {359360ArrayRef<const CodeGenInstruction *> NumberedInstructions =361Target.getInstructionsByEnumValue();362StringRef Namespace = Target.getInstNamespace();363const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();364unsigned NumCol = ValueCols.size();365unsigned TotalNumInstr = NumberedInstructions.size();366unsigned TableSize = 0;367368OS << "static const uint16_t " << InstrMapDesc.getName();369// Number of columns in the table are NumCol+1 because key instructions are370// emitted as first column.371OS << "Table[][" << NumCol + 1 << "] = {\n";372for (unsigned i = 0; i < TotalNumInstr; i++) {373Record *CurInstr = NumberedInstructions[i]->TheDef;374std::vector<Record *> ColInstrs = MapTable[CurInstr];375std::string OutStr;376unsigned RelExists = 0;377if (!ColInstrs.empty()) {378for (unsigned j = 0; j < NumCol; j++) {379if (ColInstrs[j] != nullptr) {380RelExists = 1;381OutStr += ", ";382OutStr += Namespace;383OutStr += "::";384OutStr += ColInstrs[j]->getName();385} else {386OutStr += ", (uint16_t)-1U";387}388}389390if (RelExists) {391OS << " { " << Namespace << "::" << CurInstr->getName();392OS << OutStr << " },\n";393TableSize++;394}395}396}397if (!TableSize) {398OS << " { " << Namespace << "::"399<< "INSTRUCTION_LIST_END, ";400OS << Namespace << "::"401<< "INSTRUCTION_LIST_END }";402}403OS << "}; // End of " << InstrMapDesc.getName() << "Table\n\n";404return TableSize;405}406407//===----------------------------------------------------------------------===//408// Emit binary search algorithm as part of the functions used to query409// relation tables.410//===----------------------------------------------------------------------===//411412void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) {413OS << " unsigned mid;\n";414OS << " unsigned start = 0;\n";415OS << " unsigned end = " << TableSize << ";\n";416OS << " while (start < end) {\n";417OS << " mid = start + (end - start) / 2;\n";418OS << " if (Opcode == " << InstrMapDesc.getName() << "Table[mid][0]) {\n";419OS << " break;\n";420OS << " }\n";421OS << " if (Opcode < " << InstrMapDesc.getName() << "Table[mid][0])\n";422OS << " end = mid;\n";423OS << " else\n";424OS << " start = mid + 1;\n";425OS << " }\n";426OS << " if (start == end)\n";427OS << " return -1; // Instruction doesn't exist in this table.\n\n";428}429430//===----------------------------------------------------------------------===//431// Emit functions to query relation tables.432//===----------------------------------------------------------------------===//433434void MapTableEmitter::emitMapFuncBody(raw_ostream &OS, unsigned TableSize) {435436ListInit *ColFields = InstrMapDesc.getColFields();437const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();438439// Emit binary search algorithm to locate instructions in the440// relation table. If found, return opcode value from the appropriate column441// of the table.442emitBinSearch(OS, TableSize);443444if (ValueCols.size() > 1) {445for (unsigned i = 0, e = ValueCols.size(); i < e; i++) {446ListInit *ColumnI = ValueCols[i];447OS << " if (";448for (unsigned j = 0, ColSize = ColumnI->size(); j < ColSize; ++j) {449std::string ColName = ColFields->getElement(j)->getAsUnquotedString();450OS << "in" << ColName;451OS << " == ";452OS << ColName << "_" << ColumnI->getElement(j)->getAsUnquotedString();453if (j < ColumnI->size() - 1)454OS << " && ";455}456OS << ")\n";457OS << " return " << InstrMapDesc.getName();458OS << "Table[mid][" << i + 1 << "];\n";459}460OS << " return -1;";461} else462OS << " return " << InstrMapDesc.getName() << "Table[mid][1];\n";463464OS << "}\n\n";465}466467//===----------------------------------------------------------------------===//468// Emit relation tables and the functions to query them.469//===----------------------------------------------------------------------===//470471void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) {472473// Emit function name and the input parameters : mostly opcode value of the474// current instruction. However, if a table has multiple columns (more than 2475// since first column is used for the key instructions), then we also need476// to pass another input to indicate the column to be selected.477478ListInit *ColFields = InstrMapDesc.getColFields();479const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();480OS << "// " << InstrMapDesc.getName() << "\nLLVM_READONLY\n";481OS << "int " << InstrMapDesc.getName() << "(uint16_t Opcode";482if (ValueCols.size() > 1) {483for (Init *CF : ColFields->getValues()) {484std::string ColName = CF->getAsUnquotedString();485OS << ", enum " << ColName << " in" << ColName;486}487}488OS << ") {\n";489490// Emit map table.491unsigned TableSize = emitBinSearchTable(OS);492493// Emit rest of the function body.494emitMapFuncBody(OS, TableSize);495}496497//===----------------------------------------------------------------------===//498// Emit enums for the column fields across all the instruction maps.499//===----------------------------------------------------------------------===//500501static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {502503std::vector<Record *> InstrMapVec;504InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");505std::map<std::string, std::vector<Init *>> ColFieldValueMap;506507// Iterate over all InstrMapping records and create a map between column508// fields and their possible values across all records.509for (Record *CurMap : InstrMapVec) {510ListInit *ColFields;511ColFields = CurMap->getValueAsListInit("ColFields");512ListInit *List = CurMap->getValueAsListInit("ValueCols");513std::vector<ListInit *> ValueCols;514unsigned ListSize = List->size();515516for (unsigned j = 0; j < ListSize; j++) {517auto *ListJ = cast<ListInit>(List->getElement(j));518519if (ListJ->size() != ColFields->size())520PrintFatalError("Record `" + CurMap->getName() +521"', field "522"`ValueCols' entries don't match with the entries in "523"'ColFields' !");524ValueCols.push_back(ListJ);525}526527for (unsigned j = 0, endCF = ColFields->size(); j < endCF; j++) {528for (unsigned k = 0; k < ListSize; k++) {529std::string ColName = ColFields->getElement(j)->getAsUnquotedString();530ColFieldValueMap[ColName].push_back((ValueCols[k])->getElement(j));531}532}533}534535for (auto &Entry : ColFieldValueMap) {536std::vector<Init *> FieldValues = Entry.second;537538// Delete duplicate entries from ColFieldValueMap539for (unsigned i = 0; i < FieldValues.size() - 1; i++) {540Init *CurVal = FieldValues[i];541for (unsigned j = i + 1; j < FieldValues.size(); j++) {542if (CurVal == FieldValues[j]) {543FieldValues.erase(FieldValues.begin() + j);544--j;545}546}547}548549// Emit enumerated values for the column fields.550OS << "enum " << Entry.first << " {\n";551for (unsigned i = 0, endFV = FieldValues.size(); i < endFV; i++) {552OS << "\t" << Entry.first << "_" << FieldValues[i]->getAsUnquotedString();553if (i != endFV - 1)554OS << ",\n";555else556OS << "\n};\n\n";557}558}559}560561namespace llvm {562//===----------------------------------------------------------------------===//563// Parse 'InstrMapping' records and use the information to form relationship564// between instructions. These relations are emitted as a tables along with the565// functions to query them.566//===----------------------------------------------------------------------===//567void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {568CodeGenTarget Target(Records);569StringRef NameSpace = Target.getInstNamespace();570std::vector<Record *> InstrMapVec;571InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");572573if (InstrMapVec.empty())574return;575576OS << "#ifdef GET_INSTRMAP_INFO\n";577OS << "#undef GET_INSTRMAP_INFO\n";578OS << "namespace llvm {\n\n";579OS << "namespace " << NameSpace << " {\n\n";580581// Emit coulumn field names and their values as enums.582emitEnums(OS, Records);583584// Iterate over all instruction mapping records and construct relationship585// maps based on the information specified there.586//587for (Record *CurMap : InstrMapVec) {588MapTableEmitter IMap(Target, Records, CurMap);589590// Build RowInstrMap to group instructions based on their values for591// RowFields. In the process, also collect key instructions into592// KeyInstrVec.593IMap.buildRowInstrMap();594595// Build MapTable to map key instructions with the corresponding column596// instructions.597IMap.buildMapTable();598599// Emit map tables and the functions to query them.600IMap.emitTablesWithFunc(OS);601}602OS << "} // end namespace " << NameSpace << "\n";603OS << "} // end namespace llvm\n";604OS << "#endif // GET_INSTRMAP_INFO\n\n";605}606607} // namespace llvm608609610