1//===- MatchTable.h -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file contains the generic emitter for the GlobalISel Match Table
11/// system. This file only contains the code used to emit the table itself.
12///
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H
16#define LLVM_UTILS_TABLEGEN_COMMON_GLOBALISEL_MATCHTABLE_MATCHTABLE_H
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/DenseMap.h"
20#include "llvm/ADT/StringRef.h"
21#include <string>
22
23namespace llvm {
24class raw_ostream;
25class Record;
26namespace gi {
27class Matcher;
28class MatchTable;
29
30void emitEncodingMacrosDef(raw_ostream &OS);
31void emitEncodingMacrosUndef(raw_ostream &OS);
32
33std::string getNameForFeatureBitset(ArrayRef<const Record *> FeatureBitset,
34 int HwModeIdx);
35
36/// A record to be stored in a MatchTable.
37///
38/// This class represents any and all output that may be required to emit the
39/// MatchTable. Instances are most often configured to represent an opcode or
40/// value that will be emitted to the table with some formatting but it can also
41/// represent commas, comments, and other formatting instructions.
42struct MatchTableRecord {
43 enum RecordFlagsBits {
44 MTRF_None = 0x0,
45 /// Causes EmitStr to be formatted as comment when emitted.
46 MTRF_Comment = 0x1,
47 /// Causes the record value to be followed by a comma when emitted.
48 MTRF_CommaFollows = 0x2,
49 /// Causes the record value to be followed by a line break when emitted.
50 MTRF_LineBreakFollows = 0x4,
51 /// Indicates that the record defines a label and causes an additional
52 /// comment to be emitted containing the index of the label.
53 MTRF_Label = 0x8,
54 /// Causes the record to be emitted as the index of the label specified by
55 /// LabelID along with a comment indicating where that label is.
56 MTRF_JumpTarget = 0x10,
57 /// Causes the formatter to add a level of indentation before emitting the
58 /// record.
59 MTRF_Indent = 0x20,
60 /// Causes the formatter to remove a level of indentation after emitting the
61 /// record.
62 MTRF_Outdent = 0x40,
63 /// Causes the formatter to not use encoding macros to emit this multi-byte
64 /// value.
65 MTRF_PreEncoded = 0x80,
66 };
67
68 /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to
69 /// reference or define.
70 unsigned LabelID;
71 /// The string to emit. Depending on the MTRF_* flags it may be a comment, a
72 /// value, a label name.
73 std::string EmitStr;
74
75private:
76 /// The number of MatchTable elements described by this record. Comments are 0
77 /// while values are typically 1. Values >1 may occur when we need to emit
78 /// values that exceed the size of a MatchTable element.
79 unsigned NumElements;
80
81public:
82 /// A bitfield of RecordFlagsBits flags.
83 unsigned Flags;
84
85 MatchTableRecord(std::optional<unsigned> LabelID_, StringRef EmitStr,
86 unsigned NumElements, unsigned Flags)
87 : LabelID(LabelID_.value_or(u: ~0u)), EmitStr(EmitStr),
88 NumElements(NumElements), Flags(Flags) {
89 assert((!LabelID_ || LabelID != ~0u) &&
90 "This value is reserved for non-labels");
91 }
92 MatchTableRecord(const MatchTableRecord &Other) = default;
93 MatchTableRecord(MatchTableRecord &&Other) = default;
94
95 /// Useful if a Match Table Record gets optimized out
96 void turnIntoComment() {
97 Flags |= MTRF_Comment;
98 Flags &= ~MTRF_CommaFollows;
99 NumElements = 0;
100 }
101
102 void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
103 const MatchTable &Table) const;
104 unsigned size() const { return NumElements; }
105};
106
107/// Holds the contents of a generated MatchTable to enable formatting and the
108/// necessary index tracking needed to support GIM_Try.
109class MatchTable {
110 /// An unique identifier for the table. The generated table will be named
111 /// MatchTable${ID}.
112 unsigned ID;
113 /// The records that make up the table. Also includes comments describing the
114 /// values being emitted and line breaks to format it.
115 std::vector<MatchTableRecord> Contents;
116 /// The currently defined labels.
117 DenseMap<unsigned, unsigned> LabelMap;
118 /// Tracks the sum of MatchTableRecord::NumElements as the table is built.
119 unsigned CurrentSize = 0;
120 /// A unique identifier for a MatchTable label.
121 unsigned CurrentLabelID = 0;
122 /// Determines if the table should be instrumented for rule coverage tracking.
123 bool IsWithCoverage;
124 /// Whether this table is for the GISel combiner.
125 bool IsCombinerTable;
126
127public:
128 static MatchTableRecord LineBreak;
129 static MatchTableRecord Comment(StringRef Comment);
130 static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0);
131 static MatchTableRecord NamedValue(unsigned NumBytes, StringRef NamedValue);
132 static MatchTableRecord NamedValue(unsigned NumBytes, StringRef Namespace,
133 StringRef NamedValue);
134 static MatchTableRecord IntValue(unsigned NumBytes, int64_t IntValue);
135 static MatchTableRecord ULEB128Value(uint64_t IntValue);
136 static MatchTableRecord Label(unsigned LabelID);
137 static MatchTableRecord JumpTarget(unsigned LabelID);
138
139 MatchTable(bool WithCoverage, bool IsCombinerTable, unsigned ID = 0)
140 : ID(ID), IsWithCoverage(WithCoverage), IsCombinerTable(IsCombinerTable) {
141 }
142
143 bool isWithCoverage() const { return IsWithCoverage; }
144 bool isCombiner() const { return IsCombinerTable; }
145
146 void push_back(const MatchTableRecord &Value) {
147 if (Value.Flags & MatchTableRecord::MTRF_Label)
148 defineLabel(LabelID: Value.LabelID);
149 Contents.push_back(x: Value);
150 CurrentSize += Value.size();
151 }
152
153 unsigned allocateLabelID() { return CurrentLabelID++; }
154
155 void defineLabel(unsigned LabelID) {
156 LabelMap.try_emplace(Key: LabelID, Args&: CurrentSize);
157 }
158
159 unsigned getLabelIndex(unsigned LabelID) const {
160 const auto I = LabelMap.find(Val: LabelID);
161 assert(I != LabelMap.end() && "Use of undeclared label");
162 return I->second;
163 }
164
165 void emitUse(raw_ostream &OS) const;
166 void emitDeclaration(raw_ostream &OS) const;
167};
168
169inline MatchTable &operator<<(MatchTable &Table,
170 const MatchTableRecord &Value) {
171 Table.push_back(Value);
172 return Table;
173}
174
175} // namespace gi
176} // namespace llvm
177
178#endif
179