xref: /src/contrib/llvm-project/llvm/utils/TableGen/CodeGenMapTable.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1522600a2SDimitry Andric //===- CodeGenMapTable.cpp - Instruction Mapping Table Generator ----------===//
2522600a2SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6522600a2SDimitry Andric //
7522600a2SDimitry Andric //===----------------------------------------------------------------------===//
8c0981da4SDimitry Andric // CodeGenMapTable provides functionality for the TableGen to create
9522600a2SDimitry Andric // relation mapping between instructions. Relation models are defined using
10522600a2SDimitry Andric // InstrMapping as a base class. This file implements the functionality which
11522600a2SDimitry Andric // parses these definitions and generates relation maps using the information
12522600a2SDimitry Andric // specified there. These maps are emitted as tables in the XXXGenInstrInfo.inc
13522600a2SDimitry Andric // file along with the functions to query them.
14522600a2SDimitry Andric //
15522600a2SDimitry Andric // A relationship model to relate non-predicate instructions with their
16522600a2SDimitry Andric // predicated true/false forms can be defined as follows:
17522600a2SDimitry Andric //
18522600a2SDimitry Andric // def getPredOpcode : InstrMapping {
19522600a2SDimitry Andric //  let FilterClass = "PredRel";
20522600a2SDimitry Andric //  let RowFields = ["BaseOpcode"];
21522600a2SDimitry Andric //  let ColFields = ["PredSense"];
22522600a2SDimitry Andric //  let KeyCol = ["none"];
23522600a2SDimitry Andric //  let ValueCols = [["true"], ["false"]]; }
24522600a2SDimitry Andric //
25522600a2SDimitry Andric // CodeGenMapTable parses this map and generates a table in XXXGenInstrInfo.inc
26522600a2SDimitry Andric // file that contains the instructions modeling this relationship. This table
27522600a2SDimitry Andric // is defined in the function
28522600a2SDimitry Andric // "int getPredOpcode(uint16_t Opcode, enum PredSense inPredSense)"
29522600a2SDimitry Andric // that can be used to retrieve the predicated form of the instruction by
30522600a2SDimitry Andric // passing its opcode value and the predicate sense (true/false) of the desired
31522600a2SDimitry Andric // instruction as arguments.
32522600a2SDimitry Andric //
33522600a2SDimitry Andric // Short description of the algorithm:
34522600a2SDimitry Andric //
35522600a2SDimitry Andric // 1) Iterate through all the records that derive from "InstrMapping" class.
36522600a2SDimitry Andric // 2) For each record, filter out instructions based on the FilterClass value.
37522600a2SDimitry Andric // 3) Iterate through this set of instructions and insert them into
38522600a2SDimitry Andric // RowInstrMap map based on their RowFields values. RowInstrMap is keyed by the
39522600a2SDimitry Andric // vector of RowFields values and contains vectors of Records (instructions) as
40522600a2SDimitry Andric // values. RowFields is a list of fields that are required to have the same
41522600a2SDimitry Andric // values for all the instructions appearing in the same row of the relation
42522600a2SDimitry Andric // table. All the instructions in a given row of the relation table have some
43522600a2SDimitry Andric // sort of relationship with the key instruction defined by the corresponding
44522600a2SDimitry Andric // relationship model.
45522600a2SDimitry Andric //
46522600a2SDimitry Andric // Ex: RowInstrMap(RowVal1, RowVal2, ...) -> [Instr1, Instr2, Instr3, ... ]
47522600a2SDimitry Andric // Here Instr1, Instr2, Instr3 have same values (RowVal1, RowVal2) for
48522600a2SDimitry Andric // RowFields. These groups of instructions are later matched against ValueCols
49522600a2SDimitry Andric // to determine the column they belong to, if any.
50522600a2SDimitry Andric //
51522600a2SDimitry Andric // While building the RowInstrMap map, collect all the key instructions in
52522600a2SDimitry Andric // KeyInstrVec. These are the instructions having the same values as KeyCol
53522600a2SDimitry Andric // for all the fields listed in ColFields.
54522600a2SDimitry Andric //
55522600a2SDimitry Andric // For Example:
56522600a2SDimitry Andric //
57522600a2SDimitry Andric // Relate non-predicate instructions with their predicated true/false forms.
58522600a2SDimitry Andric //
59522600a2SDimitry Andric // def getPredOpcode : InstrMapping {
60522600a2SDimitry Andric //  let FilterClass = "PredRel";
61522600a2SDimitry Andric //  let RowFields = ["BaseOpcode"];
62522600a2SDimitry Andric //  let ColFields = ["PredSense"];
63522600a2SDimitry Andric //  let KeyCol = ["none"];
64522600a2SDimitry Andric //  let ValueCols = [["true"], ["false"]]; }
65522600a2SDimitry Andric //
66522600a2SDimitry Andric // Here, only instructions that have "none" as PredSense will be selected as key
67522600a2SDimitry Andric // instructions.
68522600a2SDimitry Andric //
69522600a2SDimitry Andric // 4) For each key instruction, get the group of instructions that share the
70522600a2SDimitry Andric // same key-value as the key instruction from RowInstrMap. Iterate over the list
71522600a2SDimitry Andric // of columns in ValueCols (it is defined as a list<list<string> >. Therefore,
72522600a2SDimitry Andric // it can specify multi-column relationships). For each column, find the
73522600a2SDimitry Andric // instruction from the group that matches all the values for the column.
74522600a2SDimitry Andric // Multiple matches are not allowed.
75522600a2SDimitry Andric //
76522600a2SDimitry Andric //===----------------------------------------------------------------------===//
77522600a2SDimitry Andric 
78ac9a064cSDimitry Andric #include "Common/CodeGenInstruction.h"
79ac9a064cSDimitry Andric #include "Common/CodeGenTarget.h"
80522600a2SDimitry Andric #include "llvm/TableGen/Error.h"
817fa27ce4SDimitry Andric #include "llvm/TableGen/Record.h"
82522600a2SDimitry Andric using namespace llvm;
83522600a2SDimitry Andric typedef std::map<std::string, std::vector<Record *>> InstrRelMapTy;
84522600a2SDimitry Andric 
85522600a2SDimitry Andric typedef std::map<std::vector<Init *>, std::vector<Record *>> RowInstrMapTy;
86522600a2SDimitry Andric 
87522600a2SDimitry Andric namespace {
88522600a2SDimitry Andric 
89522600a2SDimitry Andric //===----------------------------------------------------------------------===//
90522600a2SDimitry Andric // This class is used to represent InstrMapping class defined in Target.td file.
91522600a2SDimitry Andric class InstrMap {
92522600a2SDimitry Andric private:
93522600a2SDimitry Andric   std::string Name;
94522600a2SDimitry Andric   std::string FilterClass;
95522600a2SDimitry Andric   ListInit *RowFields;
96522600a2SDimitry Andric   ListInit *ColFields;
97522600a2SDimitry Andric   ListInit *KeyCol;
98522600a2SDimitry Andric   std::vector<ListInit *> ValueCols;
99522600a2SDimitry Andric 
100522600a2SDimitry Andric public:
InstrMap(Record * MapRec)101522600a2SDimitry Andric   InstrMap(Record *MapRec) {
102cfca06d7SDimitry Andric     Name = std::string(MapRec->getName());
103522600a2SDimitry Andric 
104522600a2SDimitry Andric     // FilterClass - It's used to reduce the search space only to the
105522600a2SDimitry Andric     // instructions that define the kind of relationship modeled by
106522600a2SDimitry Andric     // this InstrMapping object/record.
107522600a2SDimitry Andric     const RecordVal *Filter = MapRec->getValue("FilterClass");
108522600a2SDimitry Andric     FilterClass = Filter->getValue()->getAsUnquotedString();
109522600a2SDimitry Andric 
110522600a2SDimitry Andric     // List of fields/attributes that need to be same across all the
111522600a2SDimitry Andric     // instructions in a row of the relation table.
112522600a2SDimitry Andric     RowFields = MapRec->getValueAsListInit("RowFields");
113522600a2SDimitry Andric 
114522600a2SDimitry Andric     // List of fields/attributes that are constant across all the instruction
115522600a2SDimitry Andric     // in a column of the relation table. Ex: ColFields = 'predSense'
116522600a2SDimitry Andric     ColFields = MapRec->getValueAsListInit("ColFields");
117522600a2SDimitry Andric 
118522600a2SDimitry Andric     // Values for the fields/attributes listed in 'ColFields'.
1195ca98fd9SDimitry Andric     // Ex: KeyCol = 'noPred' -- key instruction is non-predicated
120522600a2SDimitry Andric     KeyCol = MapRec->getValueAsListInit("KeyCol");
121522600a2SDimitry Andric 
122522600a2SDimitry Andric     // List of values for the fields/attributes listed in 'ColFields', one for
123522600a2SDimitry Andric     // each column in the relation table.
124522600a2SDimitry Andric     //
125522600a2SDimitry Andric     // Ex: ValueCols = [['true'],['false']] -- it results two columns in the
126522600a2SDimitry Andric     // table. First column requires all the instructions to have predSense
127522600a2SDimitry Andric     // set to 'true' and second column requires it to be 'false'.
128522600a2SDimitry Andric     ListInit *ColValList = MapRec->getValueAsListInit("ValueCols");
129522600a2SDimitry Andric 
130522600a2SDimitry Andric     // Each instruction map must specify at least one column for it to be valid.
1315a5ac124SDimitry Andric     if (ColValList->empty())
132522600a2SDimitry Andric       PrintFatalError(MapRec->getLoc(), "InstrMapping record `" +
133ac9a064cSDimitry Andric                                             MapRec->getName() + "' has empty " +
134ac9a064cSDimitry Andric                                             "`ValueCols' field!");
135522600a2SDimitry Andric 
13685d8b2bbSDimitry Andric     for (Init *I : ColValList->getValues()) {
1371d5ae102SDimitry Andric       auto *ColI = cast<ListInit>(I);
138522600a2SDimitry Andric 
139522600a2SDimitry Andric       // Make sure that all the sub-lists in 'ValueCols' have same number of
140522600a2SDimitry Andric       // elements as the fields in 'ColFields'.
14185d8b2bbSDimitry Andric       if (ColI->size() != ColFields->size())
142ac9a064cSDimitry Andric         PrintFatalError(MapRec->getLoc(),
143ac9a064cSDimitry Andric                         "Record `" + MapRec->getName() +
144522600a2SDimitry Andric                             "', field `ValueCols' entries don't match with " +
145522600a2SDimitry Andric                             " the entries in 'ColFields'!");
146522600a2SDimitry Andric       ValueCols.push_back(ColI);
147522600a2SDimitry Andric     }
148522600a2SDimitry Andric   }
149522600a2SDimitry Andric 
getName() const150b60736ecSDimitry Andric   const std::string &getName() const { return Name; }
151522600a2SDimitry Andric 
getFilterClass() const152b60736ecSDimitry Andric   const std::string &getFilterClass() const { return FilterClass; }
153522600a2SDimitry Andric 
getRowFields() const154b60736ecSDimitry Andric   ListInit *getRowFields() const { return RowFields; }
155522600a2SDimitry Andric 
getColFields() const156b60736ecSDimitry Andric   ListInit *getColFields() const { return ColFields; }
157522600a2SDimitry Andric 
getKeyCol() const158b60736ecSDimitry Andric   ListInit *getKeyCol() const { return KeyCol; }
159522600a2SDimitry Andric 
getValueCols() const160ac9a064cSDimitry Andric   const std::vector<ListInit *> &getValueCols() const { return ValueCols; }
161522600a2SDimitry Andric };
1621d5ae102SDimitry Andric } // end anonymous namespace
163522600a2SDimitry Andric 
164522600a2SDimitry Andric //===----------------------------------------------------------------------===//
165522600a2SDimitry Andric // class MapTableEmitter : It builds the instruction relation maps using
166522600a2SDimitry Andric // the information provided in InstrMapping records. It outputs these
167522600a2SDimitry Andric // relationship maps as tables into XXXGenInstrInfo.inc file along with the
168522600a2SDimitry Andric // functions to query them.
169522600a2SDimitry Andric 
170522600a2SDimitry Andric namespace {
171522600a2SDimitry Andric class MapTableEmitter {
172522600a2SDimitry Andric private:
173522600a2SDimitry Andric   //  std::string TargetName;
174522600a2SDimitry Andric   const CodeGenTarget &Target;
175522600a2SDimitry Andric   // InstrMapDesc - InstrMapping record to be processed.
176522600a2SDimitry Andric   InstrMap InstrMapDesc;
177522600a2SDimitry Andric 
178522600a2SDimitry Andric   // InstrDefs - list of instructions filtered using FilterClass defined
179522600a2SDimitry Andric   // in InstrMapDesc.
180522600a2SDimitry Andric   std::vector<Record *> InstrDefs;
181522600a2SDimitry Andric 
182522600a2SDimitry Andric   // RowInstrMap - maps RowFields values to the instructions. It's keyed by the
183522600a2SDimitry Andric   // values of the row fields and contains vector of records as values.
184522600a2SDimitry Andric   RowInstrMapTy RowInstrMap;
185522600a2SDimitry Andric 
186522600a2SDimitry Andric   // KeyInstrVec - list of key instructions.
187522600a2SDimitry Andric   std::vector<Record *> KeyInstrVec;
188522600a2SDimitry Andric   DenseMap<Record *, std::vector<Record *>> MapTable;
189522600a2SDimitry Andric 
190522600a2SDimitry Andric public:
MapTableEmitter(CodeGenTarget & Target,RecordKeeper & Records,Record * IMRec)191ac9a064cSDimitry Andric   MapTableEmitter(CodeGenTarget &Target, RecordKeeper &Records, Record *IMRec)
192ac9a064cSDimitry Andric       : Target(Target), InstrMapDesc(IMRec) {
193b60736ecSDimitry Andric     const std::string &FilterClass = InstrMapDesc.getFilterClass();
194522600a2SDimitry Andric     InstrDefs = Records.getAllDerivedDefinitions(FilterClass);
195522600a2SDimitry Andric   }
196522600a2SDimitry Andric 
197522600a2SDimitry Andric   void buildRowInstrMap();
198522600a2SDimitry Andric 
199522600a2SDimitry Andric   // Returns true if an instruction is a key instruction, i.e., its ColFields
200522600a2SDimitry Andric   // have same values as KeyCol.
201522600a2SDimitry Andric   bool isKeyColInstr(Record *CurInstr);
202522600a2SDimitry Andric 
203522600a2SDimitry Andric   // Find column instruction corresponding to a key instruction based on the
204522600a2SDimitry Andric   // constraints for that column.
205522600a2SDimitry Andric   Record *getInstrForColumn(Record *KeyInstr, ListInit *CurValueCol);
206522600a2SDimitry Andric 
207522600a2SDimitry Andric   // Find column instructions for each key instruction based
208522600a2SDimitry Andric   // on ValueCols and store them into MapTable.
209522600a2SDimitry Andric   void buildMapTable();
210522600a2SDimitry Andric 
211522600a2SDimitry Andric   void emitBinSearch(raw_ostream &OS, unsigned TableSize);
212522600a2SDimitry Andric   void emitTablesWithFunc(raw_ostream &OS);
213522600a2SDimitry Andric   unsigned emitBinSearchTable(raw_ostream &OS);
214522600a2SDimitry Andric 
215522600a2SDimitry Andric   // Lookup functions to query binary search tables.
216522600a2SDimitry Andric   void emitMapFuncBody(raw_ostream &OS, unsigned TableSize);
217522600a2SDimitry Andric };
2181d5ae102SDimitry Andric } // end anonymous namespace
219522600a2SDimitry Andric 
220522600a2SDimitry Andric //===----------------------------------------------------------------------===//
221522600a2SDimitry Andric // Process all the instructions that model this relation (alreday present in
222522600a2SDimitry Andric // InstrDefs) and insert them into RowInstrMap which is keyed by the values of
223522600a2SDimitry Andric // the fields listed as RowFields. It stores vectors of records as values.
224522600a2SDimitry Andric // All the related instructions have the same values for the RowFields thus are
225522600a2SDimitry Andric // part of the same key-value pair.
226522600a2SDimitry Andric //===----------------------------------------------------------------------===//
227522600a2SDimitry Andric 
buildRowInstrMap()228522600a2SDimitry Andric void MapTableEmitter::buildRowInstrMap() {
22985d8b2bbSDimitry Andric   for (Record *CurInstr : InstrDefs) {
230522600a2SDimitry Andric     std::vector<Init *> KeyValue;
231522600a2SDimitry Andric     ListInit *RowFields = InstrMapDesc.getRowFields();
23285d8b2bbSDimitry Andric     for (Init *RowField : RowFields->getValues()) {
233eb11fae6SDimitry Andric       RecordVal *RecVal = CurInstr->getValue(RowField);
234eb11fae6SDimitry Andric       if (RecVal == nullptr)
235ac9a064cSDimitry Andric         PrintFatalError(CurInstr->getLoc(),
236ac9a064cSDimitry Andric                         "No value " + RowField->getAsString() + " found in \"" +
237ac9a064cSDimitry Andric                             CurInstr->getName() +
238ac9a064cSDimitry Andric                             "\" instruction description.");
239eb11fae6SDimitry Andric       Init *CurInstrVal = RecVal->getValue();
240522600a2SDimitry Andric       KeyValue.push_back(CurInstrVal);
241522600a2SDimitry Andric     }
242522600a2SDimitry Andric 
243522600a2SDimitry Andric     // Collect key instructions into KeyInstrVec. Later, these instructions are
244522600a2SDimitry Andric     // processed to assign column position to the instructions sharing
245522600a2SDimitry Andric     // their KeyValue in RowInstrMap.
246522600a2SDimitry Andric     if (isKeyColInstr(CurInstr))
247522600a2SDimitry Andric       KeyInstrVec.push_back(CurInstr);
248522600a2SDimitry Andric 
249522600a2SDimitry Andric     RowInstrMap[KeyValue].push_back(CurInstr);
250522600a2SDimitry Andric   }
251522600a2SDimitry Andric }
252522600a2SDimitry Andric 
253522600a2SDimitry Andric //===----------------------------------------------------------------------===//
254522600a2SDimitry Andric // Return true if an instruction is a KeyCol instruction.
255522600a2SDimitry Andric //===----------------------------------------------------------------------===//
256522600a2SDimitry Andric 
isKeyColInstr(Record * CurInstr)257522600a2SDimitry Andric bool MapTableEmitter::isKeyColInstr(Record *CurInstr) {
258522600a2SDimitry Andric   ListInit *ColFields = InstrMapDesc.getColFields();
259522600a2SDimitry Andric   ListInit *KeyCol = InstrMapDesc.getKeyCol();
260522600a2SDimitry Andric 
261522600a2SDimitry Andric   // Check if the instruction is a KeyCol instruction.
262522600a2SDimitry Andric   bool MatchFound = true;
263ac9a064cSDimitry Andric   for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;
264ac9a064cSDimitry Andric        j++) {
265522600a2SDimitry Andric     RecordVal *ColFieldName = CurInstr->getValue(ColFields->getElement(j));
266522600a2SDimitry Andric     std::string CurInstrVal = ColFieldName->getValue()->getAsUnquotedString();
267522600a2SDimitry Andric     std::string KeyColValue = KeyCol->getElement(j)->getAsUnquotedString();
268522600a2SDimitry Andric     MatchFound = (CurInstrVal == KeyColValue);
269522600a2SDimitry Andric   }
270522600a2SDimitry Andric   return MatchFound;
271522600a2SDimitry Andric }
272522600a2SDimitry Andric 
273522600a2SDimitry Andric //===----------------------------------------------------------------------===//
274522600a2SDimitry Andric // Build a map to link key instructions with the column instructions arranged
275522600a2SDimitry Andric // according to their column positions.
276522600a2SDimitry Andric //===----------------------------------------------------------------------===//
277522600a2SDimitry Andric 
buildMapTable()278522600a2SDimitry Andric void MapTableEmitter::buildMapTable() {
279522600a2SDimitry Andric   // Find column instructions for a given key based on the ColField
280522600a2SDimitry Andric   // constraints.
281522600a2SDimitry Andric   const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
282522600a2SDimitry Andric   unsigned NumOfCols = ValueCols.size();
28385d8b2bbSDimitry Andric   for (Record *CurKeyInstr : KeyInstrVec) {
284522600a2SDimitry Andric     std::vector<Record *> ColInstrVec(NumOfCols);
285522600a2SDimitry Andric 
286522600a2SDimitry Andric     // Find the column instruction based on the constraints for the column.
287522600a2SDimitry Andric     for (unsigned ColIdx = 0; ColIdx < NumOfCols; ColIdx++) {
288522600a2SDimitry Andric       ListInit *CurValueCol = ValueCols[ColIdx];
289522600a2SDimitry Andric       Record *ColInstr = getInstrForColumn(CurKeyInstr, CurValueCol);
290522600a2SDimitry Andric       ColInstrVec[ColIdx] = ColInstr;
291522600a2SDimitry Andric     }
292522600a2SDimitry Andric     MapTable[CurKeyInstr] = ColInstrVec;
293522600a2SDimitry Andric   }
294522600a2SDimitry Andric }
295522600a2SDimitry Andric 
296522600a2SDimitry Andric //===----------------------------------------------------------------------===//
297522600a2SDimitry Andric // Find column instruction based on the constraints for that column.
298522600a2SDimitry Andric //===----------------------------------------------------------------------===//
299522600a2SDimitry Andric 
getInstrForColumn(Record * KeyInstr,ListInit * CurValueCol)300522600a2SDimitry Andric Record *MapTableEmitter::getInstrForColumn(Record *KeyInstr,
301522600a2SDimitry Andric                                            ListInit *CurValueCol) {
302522600a2SDimitry Andric   ListInit *RowFields = InstrMapDesc.getRowFields();
303522600a2SDimitry Andric   std::vector<Init *> KeyValue;
304522600a2SDimitry Andric 
305522600a2SDimitry Andric   // Construct KeyValue using KeyInstr's values for RowFields.
30685d8b2bbSDimitry Andric   for (Init *RowField : RowFields->getValues()) {
30785d8b2bbSDimitry Andric     Init *KeyInstrVal = KeyInstr->getValue(RowField)->getValue();
308522600a2SDimitry Andric     KeyValue.push_back(KeyInstrVal);
309522600a2SDimitry Andric   }
310522600a2SDimitry Andric 
311522600a2SDimitry Andric   // Get all the instructions that share the same KeyValue as the KeyInstr
312522600a2SDimitry Andric   // in RowInstrMap. We search through these instructions to find a match
313522600a2SDimitry Andric   // for the current column, i.e., the instruction which has the same values
314522600a2SDimitry Andric   // as CurValueCol for all the fields in ColFields.
315522600a2SDimitry Andric   const std::vector<Record *> &RelatedInstrVec = RowInstrMap[KeyValue];
316522600a2SDimitry Andric 
317522600a2SDimitry Andric   ListInit *ColFields = InstrMapDesc.getColFields();
3185ca98fd9SDimitry Andric   Record *MatchInstr = nullptr;
319522600a2SDimitry Andric 
320344a3780SDimitry Andric   for (llvm::Record *CurInstr : RelatedInstrVec) {
321522600a2SDimitry Andric     bool MatchFound = true;
322ac9a064cSDimitry Andric     for (unsigned j = 0, endCF = ColFields->size(); (j < endCF) && MatchFound;
323ac9a064cSDimitry Andric          j++) {
324522600a2SDimitry Andric       Init *ColFieldJ = ColFields->getElement(j);
325522600a2SDimitry Andric       Init *CurInstrInit = CurInstr->getValue(ColFieldJ)->getValue();
326522600a2SDimitry Andric       std::string CurInstrVal = CurInstrInit->getAsUnquotedString();
327522600a2SDimitry Andric       Init *ColFieldJVallue = CurValueCol->getElement(j);
328522600a2SDimitry Andric       MatchFound = (CurInstrVal == ColFieldJVallue->getAsUnquotedString());
329522600a2SDimitry Andric     }
330522600a2SDimitry Andric 
331522600a2SDimitry Andric     if (MatchFound) {
33201095a5dSDimitry Andric       if (MatchInstr) {
33301095a5dSDimitry Andric         // Already had a match
334522600a2SDimitry Andric         // Error if multiple matches are found for a column.
33501095a5dSDimitry Andric         std::string KeyValueStr;
33601095a5dSDimitry Andric         for (Init *Value : KeyValue) {
33701095a5dSDimitry Andric           if (!KeyValueStr.empty())
33801095a5dSDimitry Andric             KeyValueStr += ", ";
33901095a5dSDimitry Andric           KeyValueStr += Value->getAsString();
34001095a5dSDimitry Andric         }
34101095a5dSDimitry Andric 
342522600a2SDimitry Andric         PrintFatalError("Multiple matches found for `" + KeyInstr->getName() +
343344a3780SDimitry Andric                         "', for the relation `" + InstrMapDesc.getName() +
344344a3780SDimitry Andric                         "', row fields [" + KeyValueStr + "], column `" +
345344a3780SDimitry Andric                         CurValueCol->getAsString() + "'");
34601095a5dSDimitry Andric       }
347522600a2SDimitry Andric       MatchInstr = CurInstr;
348522600a2SDimitry Andric     }
349522600a2SDimitry Andric   }
350522600a2SDimitry Andric   return MatchInstr;
351522600a2SDimitry Andric }
352522600a2SDimitry Andric 
353522600a2SDimitry Andric //===----------------------------------------------------------------------===//
354522600a2SDimitry Andric // Emit one table per relation. Only instructions with a valid relation of a
355522600a2SDimitry Andric // given type are included in the table sorted by their enum values (opcodes).
356522600a2SDimitry Andric // Binary search is used for locating instructions in the table.
357522600a2SDimitry Andric //===----------------------------------------------------------------------===//
358522600a2SDimitry Andric 
emitBinSearchTable(raw_ostream & OS)359522600a2SDimitry Andric unsigned MapTableEmitter::emitBinSearchTable(raw_ostream &OS) {
360522600a2SDimitry Andric 
36101095a5dSDimitry Andric   ArrayRef<const CodeGenInstruction *> NumberedInstructions =
362522600a2SDimitry Andric       Target.getInstructionsByEnumValue();
363ca089b24SDimitry Andric   StringRef Namespace = Target.getInstNamespace();
364522600a2SDimitry Andric   const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
365522600a2SDimitry Andric   unsigned NumCol = ValueCols.size();
366522600a2SDimitry Andric   unsigned TotalNumInstr = NumberedInstructions.size();
367522600a2SDimitry Andric   unsigned TableSize = 0;
368522600a2SDimitry Andric 
369522600a2SDimitry Andric   OS << "static const uint16_t " << InstrMapDesc.getName();
370522600a2SDimitry Andric   // Number of columns in the table are NumCol+1 because key instructions are
371522600a2SDimitry Andric   // emitted as first column.
372522600a2SDimitry Andric   OS << "Table[][" << NumCol + 1 << "] = {\n";
373522600a2SDimitry Andric   for (unsigned i = 0; i < TotalNumInstr; i++) {
374522600a2SDimitry Andric     Record *CurInstr = NumberedInstructions[i]->TheDef;
375522600a2SDimitry Andric     std::vector<Record *> ColInstrs = MapTable[CurInstr];
376b60736ecSDimitry Andric     std::string OutStr;
377522600a2SDimitry Andric     unsigned RelExists = 0;
3785a5ac124SDimitry Andric     if (!ColInstrs.empty()) {
379522600a2SDimitry Andric       for (unsigned j = 0; j < NumCol; j++) {
3805ca98fd9SDimitry Andric         if (ColInstrs[j] != nullptr) {
381522600a2SDimitry Andric           RelExists = 1;
382522600a2SDimitry Andric           OutStr += ", ";
38371d5a254SDimitry Andric           OutStr += Namespace;
384522600a2SDimitry Andric           OutStr += "::";
385522600a2SDimitry Andric           OutStr += ColInstrs[j]->getName();
386ac9a064cSDimitry Andric         } else {
387ac9a064cSDimitry Andric           OutStr += ", (uint16_t)-1U";
388ac9a064cSDimitry Andric         }
389522600a2SDimitry Andric       }
390522600a2SDimitry Andric 
391522600a2SDimitry Andric       if (RelExists) {
39271d5a254SDimitry Andric         OS << "  { " << Namespace << "::" << CurInstr->getName();
393522600a2SDimitry Andric         OS << OutStr << " },\n";
394522600a2SDimitry Andric         TableSize++;
395522600a2SDimitry Andric       }
396522600a2SDimitry Andric     }
397522600a2SDimitry Andric   }
398522600a2SDimitry Andric   if (!TableSize) {
399ac9a064cSDimitry Andric     OS << "  { " << Namespace << "::"
400ac9a064cSDimitry Andric        << "INSTRUCTION_LIST_END, ";
401ac9a064cSDimitry Andric     OS << Namespace << "::"
402ac9a064cSDimitry Andric        << "INSTRUCTION_LIST_END }";
403522600a2SDimitry Andric   }
404522600a2SDimitry Andric   OS << "}; // End of " << InstrMapDesc.getName() << "Table\n\n";
405522600a2SDimitry Andric   return TableSize;
406522600a2SDimitry Andric }
407522600a2SDimitry Andric 
408522600a2SDimitry Andric //===----------------------------------------------------------------------===//
409522600a2SDimitry Andric // Emit binary search algorithm as part of the functions used to query
410522600a2SDimitry Andric // relation tables.
411522600a2SDimitry Andric //===----------------------------------------------------------------------===//
412522600a2SDimitry Andric 
emitBinSearch(raw_ostream & OS,unsigned TableSize)413522600a2SDimitry Andric void MapTableEmitter::emitBinSearch(raw_ostream &OS, unsigned TableSize) {
414522600a2SDimitry Andric   OS << "  unsigned mid;\n";
415522600a2SDimitry Andric   OS << "  unsigned start = 0;\n";
416522600a2SDimitry Andric   OS << "  unsigned end = " << TableSize << ";\n";
417522600a2SDimitry Andric   OS << "  while (start < end) {\n";
418522600a2SDimitry Andric   OS << "    mid = start + (end - start) / 2;\n";
419522600a2SDimitry Andric   OS << "    if (Opcode == " << InstrMapDesc.getName() << "Table[mid][0]) {\n";
420522600a2SDimitry Andric   OS << "      break;\n";
421522600a2SDimitry Andric   OS << "    }\n";
422522600a2SDimitry Andric   OS << "    if (Opcode < " << InstrMapDesc.getName() << "Table[mid][0])\n";
423522600a2SDimitry Andric   OS << "      end = mid;\n";
424522600a2SDimitry Andric   OS << "    else\n";
425522600a2SDimitry Andric   OS << "      start = mid + 1;\n";
426522600a2SDimitry Andric   OS << "  }\n";
427522600a2SDimitry Andric   OS << "  if (start == end)\n";
428522600a2SDimitry Andric   OS << "    return -1; // Instruction doesn't exist in this table.\n\n";
429522600a2SDimitry Andric }
430522600a2SDimitry Andric 
431522600a2SDimitry Andric //===----------------------------------------------------------------------===//
432522600a2SDimitry Andric // Emit functions to query relation tables.
433522600a2SDimitry Andric //===----------------------------------------------------------------------===//
434522600a2SDimitry Andric 
emitMapFuncBody(raw_ostream & OS,unsigned TableSize)435ac9a064cSDimitry Andric void MapTableEmitter::emitMapFuncBody(raw_ostream &OS, unsigned TableSize) {
436522600a2SDimitry Andric 
437522600a2SDimitry Andric   ListInit *ColFields = InstrMapDesc.getColFields();
438522600a2SDimitry Andric   const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
439522600a2SDimitry Andric 
440522600a2SDimitry Andric   // Emit binary search algorithm to locate instructions in the
441522600a2SDimitry Andric   // relation table. If found, return opcode value from the appropriate column
442522600a2SDimitry Andric   // of the table.
443522600a2SDimitry Andric   emitBinSearch(OS, TableSize);
444522600a2SDimitry Andric 
445522600a2SDimitry Andric   if (ValueCols.size() > 1) {
446522600a2SDimitry Andric     for (unsigned i = 0, e = ValueCols.size(); i < e; i++) {
447522600a2SDimitry Andric       ListInit *ColumnI = ValueCols[i];
448c0981da4SDimitry Andric       OS << "  if (";
44985d8b2bbSDimitry Andric       for (unsigned j = 0, ColSize = ColumnI->size(); j < ColSize; ++j) {
450522600a2SDimitry Andric         std::string ColName = ColFields->getElement(j)->getAsUnquotedString();
451c0981da4SDimitry Andric         OS << "in" << ColName;
452522600a2SDimitry Andric         OS << " == ";
453522600a2SDimitry Andric         OS << ColName << "_" << ColumnI->getElement(j)->getAsUnquotedString();
454c0981da4SDimitry Andric         if (j < ColumnI->size() - 1)
455c0981da4SDimitry Andric           OS << " && ";
456522600a2SDimitry Andric       }
457c0981da4SDimitry Andric       OS << ")\n";
458522600a2SDimitry Andric       OS << "    return " << InstrMapDesc.getName();
459522600a2SDimitry Andric       OS << "Table[mid][" << i + 1 << "];\n";
460522600a2SDimitry Andric     }
461522600a2SDimitry Andric     OS << "  return -1;";
462ac9a064cSDimitry Andric   } else
463522600a2SDimitry Andric     OS << "  return " << InstrMapDesc.getName() << "Table[mid][1];\n";
464522600a2SDimitry Andric 
465522600a2SDimitry Andric   OS << "}\n\n";
466522600a2SDimitry Andric }
467522600a2SDimitry Andric 
468522600a2SDimitry Andric //===----------------------------------------------------------------------===//
469522600a2SDimitry Andric // Emit relation tables and the functions to query them.
470522600a2SDimitry Andric //===----------------------------------------------------------------------===//
471522600a2SDimitry Andric 
emitTablesWithFunc(raw_ostream & OS)472522600a2SDimitry Andric void MapTableEmitter::emitTablesWithFunc(raw_ostream &OS) {
473522600a2SDimitry Andric 
474522600a2SDimitry Andric   // Emit function name and the input parameters : mostly opcode value of the
475522600a2SDimitry Andric   // current instruction. However, if a table has multiple columns (more than 2
476522600a2SDimitry Andric   // since first column is used for the key instructions), then we also need
477522600a2SDimitry Andric   // to pass another input to indicate the column to be selected.
478522600a2SDimitry Andric 
479522600a2SDimitry Andric   ListInit *ColFields = InstrMapDesc.getColFields();
480522600a2SDimitry Andric   const std::vector<ListInit *> &ValueCols = InstrMapDesc.getValueCols();
481dd58ef01SDimitry Andric   OS << "// " << InstrMapDesc.getName() << "\nLLVM_READONLY\n";
482522600a2SDimitry Andric   OS << "int " << InstrMapDesc.getName() << "(uint16_t Opcode";
483522600a2SDimitry Andric   if (ValueCols.size() > 1) {
48485d8b2bbSDimitry Andric     for (Init *CF : ColFields->getValues()) {
48585d8b2bbSDimitry Andric       std::string ColName = CF->getAsUnquotedString();
486c0981da4SDimitry Andric       OS << ", enum " << ColName << " in" << ColName;
487522600a2SDimitry Andric     }
488c0981da4SDimitry Andric   }
489c0981da4SDimitry Andric   OS << ") {\n";
490522600a2SDimitry Andric 
491522600a2SDimitry Andric   // Emit map table.
492522600a2SDimitry Andric   unsigned TableSize = emitBinSearchTable(OS);
493522600a2SDimitry Andric 
494522600a2SDimitry Andric   // Emit rest of the function body.
495522600a2SDimitry Andric   emitMapFuncBody(OS, TableSize);
496522600a2SDimitry Andric }
497522600a2SDimitry Andric 
498522600a2SDimitry Andric //===----------------------------------------------------------------------===//
499522600a2SDimitry Andric // Emit enums for the column fields across all the instruction maps.
500522600a2SDimitry Andric //===----------------------------------------------------------------------===//
501522600a2SDimitry Andric 
emitEnums(raw_ostream & OS,RecordKeeper & Records)502522600a2SDimitry Andric static void emitEnums(raw_ostream &OS, RecordKeeper &Records) {
503522600a2SDimitry Andric 
504522600a2SDimitry Andric   std::vector<Record *> InstrMapVec;
505522600a2SDimitry Andric   InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");
506522600a2SDimitry Andric   std::map<std::string, std::vector<Init *>> ColFieldValueMap;
507522600a2SDimitry Andric 
508522600a2SDimitry Andric   // Iterate over all InstrMapping records and create a map between column
509522600a2SDimitry Andric   // fields and their possible values across all records.
51001095a5dSDimitry Andric   for (Record *CurMap : InstrMapVec) {
511522600a2SDimitry Andric     ListInit *ColFields;
512522600a2SDimitry Andric     ColFields = CurMap->getValueAsListInit("ColFields");
513522600a2SDimitry Andric     ListInit *List = CurMap->getValueAsListInit("ValueCols");
514522600a2SDimitry Andric     std::vector<ListInit *> ValueCols;
51585d8b2bbSDimitry Andric     unsigned ListSize = List->size();
516522600a2SDimitry Andric 
517522600a2SDimitry Andric     for (unsigned j = 0; j < ListSize; j++) {
5181d5ae102SDimitry Andric       auto *ListJ = cast<ListInit>(List->getElement(j));
519522600a2SDimitry Andric 
52085d8b2bbSDimitry Andric       if (ListJ->size() != ColFields->size())
521ac9a064cSDimitry Andric         PrintFatalError("Record `" + CurMap->getName() +
522ac9a064cSDimitry Andric                         "', field "
523ac9a064cSDimitry Andric                         "`ValueCols' entries don't match with the entries in "
524ac9a064cSDimitry Andric                         "'ColFields' !");
525522600a2SDimitry Andric       ValueCols.push_back(ListJ);
526522600a2SDimitry Andric     }
527522600a2SDimitry Andric 
52885d8b2bbSDimitry Andric     for (unsigned j = 0, endCF = ColFields->size(); j < endCF; j++) {
529522600a2SDimitry Andric       for (unsigned k = 0; k < ListSize; k++) {
530522600a2SDimitry Andric         std::string ColName = ColFields->getElement(j)->getAsUnquotedString();
531522600a2SDimitry Andric         ColFieldValueMap[ColName].push_back((ValueCols[k])->getElement(j));
532522600a2SDimitry Andric       }
533522600a2SDimitry Andric     }
534522600a2SDimitry Andric   }
535522600a2SDimitry Andric 
53601095a5dSDimitry Andric   for (auto &Entry : ColFieldValueMap) {
53701095a5dSDimitry Andric     std::vector<Init *> FieldValues = Entry.second;
538522600a2SDimitry Andric 
539522600a2SDimitry Andric     // Delete duplicate entries from ColFieldValueMap
5404a16efa3SDimitry Andric     for (unsigned i = 0; i < FieldValues.size() - 1; i++) {
541522600a2SDimitry Andric       Init *CurVal = FieldValues[i];
5424a16efa3SDimitry Andric       for (unsigned j = i + 1; j < FieldValues.size(); j++) {
543522600a2SDimitry Andric         if (CurVal == FieldValues[j]) {
544522600a2SDimitry Andric           FieldValues.erase(FieldValues.begin() + j);
545b915e9e0SDimitry Andric           --j;
546522600a2SDimitry Andric         }
547522600a2SDimitry Andric       }
548522600a2SDimitry Andric     }
549522600a2SDimitry Andric 
550522600a2SDimitry Andric     // Emit enumerated values for the column fields.
55101095a5dSDimitry Andric     OS << "enum " << Entry.first << " {\n";
5524a16efa3SDimitry Andric     for (unsigned i = 0, endFV = FieldValues.size(); i < endFV; i++) {
55301095a5dSDimitry Andric       OS << "\t" << Entry.first << "_" << FieldValues[i]->getAsUnquotedString();
5544a16efa3SDimitry Andric       if (i != endFV - 1)
555522600a2SDimitry Andric         OS << ",\n";
556522600a2SDimitry Andric       else
557522600a2SDimitry Andric         OS << "\n};\n\n";
558522600a2SDimitry Andric     }
559522600a2SDimitry Andric   }
560522600a2SDimitry Andric }
561522600a2SDimitry Andric 
562522600a2SDimitry Andric namespace llvm {
563522600a2SDimitry Andric //===----------------------------------------------------------------------===//
564522600a2SDimitry Andric // Parse 'InstrMapping' records and use the information to form relationship
565522600a2SDimitry Andric // between instructions. These relations are emitted as a tables along with the
566522600a2SDimitry Andric // functions to query them.
567522600a2SDimitry Andric //===----------------------------------------------------------------------===//
EmitMapTable(RecordKeeper & Records,raw_ostream & OS)568522600a2SDimitry Andric void EmitMapTable(RecordKeeper &Records, raw_ostream &OS) {
569522600a2SDimitry Andric   CodeGenTarget Target(Records);
570ca089b24SDimitry Andric   StringRef NameSpace = Target.getInstNamespace();
571522600a2SDimitry Andric   std::vector<Record *> InstrMapVec;
572522600a2SDimitry Andric   InstrMapVec = Records.getAllDerivedDefinitions("InstrMapping");
573522600a2SDimitry Andric 
5745a5ac124SDimitry Andric   if (InstrMapVec.empty())
575522600a2SDimitry Andric     return;
576522600a2SDimitry Andric 
577522600a2SDimitry Andric   OS << "#ifdef GET_INSTRMAP_INFO\n";
578522600a2SDimitry Andric   OS << "#undef GET_INSTRMAP_INFO\n";
579522600a2SDimitry Andric   OS << "namespace llvm {\n\n";
58071d5a254SDimitry Andric   OS << "namespace " << NameSpace << " {\n\n";
581522600a2SDimitry Andric 
582522600a2SDimitry Andric   // Emit coulumn field names and their values as enums.
583522600a2SDimitry Andric   emitEnums(OS, Records);
584522600a2SDimitry Andric 
585522600a2SDimitry Andric   // Iterate over all instruction mapping records and construct relationship
586522600a2SDimitry Andric   // maps based on the information specified there.
587522600a2SDimitry Andric   //
58801095a5dSDimitry Andric   for (Record *CurMap : InstrMapVec) {
58901095a5dSDimitry Andric     MapTableEmitter IMap(Target, Records, CurMap);
590522600a2SDimitry Andric 
591522600a2SDimitry Andric     // Build RowInstrMap to group instructions based on their values for
592522600a2SDimitry Andric     // RowFields. In the process, also collect key instructions into
593522600a2SDimitry Andric     // KeyInstrVec.
594522600a2SDimitry Andric     IMap.buildRowInstrMap();
595522600a2SDimitry Andric 
596522600a2SDimitry Andric     // Build MapTable to map key instructions with the corresponding column
597522600a2SDimitry Andric     // instructions.
598522600a2SDimitry Andric     IMap.buildMapTable();
599522600a2SDimitry Andric 
600522600a2SDimitry Andric     // Emit map tables and the functions to query them.
601522600a2SDimitry Andric     IMap.emitTablesWithFunc(OS);
602522600a2SDimitry Andric   }
6031d5ae102SDimitry Andric   OS << "} // end namespace " << NameSpace << "\n";
6041d5ae102SDimitry Andric   OS << "} // end namespace llvm\n";
605522600a2SDimitry Andric   OS << "#endif // GET_INSTRMAP_INFO\n\n";
606522600a2SDimitry Andric }
607522600a2SDimitry Andric 
608ac9a064cSDimitry Andric } // namespace llvm
609