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