1*0fca6ea1SDimitry Andric //===- GlobalISelMatchTable.cpp -------------------------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric
9*0fca6ea1SDimitry Andric #include "GlobalISelMatchTable.h"
10*0fca6ea1SDimitry Andric #include "Common/CodeGenInstruction.h"
11*0fca6ea1SDimitry Andric #include "Common/CodeGenRegisters.h"
12*0fca6ea1SDimitry Andric #include "llvm/ADT/Statistic.h"
13*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h"
14*0fca6ea1SDimitry Andric #include "llvm/Support/LEB128.h"
15*0fca6ea1SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
16*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h"
17*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h"
18*0fca6ea1SDimitry Andric
19*0fca6ea1SDimitry Andric #define DEBUG_TYPE "gi-match-table"
20*0fca6ea1SDimitry Andric
21*0fca6ea1SDimitry Andric STATISTIC(NumPatternEmitted, "Number of patterns emitted");
22*0fca6ea1SDimitry Andric
23*0fca6ea1SDimitry Andric namespace llvm {
24*0fca6ea1SDimitry Andric namespace gi {
25*0fca6ea1SDimitry Andric
26*0fca6ea1SDimitry Andric namespace {
27*0fca6ea1SDimitry Andric
failUnsupported(const Twine & Reason)28*0fca6ea1SDimitry Andric Error failUnsupported(const Twine &Reason) {
29*0fca6ea1SDimitry Andric return make_error<StringError>(Reason, inconvertibleErrorCode());
30*0fca6ea1SDimitry Andric }
31*0fca6ea1SDimitry Andric
32*0fca6ea1SDimitry Andric /// Get the name of the enum value used to number the predicate function.
getEnumNameForPredicate(const TreePredicateFn & Predicate)33*0fca6ea1SDimitry Andric std::string getEnumNameForPredicate(const TreePredicateFn &Predicate) {
34*0fca6ea1SDimitry Andric if (Predicate.hasGISelPredicateCode())
35*0fca6ea1SDimitry Andric return "GICXXPred_MI_" + Predicate.getFnName();
36*0fca6ea1SDimitry Andric return "GICXXPred_" + Predicate.getImmTypeIdentifier().str() + "_" +
37*0fca6ea1SDimitry Andric Predicate.getFnName();
38*0fca6ea1SDimitry Andric }
39*0fca6ea1SDimitry Andric
getMatchOpcodeForImmPredicate(const TreePredicateFn & Predicate)40*0fca6ea1SDimitry Andric std::string getMatchOpcodeForImmPredicate(const TreePredicateFn &Predicate) {
41*0fca6ea1SDimitry Andric return "GIM_Check" + Predicate.getImmTypeIdentifier().str() + "ImmPredicate";
42*0fca6ea1SDimitry Andric }
43*0fca6ea1SDimitry Andric
44*0fca6ea1SDimitry Andric // GIMT_Encode2/4/8
45*0fca6ea1SDimitry Andric constexpr StringLiteral EncodeMacroName = "GIMT_Encode";
46*0fca6ea1SDimitry Andric
47*0fca6ea1SDimitry Andric } // namespace
48*0fca6ea1SDimitry Andric
49*0fca6ea1SDimitry Andric //===- Helpers ------------------------------------------------------------===//
50*0fca6ea1SDimitry Andric
emitEncodingMacrosDef(raw_ostream & OS)51*0fca6ea1SDimitry Andric void emitEncodingMacrosDef(raw_ostream &OS) {
52*0fca6ea1SDimitry Andric OS << "#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n"
53*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "2(Val)"
54*0fca6ea1SDimitry Andric << " uint8_t(Val), uint8_t((uint16_t)Val >> 8)\n"
55*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "4(Val)"
56*0fca6ea1SDimitry Andric << " uint8_t(Val), uint8_t((uint32_t)Val >> 8), "
57*0fca6ea1SDimitry Andric "uint8_t((uint32_t)Val >> 16), uint8_t((uint32_t)Val >> 24)\n"
58*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "8(Val)"
59*0fca6ea1SDimitry Andric << " uint8_t(Val), uint8_t((uint64_t)Val >> 8), "
60*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 16), uint8_t((uint64_t)Val >> 24), "
61*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 32), uint8_t((uint64_t)Val >> 40), "
62*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 48), uint8_t((uint64_t)Val >> 56)\n"
63*0fca6ea1SDimitry Andric << "#else\n"
64*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "2(Val)"
65*0fca6ea1SDimitry Andric << " uint8_t((uint16_t)Val >> 8), uint8_t(Val)\n"
66*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "4(Val)"
67*0fca6ea1SDimitry Andric << " uint8_t((uint32_t)Val >> 24), uint8_t((uint32_t)Val >> 16), "
68*0fca6ea1SDimitry Andric "uint8_t((uint32_t)Val >> 8), uint8_t(Val)\n"
69*0fca6ea1SDimitry Andric << "#define " << EncodeMacroName << "8(Val)"
70*0fca6ea1SDimitry Andric << " uint8_t((uint64_t)Val >> 56), uint8_t((uint64_t)Val >> 48), "
71*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 40), uint8_t((uint64_t)Val >> 32), "
72*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 24), uint8_t((uint64_t)Val >> 16), "
73*0fca6ea1SDimitry Andric "uint8_t((uint64_t)Val >> 8), uint8_t(Val)\n"
74*0fca6ea1SDimitry Andric << "#endif\n";
75*0fca6ea1SDimitry Andric }
76*0fca6ea1SDimitry Andric
emitEncodingMacrosUndef(raw_ostream & OS)77*0fca6ea1SDimitry Andric void emitEncodingMacrosUndef(raw_ostream &OS) {
78*0fca6ea1SDimitry Andric OS << "#undef " << EncodeMacroName << "2\n"
79*0fca6ea1SDimitry Andric << "#undef " << EncodeMacroName << "4\n"
80*0fca6ea1SDimitry Andric << "#undef " << EncodeMacroName << "8\n";
81*0fca6ea1SDimitry Andric }
82*0fca6ea1SDimitry Andric
getNameForFeatureBitset(const std::vector<Record * > & FeatureBitset,int HwModeIdx)83*0fca6ea1SDimitry Andric std::string getNameForFeatureBitset(const std::vector<Record *> &FeatureBitset,
84*0fca6ea1SDimitry Andric int HwModeIdx) {
85*0fca6ea1SDimitry Andric std::string Name = "GIFBS";
86*0fca6ea1SDimitry Andric for (const auto &Feature : FeatureBitset)
87*0fca6ea1SDimitry Andric Name += ("_" + Feature->getName()).str();
88*0fca6ea1SDimitry Andric if (HwModeIdx >= 0)
89*0fca6ea1SDimitry Andric Name += ("_HwMode" + std::to_string(HwModeIdx));
90*0fca6ea1SDimitry Andric return Name;
91*0fca6ea1SDimitry Andric }
92*0fca6ea1SDimitry Andric
93*0fca6ea1SDimitry Andric template <class GroupT>
94*0fca6ea1SDimitry Andric std::vector<Matcher *>
optimizeRules(ArrayRef<Matcher * > Rules,std::vector<std::unique_ptr<Matcher>> & MatcherStorage)95*0fca6ea1SDimitry Andric optimizeRules(ArrayRef<Matcher *> Rules,
96*0fca6ea1SDimitry Andric std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
97*0fca6ea1SDimitry Andric
98*0fca6ea1SDimitry Andric std::vector<Matcher *> OptRules;
99*0fca6ea1SDimitry Andric std::unique_ptr<GroupT> CurrentGroup = std::make_unique<GroupT>();
100*0fca6ea1SDimitry Andric assert(CurrentGroup->empty() && "Newly created group isn't empty!");
101*0fca6ea1SDimitry Andric unsigned NumGroups = 0;
102*0fca6ea1SDimitry Andric
103*0fca6ea1SDimitry Andric auto ProcessCurrentGroup = [&]() {
104*0fca6ea1SDimitry Andric if (CurrentGroup->empty())
105*0fca6ea1SDimitry Andric // An empty group is good to be reused:
106*0fca6ea1SDimitry Andric return;
107*0fca6ea1SDimitry Andric
108*0fca6ea1SDimitry Andric // If the group isn't large enough to provide any benefit, move all the
109*0fca6ea1SDimitry Andric // added rules out of it and make sure to re-create the group to properly
110*0fca6ea1SDimitry Andric // re-initialize it:
111*0fca6ea1SDimitry Andric if (CurrentGroup->size() < 2)
112*0fca6ea1SDimitry Andric append_range(OptRules, CurrentGroup->matchers());
113*0fca6ea1SDimitry Andric else {
114*0fca6ea1SDimitry Andric CurrentGroup->finalize();
115*0fca6ea1SDimitry Andric OptRules.push_back(CurrentGroup.get());
116*0fca6ea1SDimitry Andric MatcherStorage.emplace_back(std::move(CurrentGroup));
117*0fca6ea1SDimitry Andric ++NumGroups;
118*0fca6ea1SDimitry Andric }
119*0fca6ea1SDimitry Andric CurrentGroup = std::make_unique<GroupT>();
120*0fca6ea1SDimitry Andric };
121*0fca6ea1SDimitry Andric for (Matcher *Rule : Rules) {
122*0fca6ea1SDimitry Andric // Greedily add as many matchers as possible to the current group:
123*0fca6ea1SDimitry Andric if (CurrentGroup->addMatcher(*Rule))
124*0fca6ea1SDimitry Andric continue;
125*0fca6ea1SDimitry Andric
126*0fca6ea1SDimitry Andric ProcessCurrentGroup();
127*0fca6ea1SDimitry Andric assert(CurrentGroup->empty() && "A group wasn't properly re-initialized");
128*0fca6ea1SDimitry Andric
129*0fca6ea1SDimitry Andric // Try to add the pending matcher to a newly created empty group:
130*0fca6ea1SDimitry Andric if (!CurrentGroup->addMatcher(*Rule))
131*0fca6ea1SDimitry Andric // If we couldn't add the matcher to an empty group, that group type
132*0fca6ea1SDimitry Andric // doesn't support that kind of matchers at all, so just skip it:
133*0fca6ea1SDimitry Andric OptRules.push_back(Rule);
134*0fca6ea1SDimitry Andric }
135*0fca6ea1SDimitry Andric ProcessCurrentGroup();
136*0fca6ea1SDimitry Andric
137*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");
138*0fca6ea1SDimitry Andric (void)NumGroups;
139*0fca6ea1SDimitry Andric assert(CurrentGroup->empty() && "The last group wasn't properly processed");
140*0fca6ea1SDimitry Andric return OptRules;
141*0fca6ea1SDimitry Andric }
142*0fca6ea1SDimitry Andric
143*0fca6ea1SDimitry Andric template std::vector<Matcher *> optimizeRules<GroupMatcher>(
144*0fca6ea1SDimitry Andric ArrayRef<Matcher *> Rules,
145*0fca6ea1SDimitry Andric std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
146*0fca6ea1SDimitry Andric
147*0fca6ea1SDimitry Andric template std::vector<Matcher *> optimizeRules<SwitchMatcher>(
148*0fca6ea1SDimitry Andric ArrayRef<Matcher *> Rules,
149*0fca6ea1SDimitry Andric std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
150*0fca6ea1SDimitry Andric
getEncodedEmitStr(StringRef NamedValue,unsigned NumBytes)151*0fca6ea1SDimitry Andric static std::string getEncodedEmitStr(StringRef NamedValue, unsigned NumBytes) {
152*0fca6ea1SDimitry Andric if (NumBytes == 2 || NumBytes == 4 || NumBytes == 8)
153*0fca6ea1SDimitry Andric return (EncodeMacroName + Twine(NumBytes) + "(" + NamedValue + ")").str();
154*0fca6ea1SDimitry Andric llvm_unreachable("Unsupported number of bytes!");
155*0fca6ea1SDimitry Andric }
156*0fca6ea1SDimitry Andric
157*0fca6ea1SDimitry Andric //===- Global Data --------------------------------------------------------===//
158*0fca6ea1SDimitry Andric
159*0fca6ea1SDimitry Andric std::set<LLTCodeGen> KnownTypes;
160*0fca6ea1SDimitry Andric
161*0fca6ea1SDimitry Andric //===- MatchTableRecord ---------------------------------------------------===//
162*0fca6ea1SDimitry Andric
emit(raw_ostream & OS,bool LineBreakIsNextAfterThis,const MatchTable & Table) const163*0fca6ea1SDimitry Andric void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis,
164*0fca6ea1SDimitry Andric const MatchTable &Table) const {
165*0fca6ea1SDimitry Andric bool UseLineComment =
166*0fca6ea1SDimitry Andric LineBreakIsNextAfterThis || (Flags & MTRF_LineBreakFollows);
167*0fca6ea1SDimitry Andric if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows))
168*0fca6ea1SDimitry Andric UseLineComment = false;
169*0fca6ea1SDimitry Andric
170*0fca6ea1SDimitry Andric if (Flags & MTRF_Comment)
171*0fca6ea1SDimitry Andric OS << (UseLineComment ? "// " : "/*");
172*0fca6ea1SDimitry Andric
173*0fca6ea1SDimitry Andric if (NumElements > 1 && !(Flags & (MTRF_PreEncoded | MTRF_Comment)))
174*0fca6ea1SDimitry Andric OS << getEncodedEmitStr(EmitStr, NumElements);
175*0fca6ea1SDimitry Andric else
176*0fca6ea1SDimitry Andric OS << EmitStr;
177*0fca6ea1SDimitry Andric
178*0fca6ea1SDimitry Andric if (Flags & MTRF_Label)
179*0fca6ea1SDimitry Andric OS << ": @" << Table.getLabelIndex(LabelID);
180*0fca6ea1SDimitry Andric
181*0fca6ea1SDimitry Andric if ((Flags & MTRF_Comment) && !UseLineComment)
182*0fca6ea1SDimitry Andric OS << "*/";
183*0fca6ea1SDimitry Andric
184*0fca6ea1SDimitry Andric if (Flags & MTRF_JumpTarget) {
185*0fca6ea1SDimitry Andric if (Flags & MTRF_Comment)
186*0fca6ea1SDimitry Andric OS << " ";
187*0fca6ea1SDimitry Andric // TODO: Could encode this AOT to speed up build of generated file
188*0fca6ea1SDimitry Andric OS << getEncodedEmitStr(llvm::to_string(Table.getLabelIndex(LabelID)),
189*0fca6ea1SDimitry Andric NumElements);
190*0fca6ea1SDimitry Andric }
191*0fca6ea1SDimitry Andric
192*0fca6ea1SDimitry Andric if (Flags & MTRF_CommaFollows) {
193*0fca6ea1SDimitry Andric OS << ",";
194*0fca6ea1SDimitry Andric if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows))
195*0fca6ea1SDimitry Andric OS << " ";
196*0fca6ea1SDimitry Andric }
197*0fca6ea1SDimitry Andric
198*0fca6ea1SDimitry Andric if (Flags & MTRF_LineBreakFollows)
199*0fca6ea1SDimitry Andric OS << "\n";
200*0fca6ea1SDimitry Andric }
201*0fca6ea1SDimitry Andric
202*0fca6ea1SDimitry Andric //===- MatchTable ---------------------------------------------------------===//
203*0fca6ea1SDimitry Andric
204*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::LineBreak = {
205*0fca6ea1SDimitry Andric std::nullopt, "" /* Emit String */, 0 /* Elements */,
206*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_LineBreakFollows};
207*0fca6ea1SDimitry Andric
Comment(StringRef Comment)208*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::Comment(StringRef Comment) {
209*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, Comment, 0,
210*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_Comment);
211*0fca6ea1SDimitry Andric }
212*0fca6ea1SDimitry Andric
Opcode(StringRef Opcode,int IndentAdjust)213*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::Opcode(StringRef Opcode, int IndentAdjust) {
214*0fca6ea1SDimitry Andric unsigned ExtraFlags = 0;
215*0fca6ea1SDimitry Andric if (IndentAdjust > 0)
216*0fca6ea1SDimitry Andric ExtraFlags |= MatchTableRecord::MTRF_Indent;
217*0fca6ea1SDimitry Andric if (IndentAdjust < 0)
218*0fca6ea1SDimitry Andric ExtraFlags |= MatchTableRecord::MTRF_Outdent;
219*0fca6ea1SDimitry Andric
220*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, Opcode, 1,
221*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows | ExtraFlags);
222*0fca6ea1SDimitry Andric }
223*0fca6ea1SDimitry Andric
NamedValue(unsigned NumBytes,StringRef NamedValue)224*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::NamedValue(unsigned NumBytes,
225*0fca6ea1SDimitry Andric StringRef NamedValue) {
226*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
227*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows);
228*0fca6ea1SDimitry Andric }
229*0fca6ea1SDimitry Andric
NamedValue(unsigned NumBytes,StringRef NamedValue,int64_t RawValue)230*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef NamedValue,
231*0fca6ea1SDimitry Andric int64_t RawValue) {
232*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, NamedValue, NumBytes,
233*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows, RawValue);
234*0fca6ea1SDimitry Andric }
235*0fca6ea1SDimitry Andric
NamedValue(unsigned NumBytes,StringRef Namespace,StringRef NamedValue)236*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
237*0fca6ea1SDimitry Andric StringRef NamedValue) {
238*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
239*0fca6ea1SDimitry Andric NumBytes, MatchTableRecord::MTRF_CommaFollows);
240*0fca6ea1SDimitry Andric }
241*0fca6ea1SDimitry Andric
NamedValue(unsigned NumBytes,StringRef Namespace,StringRef NamedValue,int64_t RawValue)242*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::NamedValue(unsigned NumBytes, StringRef Namespace,
243*0fca6ea1SDimitry Andric StringRef NamedValue,
244*0fca6ea1SDimitry Andric int64_t RawValue) {
245*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, (Namespace + "::" + NamedValue).str(),
246*0fca6ea1SDimitry Andric NumBytes, MatchTableRecord::MTRF_CommaFollows,
247*0fca6ea1SDimitry Andric RawValue);
248*0fca6ea1SDimitry Andric }
249*0fca6ea1SDimitry Andric
IntValue(unsigned NumBytes,int64_t IntValue)250*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::IntValue(unsigned NumBytes, int64_t IntValue) {
251*0fca6ea1SDimitry Andric assert(isUIntN(NumBytes * 8, IntValue) || isIntN(NumBytes * 8, IntValue));
252*0fca6ea1SDimitry Andric auto Str = llvm::to_string(IntValue);
253*0fca6ea1SDimitry Andric if (NumBytes == 1 && IntValue < 0)
254*0fca6ea1SDimitry Andric Str = "uint8_t(" + Str + ")";
255*0fca6ea1SDimitry Andric // TODO: Could optimize this directly to save the compiler some work when
256*0fca6ea1SDimitry Andric // building the file
257*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, Str, NumBytes,
258*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows);
259*0fca6ea1SDimitry Andric }
260*0fca6ea1SDimitry Andric
ULEB128Value(uint64_t IntValue)261*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::ULEB128Value(uint64_t IntValue) {
262*0fca6ea1SDimitry Andric uint8_t Buffer[10];
263*0fca6ea1SDimitry Andric unsigned Len = encodeULEB128(IntValue, Buffer);
264*0fca6ea1SDimitry Andric
265*0fca6ea1SDimitry Andric // Simple case (most common)
266*0fca6ea1SDimitry Andric if (Len == 1) {
267*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, llvm::to_string((unsigned)Buffer[0]),
268*0fca6ea1SDimitry Andric 1, MatchTableRecord::MTRF_CommaFollows);
269*0fca6ea1SDimitry Andric }
270*0fca6ea1SDimitry Andric
271*0fca6ea1SDimitry Andric // Print it as, e.g. /* -123456 (*/, 0xC0, 0xBB, 0x78 /*)*/
272*0fca6ea1SDimitry Andric std::string Str;
273*0fca6ea1SDimitry Andric raw_string_ostream OS(Str);
274*0fca6ea1SDimitry Andric OS << "/* " << llvm::to_string(IntValue) << "(*/";
275*0fca6ea1SDimitry Andric for (unsigned K = 0; K < Len; ++K) {
276*0fca6ea1SDimitry Andric if (K)
277*0fca6ea1SDimitry Andric OS << ", ";
278*0fca6ea1SDimitry Andric OS << "0x" << llvm::toHex({Buffer[K]});
279*0fca6ea1SDimitry Andric }
280*0fca6ea1SDimitry Andric OS << "/*)*/";
281*0fca6ea1SDimitry Andric return MatchTableRecord(std::nullopt, Str, Len,
282*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows |
283*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_PreEncoded);
284*0fca6ea1SDimitry Andric }
285*0fca6ea1SDimitry Andric
Label(unsigned LabelID)286*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::Label(unsigned LabelID) {
287*0fca6ea1SDimitry Andric return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0,
288*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_Label |
289*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_Comment |
290*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_LineBreakFollows);
291*0fca6ea1SDimitry Andric }
292*0fca6ea1SDimitry Andric
JumpTarget(unsigned LabelID)293*0fca6ea1SDimitry Andric MatchTableRecord MatchTable::JumpTarget(unsigned LabelID) {
294*0fca6ea1SDimitry Andric return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 4,
295*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_JumpTarget |
296*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_Comment |
297*0fca6ea1SDimitry Andric MatchTableRecord::MTRF_CommaFollows);
298*0fca6ea1SDimitry Andric }
299*0fca6ea1SDimitry Andric
emitUse(raw_ostream & OS) const300*0fca6ea1SDimitry Andric void MatchTable::emitUse(raw_ostream &OS) const { OS << "MatchTable" << ID; }
301*0fca6ea1SDimitry Andric
emitDeclaration(raw_ostream & OS) const302*0fca6ea1SDimitry Andric void MatchTable::emitDeclaration(raw_ostream &OS) const {
303*0fca6ea1SDimitry Andric unsigned Indentation = 4;
304*0fca6ea1SDimitry Andric OS << " constexpr static uint8_t MatchTable" << ID << "[] = {";
305*0fca6ea1SDimitry Andric LineBreak.emit(OS, true, *this);
306*0fca6ea1SDimitry Andric OS << std::string(Indentation, ' ');
307*0fca6ea1SDimitry Andric
308*0fca6ea1SDimitry Andric for (auto I = Contents.begin(), E = Contents.end(); I != E; ++I) {
309*0fca6ea1SDimitry Andric bool LineBreakIsNext = false;
310*0fca6ea1SDimitry Andric const auto &NextI = std::next(I);
311*0fca6ea1SDimitry Andric
312*0fca6ea1SDimitry Andric if (NextI != E) {
313*0fca6ea1SDimitry Andric if (NextI->EmitStr == "" &&
314*0fca6ea1SDimitry Andric NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows)
315*0fca6ea1SDimitry Andric LineBreakIsNext = true;
316*0fca6ea1SDimitry Andric }
317*0fca6ea1SDimitry Andric
318*0fca6ea1SDimitry Andric if (I->Flags & MatchTableRecord::MTRF_Indent)
319*0fca6ea1SDimitry Andric Indentation += 2;
320*0fca6ea1SDimitry Andric
321*0fca6ea1SDimitry Andric I->emit(OS, LineBreakIsNext, *this);
322*0fca6ea1SDimitry Andric if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows)
323*0fca6ea1SDimitry Andric OS << std::string(Indentation, ' ');
324*0fca6ea1SDimitry Andric
325*0fca6ea1SDimitry Andric if (I->Flags & MatchTableRecord::MTRF_Outdent)
326*0fca6ea1SDimitry Andric Indentation -= 2;
327*0fca6ea1SDimitry Andric }
328*0fca6ea1SDimitry Andric OS << "}; // Size: " << CurrentSize << " bytes\n";
329*0fca6ea1SDimitry Andric }
330*0fca6ea1SDimitry Andric
buildTable(ArrayRef<Matcher * > Rules,bool WithCoverage,bool IsCombiner)331*0fca6ea1SDimitry Andric MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules, bool WithCoverage,
332*0fca6ea1SDimitry Andric bool IsCombiner) {
333*0fca6ea1SDimitry Andric MatchTable Table(WithCoverage, IsCombiner);
334*0fca6ea1SDimitry Andric for (Matcher *Rule : Rules)
335*0fca6ea1SDimitry Andric Rule->emit(Table);
336*0fca6ea1SDimitry Andric
337*0fca6ea1SDimitry Andric return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
338*0fca6ea1SDimitry Andric }
339*0fca6ea1SDimitry Andric
340*0fca6ea1SDimitry Andric //===- LLTCodeGen ---------------------------------------------------------===//
341*0fca6ea1SDimitry Andric
getCxxEnumValue() const342*0fca6ea1SDimitry Andric std::string LLTCodeGen::getCxxEnumValue() const {
343*0fca6ea1SDimitry Andric std::string Str;
344*0fca6ea1SDimitry Andric raw_string_ostream OS(Str);
345*0fca6ea1SDimitry Andric
346*0fca6ea1SDimitry Andric emitCxxEnumValue(OS);
347*0fca6ea1SDimitry Andric return Str;
348*0fca6ea1SDimitry Andric }
349*0fca6ea1SDimitry Andric
emitCxxEnumValue(raw_ostream & OS) const350*0fca6ea1SDimitry Andric void LLTCodeGen::emitCxxEnumValue(raw_ostream &OS) const {
351*0fca6ea1SDimitry Andric if (Ty.isScalar()) {
352*0fca6ea1SDimitry Andric OS << "GILLT_s" << Ty.getSizeInBits();
353*0fca6ea1SDimitry Andric return;
354*0fca6ea1SDimitry Andric }
355*0fca6ea1SDimitry Andric if (Ty.isVector()) {
356*0fca6ea1SDimitry Andric OS << (Ty.isScalable() ? "GILLT_nxv" : "GILLT_v")
357*0fca6ea1SDimitry Andric << Ty.getElementCount().getKnownMinValue() << "s"
358*0fca6ea1SDimitry Andric << Ty.getScalarSizeInBits();
359*0fca6ea1SDimitry Andric return;
360*0fca6ea1SDimitry Andric }
361*0fca6ea1SDimitry Andric if (Ty.isPointer()) {
362*0fca6ea1SDimitry Andric OS << "GILLT_p" << Ty.getAddressSpace();
363*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() > 0)
364*0fca6ea1SDimitry Andric OS << "s" << Ty.getSizeInBits();
365*0fca6ea1SDimitry Andric return;
366*0fca6ea1SDimitry Andric }
367*0fca6ea1SDimitry Andric llvm_unreachable("Unhandled LLT");
368*0fca6ea1SDimitry Andric }
369*0fca6ea1SDimitry Andric
emitCxxConstructorCall(raw_ostream & OS) const370*0fca6ea1SDimitry Andric void LLTCodeGen::emitCxxConstructorCall(raw_ostream &OS) const {
371*0fca6ea1SDimitry Andric if (Ty.isScalar()) {
372*0fca6ea1SDimitry Andric OS << "LLT::scalar(" << Ty.getSizeInBits() << ")";
373*0fca6ea1SDimitry Andric return;
374*0fca6ea1SDimitry Andric }
375*0fca6ea1SDimitry Andric if (Ty.isVector()) {
376*0fca6ea1SDimitry Andric OS << "LLT::vector("
377*0fca6ea1SDimitry Andric << (Ty.isScalable() ? "ElementCount::getScalable("
378*0fca6ea1SDimitry Andric : "ElementCount::getFixed(")
379*0fca6ea1SDimitry Andric << Ty.getElementCount().getKnownMinValue() << "), "
380*0fca6ea1SDimitry Andric << Ty.getScalarSizeInBits() << ")";
381*0fca6ea1SDimitry Andric return;
382*0fca6ea1SDimitry Andric }
383*0fca6ea1SDimitry Andric if (Ty.isPointer() && Ty.getSizeInBits() > 0) {
384*0fca6ea1SDimitry Andric OS << "LLT::pointer(" << Ty.getAddressSpace() << ", " << Ty.getSizeInBits()
385*0fca6ea1SDimitry Andric << ")";
386*0fca6ea1SDimitry Andric return;
387*0fca6ea1SDimitry Andric }
388*0fca6ea1SDimitry Andric llvm_unreachable("Unhandled LLT");
389*0fca6ea1SDimitry Andric }
390*0fca6ea1SDimitry Andric
391*0fca6ea1SDimitry Andric /// This ordering is used for std::unique() and llvm::sort(). There's no
392*0fca6ea1SDimitry Andric /// particular logic behind the order but either A < B or B < A must be
393*0fca6ea1SDimitry Andric /// true if A != B.
operator <(const LLTCodeGen & Other) const394*0fca6ea1SDimitry Andric bool LLTCodeGen::operator<(const LLTCodeGen &Other) const {
395*0fca6ea1SDimitry Andric if (Ty.isValid() != Other.Ty.isValid())
396*0fca6ea1SDimitry Andric return Ty.isValid() < Other.Ty.isValid();
397*0fca6ea1SDimitry Andric if (!Ty.isValid())
398*0fca6ea1SDimitry Andric return false;
399*0fca6ea1SDimitry Andric
400*0fca6ea1SDimitry Andric if (Ty.isVector() != Other.Ty.isVector())
401*0fca6ea1SDimitry Andric return Ty.isVector() < Other.Ty.isVector();
402*0fca6ea1SDimitry Andric if (Ty.isScalar() != Other.Ty.isScalar())
403*0fca6ea1SDimitry Andric return Ty.isScalar() < Other.Ty.isScalar();
404*0fca6ea1SDimitry Andric if (Ty.isPointer() != Other.Ty.isPointer())
405*0fca6ea1SDimitry Andric return Ty.isPointer() < Other.Ty.isPointer();
406*0fca6ea1SDimitry Andric
407*0fca6ea1SDimitry Andric if (Ty.isPointer() && Ty.getAddressSpace() != Other.Ty.getAddressSpace())
408*0fca6ea1SDimitry Andric return Ty.getAddressSpace() < Other.Ty.getAddressSpace();
409*0fca6ea1SDimitry Andric
410*0fca6ea1SDimitry Andric if (Ty.isVector() && Ty.getElementCount() != Other.Ty.getElementCount())
411*0fca6ea1SDimitry Andric return std::tuple(Ty.isScalable(),
412*0fca6ea1SDimitry Andric Ty.getElementCount().getKnownMinValue()) <
413*0fca6ea1SDimitry Andric std::tuple(Other.Ty.isScalable(),
414*0fca6ea1SDimitry Andric Other.Ty.getElementCount().getKnownMinValue());
415*0fca6ea1SDimitry Andric
416*0fca6ea1SDimitry Andric assert((!Ty.isVector() || Ty.isScalable() == Other.Ty.isScalable()) &&
417*0fca6ea1SDimitry Andric "Unexpected mismatch of scalable property");
418*0fca6ea1SDimitry Andric return Ty.isVector()
419*0fca6ea1SDimitry Andric ? std::tuple(Ty.isScalable(),
420*0fca6ea1SDimitry Andric Ty.getSizeInBits().getKnownMinValue()) <
421*0fca6ea1SDimitry Andric std::tuple(Other.Ty.isScalable(),
422*0fca6ea1SDimitry Andric Other.Ty.getSizeInBits().getKnownMinValue())
423*0fca6ea1SDimitry Andric : Ty.getSizeInBits().getFixedValue() <
424*0fca6ea1SDimitry Andric Other.Ty.getSizeInBits().getFixedValue();
425*0fca6ea1SDimitry Andric }
426*0fca6ea1SDimitry Andric
427*0fca6ea1SDimitry Andric //===- LLTCodeGen Helpers -------------------------------------------------===//
428*0fca6ea1SDimitry Andric
MVTToLLT(MVT::SimpleValueType SVT)429*0fca6ea1SDimitry Andric std::optional<LLTCodeGen> MVTToLLT(MVT::SimpleValueType SVT) {
430*0fca6ea1SDimitry Andric MVT VT(SVT);
431*0fca6ea1SDimitry Andric
432*0fca6ea1SDimitry Andric if (VT.isVector() && !VT.getVectorElementCount().isScalar())
433*0fca6ea1SDimitry Andric return LLTCodeGen(
434*0fca6ea1SDimitry Andric LLT::vector(VT.getVectorElementCount(), VT.getScalarSizeInBits()));
435*0fca6ea1SDimitry Andric
436*0fca6ea1SDimitry Andric if (VT.isInteger() || VT.isFloatingPoint())
437*0fca6ea1SDimitry Andric return LLTCodeGen(LLT::scalar(VT.getSizeInBits()));
438*0fca6ea1SDimitry Andric
439*0fca6ea1SDimitry Andric return std::nullopt;
440*0fca6ea1SDimitry Andric }
441*0fca6ea1SDimitry Andric
442*0fca6ea1SDimitry Andric //===- Matcher ------------------------------------------------------------===//
443*0fca6ea1SDimitry Andric
optimize()444*0fca6ea1SDimitry Andric void Matcher::optimize() {}
445*0fca6ea1SDimitry Andric
~Matcher()446*0fca6ea1SDimitry Andric Matcher::~Matcher() {}
447*0fca6ea1SDimitry Andric
448*0fca6ea1SDimitry Andric //===- GroupMatcher -------------------------------------------------------===//
449*0fca6ea1SDimitry Andric
candidateConditionMatches(const PredicateMatcher & Predicate) const450*0fca6ea1SDimitry Andric bool GroupMatcher::candidateConditionMatches(
451*0fca6ea1SDimitry Andric const PredicateMatcher &Predicate) const {
452*0fca6ea1SDimitry Andric
453*0fca6ea1SDimitry Andric if (empty()) {
454*0fca6ea1SDimitry Andric // Sharing predicates for nested instructions is not supported yet as we
455*0fca6ea1SDimitry Andric // currently don't hoist the GIM_RecordInsn's properly, therefore we can
456*0fca6ea1SDimitry Andric // only work on the original root instruction (InsnVarID == 0):
457*0fca6ea1SDimitry Andric if (Predicate.getInsnVarID() != 0)
458*0fca6ea1SDimitry Andric return false;
459*0fca6ea1SDimitry Andric // ... otherwise an empty group can handle any predicate with no specific
460*0fca6ea1SDimitry Andric // requirements:
461*0fca6ea1SDimitry Andric return true;
462*0fca6ea1SDimitry Andric }
463*0fca6ea1SDimitry Andric
464*0fca6ea1SDimitry Andric const Matcher &Representative = **Matchers.begin();
465*0fca6ea1SDimitry Andric const auto &RepresentativeCondition = Representative.getFirstCondition();
466*0fca6ea1SDimitry Andric // ... if not empty, the group can only accomodate matchers with the exact
467*0fca6ea1SDimitry Andric // same first condition:
468*0fca6ea1SDimitry Andric return Predicate.isIdentical(RepresentativeCondition);
469*0fca6ea1SDimitry Andric }
470*0fca6ea1SDimitry Andric
addMatcher(Matcher & Candidate)471*0fca6ea1SDimitry Andric bool GroupMatcher::addMatcher(Matcher &Candidate) {
472*0fca6ea1SDimitry Andric if (!Candidate.hasFirstCondition())
473*0fca6ea1SDimitry Andric return false;
474*0fca6ea1SDimitry Andric
475*0fca6ea1SDimitry Andric const PredicateMatcher &Predicate = Candidate.getFirstCondition();
476*0fca6ea1SDimitry Andric if (!candidateConditionMatches(Predicate))
477*0fca6ea1SDimitry Andric return false;
478*0fca6ea1SDimitry Andric
479*0fca6ea1SDimitry Andric Matchers.push_back(&Candidate);
480*0fca6ea1SDimitry Andric return true;
481*0fca6ea1SDimitry Andric }
482*0fca6ea1SDimitry Andric
finalize()483*0fca6ea1SDimitry Andric void GroupMatcher::finalize() {
484*0fca6ea1SDimitry Andric assert(Conditions.empty() && "Already finalized?");
485*0fca6ea1SDimitry Andric if (empty())
486*0fca6ea1SDimitry Andric return;
487*0fca6ea1SDimitry Andric
488*0fca6ea1SDimitry Andric Matcher &FirstRule = **Matchers.begin();
489*0fca6ea1SDimitry Andric for (;;) {
490*0fca6ea1SDimitry Andric // All the checks are expected to succeed during the first iteration:
491*0fca6ea1SDimitry Andric for (const auto &Rule : Matchers)
492*0fca6ea1SDimitry Andric if (!Rule->hasFirstCondition())
493*0fca6ea1SDimitry Andric return;
494*0fca6ea1SDimitry Andric const auto &FirstCondition = FirstRule.getFirstCondition();
495*0fca6ea1SDimitry Andric for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
496*0fca6ea1SDimitry Andric if (!Matchers[I]->getFirstCondition().isIdentical(FirstCondition))
497*0fca6ea1SDimitry Andric return;
498*0fca6ea1SDimitry Andric
499*0fca6ea1SDimitry Andric Conditions.push_back(FirstRule.popFirstCondition());
500*0fca6ea1SDimitry Andric for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
501*0fca6ea1SDimitry Andric Matchers[I]->popFirstCondition();
502*0fca6ea1SDimitry Andric }
503*0fca6ea1SDimitry Andric }
504*0fca6ea1SDimitry Andric
emit(MatchTable & Table)505*0fca6ea1SDimitry Andric void GroupMatcher::emit(MatchTable &Table) {
506*0fca6ea1SDimitry Andric unsigned LabelID = ~0U;
507*0fca6ea1SDimitry Andric if (!Conditions.empty()) {
508*0fca6ea1SDimitry Andric LabelID = Table.allocateLabelID();
509*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_Try", +1)
510*0fca6ea1SDimitry Andric << MatchTable::Comment("On fail goto")
511*0fca6ea1SDimitry Andric << MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak;
512*0fca6ea1SDimitry Andric }
513*0fca6ea1SDimitry Andric for (auto &Condition : Conditions)
514*0fca6ea1SDimitry Andric Condition->emitPredicateOpcodes(
515*0fca6ea1SDimitry Andric Table, *static_cast<RuleMatcher *>(*Matchers.begin()));
516*0fca6ea1SDimitry Andric
517*0fca6ea1SDimitry Andric for (const auto &M : Matchers)
518*0fca6ea1SDimitry Andric M->emit(Table);
519*0fca6ea1SDimitry Andric
520*0fca6ea1SDimitry Andric // Exit the group
521*0fca6ea1SDimitry Andric if (!Conditions.empty())
522*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak
523*0fca6ea1SDimitry Andric << MatchTable::Label(LabelID);
524*0fca6ea1SDimitry Andric }
525*0fca6ea1SDimitry Andric
optimize()526*0fca6ea1SDimitry Andric void GroupMatcher::optimize() {
527*0fca6ea1SDimitry Andric // Make sure we only sort by a specific predicate within a range of rules that
528*0fca6ea1SDimitry Andric // all have that predicate checked against a specific value (not a wildcard):
529*0fca6ea1SDimitry Andric auto F = Matchers.begin();
530*0fca6ea1SDimitry Andric auto T = F;
531*0fca6ea1SDimitry Andric auto E = Matchers.end();
532*0fca6ea1SDimitry Andric while (T != E) {
533*0fca6ea1SDimitry Andric while (T != E) {
534*0fca6ea1SDimitry Andric auto *R = static_cast<RuleMatcher *>(*T);
535*0fca6ea1SDimitry Andric if (!R->getFirstConditionAsRootType().get().isValid())
536*0fca6ea1SDimitry Andric break;
537*0fca6ea1SDimitry Andric ++T;
538*0fca6ea1SDimitry Andric }
539*0fca6ea1SDimitry Andric std::stable_sort(F, T, [](Matcher *A, Matcher *B) {
540*0fca6ea1SDimitry Andric auto *L = static_cast<RuleMatcher *>(A);
541*0fca6ea1SDimitry Andric auto *R = static_cast<RuleMatcher *>(B);
542*0fca6ea1SDimitry Andric return L->getFirstConditionAsRootType() <
543*0fca6ea1SDimitry Andric R->getFirstConditionAsRootType();
544*0fca6ea1SDimitry Andric });
545*0fca6ea1SDimitry Andric if (T != E)
546*0fca6ea1SDimitry Andric F = ++T;
547*0fca6ea1SDimitry Andric }
548*0fca6ea1SDimitry Andric Matchers = optimizeRules<GroupMatcher>(Matchers, MatcherStorage);
549*0fca6ea1SDimitry Andric Matchers = optimizeRules<SwitchMatcher>(Matchers, MatcherStorage);
550*0fca6ea1SDimitry Andric }
551*0fca6ea1SDimitry Andric
552*0fca6ea1SDimitry Andric //===- SwitchMatcher ------------------------------------------------------===//
553*0fca6ea1SDimitry Andric
isSupportedPredicateType(const PredicateMatcher & P)554*0fca6ea1SDimitry Andric bool SwitchMatcher::isSupportedPredicateType(const PredicateMatcher &P) {
555*0fca6ea1SDimitry Andric return isa<InstructionOpcodeMatcher>(P) || isa<LLTOperandMatcher>(P);
556*0fca6ea1SDimitry Andric }
557*0fca6ea1SDimitry Andric
candidateConditionMatches(const PredicateMatcher & Predicate) const558*0fca6ea1SDimitry Andric bool SwitchMatcher::candidateConditionMatches(
559*0fca6ea1SDimitry Andric const PredicateMatcher &Predicate) const {
560*0fca6ea1SDimitry Andric
561*0fca6ea1SDimitry Andric if (empty()) {
562*0fca6ea1SDimitry Andric // Sharing predicates for nested instructions is not supported yet as we
563*0fca6ea1SDimitry Andric // currently don't hoist the GIM_RecordInsn's properly, therefore we can
564*0fca6ea1SDimitry Andric // only work on the original root instruction (InsnVarID == 0):
565*0fca6ea1SDimitry Andric if (Predicate.getInsnVarID() != 0)
566*0fca6ea1SDimitry Andric return false;
567*0fca6ea1SDimitry Andric // ... while an attempt to add even a root matcher to an empty SwitchMatcher
568*0fca6ea1SDimitry Andric // could fail as not all the types of conditions are supported:
569*0fca6ea1SDimitry Andric if (!isSupportedPredicateType(Predicate))
570*0fca6ea1SDimitry Andric return false;
571*0fca6ea1SDimitry Andric // ... or the condition might not have a proper implementation of
572*0fca6ea1SDimitry Andric // getValue() / isIdenticalDownToValue() yet:
573*0fca6ea1SDimitry Andric if (!Predicate.hasValue())
574*0fca6ea1SDimitry Andric return false;
575*0fca6ea1SDimitry Andric // ... otherwise an empty Switch can accomodate the condition with no
576*0fca6ea1SDimitry Andric // further requirements:
577*0fca6ea1SDimitry Andric return true;
578*0fca6ea1SDimitry Andric }
579*0fca6ea1SDimitry Andric
580*0fca6ea1SDimitry Andric const Matcher &CaseRepresentative = **Matchers.begin();
581*0fca6ea1SDimitry Andric const auto &RepresentativeCondition = CaseRepresentative.getFirstCondition();
582*0fca6ea1SDimitry Andric // Switch-cases must share the same kind of condition and path to the value it
583*0fca6ea1SDimitry Andric // checks:
584*0fca6ea1SDimitry Andric if (!Predicate.isIdenticalDownToValue(RepresentativeCondition))
585*0fca6ea1SDimitry Andric return false;
586*0fca6ea1SDimitry Andric
587*0fca6ea1SDimitry Andric const auto Value = Predicate.getValue();
588*0fca6ea1SDimitry Andric // ... but be unique with respect to the actual value they check:
589*0fca6ea1SDimitry Andric return Values.count(Value) == 0;
590*0fca6ea1SDimitry Andric }
591*0fca6ea1SDimitry Andric
addMatcher(Matcher & Candidate)592*0fca6ea1SDimitry Andric bool SwitchMatcher::addMatcher(Matcher &Candidate) {
593*0fca6ea1SDimitry Andric if (!Candidate.hasFirstCondition())
594*0fca6ea1SDimitry Andric return false;
595*0fca6ea1SDimitry Andric
596*0fca6ea1SDimitry Andric const PredicateMatcher &Predicate = Candidate.getFirstCondition();
597*0fca6ea1SDimitry Andric if (!candidateConditionMatches(Predicate))
598*0fca6ea1SDimitry Andric return false;
599*0fca6ea1SDimitry Andric const auto Value = Predicate.getValue();
600*0fca6ea1SDimitry Andric Values.insert(Value);
601*0fca6ea1SDimitry Andric
602*0fca6ea1SDimitry Andric Matchers.push_back(&Candidate);
603*0fca6ea1SDimitry Andric return true;
604*0fca6ea1SDimitry Andric }
605*0fca6ea1SDimitry Andric
finalize()606*0fca6ea1SDimitry Andric void SwitchMatcher::finalize() {
607*0fca6ea1SDimitry Andric assert(Condition == nullptr && "Already finalized");
608*0fca6ea1SDimitry Andric assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
609*0fca6ea1SDimitry Andric if (empty())
610*0fca6ea1SDimitry Andric return;
611*0fca6ea1SDimitry Andric
612*0fca6ea1SDimitry Andric llvm::stable_sort(Matchers, [](const Matcher *L, const Matcher *R) {
613*0fca6ea1SDimitry Andric return L->getFirstCondition().getValue() <
614*0fca6ea1SDimitry Andric R->getFirstCondition().getValue();
615*0fca6ea1SDimitry Andric });
616*0fca6ea1SDimitry Andric Condition = Matchers[0]->popFirstCondition();
617*0fca6ea1SDimitry Andric for (unsigned I = 1, E = Values.size(); I < E; ++I)
618*0fca6ea1SDimitry Andric Matchers[I]->popFirstCondition();
619*0fca6ea1SDimitry Andric }
620*0fca6ea1SDimitry Andric
emitPredicateSpecificOpcodes(const PredicateMatcher & P,MatchTable & Table)621*0fca6ea1SDimitry Andric void SwitchMatcher::emitPredicateSpecificOpcodes(const PredicateMatcher &P,
622*0fca6ea1SDimitry Andric MatchTable &Table) {
623*0fca6ea1SDimitry Andric assert(isSupportedPredicateType(P) && "Predicate type is not supported");
624*0fca6ea1SDimitry Andric
625*0fca6ea1SDimitry Andric if (const auto *Condition = dyn_cast<InstructionOpcodeMatcher>(&P)) {
626*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_SwitchOpcode") << MatchTable::Comment("MI")
627*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(Condition->getInsnVarID());
628*0fca6ea1SDimitry Andric return;
629*0fca6ea1SDimitry Andric }
630*0fca6ea1SDimitry Andric if (const auto *Condition = dyn_cast<LLTOperandMatcher>(&P)) {
631*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_SwitchType") << MatchTable::Comment("MI")
632*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(Condition->getInsnVarID())
633*0fca6ea1SDimitry Andric << MatchTable::Comment("Op")
634*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(Condition->getOpIdx());
635*0fca6ea1SDimitry Andric return;
636*0fca6ea1SDimitry Andric }
637*0fca6ea1SDimitry Andric
638*0fca6ea1SDimitry Andric llvm_unreachable("emitPredicateSpecificOpcodes is broken: can not handle a "
639*0fca6ea1SDimitry Andric "predicate type that is claimed to be supported");
640*0fca6ea1SDimitry Andric }
641*0fca6ea1SDimitry Andric
emit(MatchTable & Table)642*0fca6ea1SDimitry Andric void SwitchMatcher::emit(MatchTable &Table) {
643*0fca6ea1SDimitry Andric assert(Values.size() == Matchers.size() && "Broken SwitchMatcher");
644*0fca6ea1SDimitry Andric if (empty())
645*0fca6ea1SDimitry Andric return;
646*0fca6ea1SDimitry Andric assert(Condition != nullptr &&
647*0fca6ea1SDimitry Andric "Broken SwitchMatcher, hasn't been finalized?");
648*0fca6ea1SDimitry Andric
649*0fca6ea1SDimitry Andric std::vector<unsigned> LabelIDs(Values.size());
650*0fca6ea1SDimitry Andric std::generate(LabelIDs.begin(), LabelIDs.end(),
651*0fca6ea1SDimitry Andric [&Table]() { return Table.allocateLabelID(); });
652*0fca6ea1SDimitry Andric const unsigned Default = Table.allocateLabelID();
653*0fca6ea1SDimitry Andric
654*0fca6ea1SDimitry Andric const int64_t LowerBound = Values.begin()->getRawValue();
655*0fca6ea1SDimitry Andric const int64_t UpperBound = Values.rbegin()->getRawValue() + 1;
656*0fca6ea1SDimitry Andric
657*0fca6ea1SDimitry Andric emitPredicateSpecificOpcodes(*Condition, Table);
658*0fca6ea1SDimitry Andric
659*0fca6ea1SDimitry Andric Table << MatchTable::Comment("[") << MatchTable::IntValue(2, LowerBound)
660*0fca6ea1SDimitry Andric << MatchTable::IntValue(2, UpperBound) << MatchTable::Comment(")")
661*0fca6ea1SDimitry Andric << MatchTable::Comment("default:") << MatchTable::JumpTarget(Default);
662*0fca6ea1SDimitry Andric
663*0fca6ea1SDimitry Andric int64_t J = LowerBound;
664*0fca6ea1SDimitry Andric auto VI = Values.begin();
665*0fca6ea1SDimitry Andric for (unsigned I = 0, E = Values.size(); I < E; ++I) {
666*0fca6ea1SDimitry Andric auto V = *VI++;
667*0fca6ea1SDimitry Andric while (J++ < V.getRawValue())
668*0fca6ea1SDimitry Andric Table << MatchTable::IntValue(4, 0);
669*0fca6ea1SDimitry Andric V.turnIntoComment();
670*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak << V << MatchTable::JumpTarget(LabelIDs[I]);
671*0fca6ea1SDimitry Andric }
672*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
673*0fca6ea1SDimitry Andric
674*0fca6ea1SDimitry Andric for (unsigned I = 0, E = Values.size(); I < E; ++I) {
675*0fca6ea1SDimitry Andric Table << MatchTable::Label(LabelIDs[I]);
676*0fca6ea1SDimitry Andric Matchers[I]->emit(Table);
677*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
678*0fca6ea1SDimitry Andric }
679*0fca6ea1SDimitry Andric Table << MatchTable::Label(Default);
680*0fca6ea1SDimitry Andric }
681*0fca6ea1SDimitry Andric
682*0fca6ea1SDimitry Andric //===- RuleMatcher --------------------------------------------------------===//
683*0fca6ea1SDimitry Andric
684*0fca6ea1SDimitry Andric uint64_t RuleMatcher::NextRuleID = 0;
685*0fca6ea1SDimitry Andric
getOpcode() const686*0fca6ea1SDimitry Andric StringRef RuleMatcher::getOpcode() const {
687*0fca6ea1SDimitry Andric return Matchers.front()->getOpcode();
688*0fca6ea1SDimitry Andric }
689*0fca6ea1SDimitry Andric
getNumOperands() const690*0fca6ea1SDimitry Andric unsigned RuleMatcher::getNumOperands() const {
691*0fca6ea1SDimitry Andric return Matchers.front()->getNumOperands();
692*0fca6ea1SDimitry Andric }
693*0fca6ea1SDimitry Andric
getFirstConditionAsRootType()694*0fca6ea1SDimitry Andric LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {
695*0fca6ea1SDimitry Andric InstructionMatcher &InsnMatcher = *Matchers.front();
696*0fca6ea1SDimitry Andric if (!InsnMatcher.predicates_empty())
697*0fca6ea1SDimitry Andric if (const auto *TM =
698*0fca6ea1SDimitry Andric dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))
699*0fca6ea1SDimitry Andric if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
700*0fca6ea1SDimitry Andric return TM->getTy();
701*0fca6ea1SDimitry Andric return {};
702*0fca6ea1SDimitry Andric }
703*0fca6ea1SDimitry Andric
optimize()704*0fca6ea1SDimitry Andric void RuleMatcher::optimize() {
705*0fca6ea1SDimitry Andric for (auto &Item : InsnVariableIDs) {
706*0fca6ea1SDimitry Andric InstructionMatcher &InsnMatcher = *Item.first;
707*0fca6ea1SDimitry Andric for (auto &OM : InsnMatcher.operands()) {
708*0fca6ea1SDimitry Andric // Complex Patterns are usually expensive and they relatively rarely fail
709*0fca6ea1SDimitry Andric // on their own: more often we end up throwing away all the work done by a
710*0fca6ea1SDimitry Andric // matching part of a complex pattern because some other part of the
711*0fca6ea1SDimitry Andric // enclosing pattern didn't match. All of this makes it beneficial to
712*0fca6ea1SDimitry Andric // delay complex patterns until the very end of the rule matching,
713*0fca6ea1SDimitry Andric // especially for targets having lots of complex patterns.
714*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
715*0fca6ea1SDimitry Andric if (isa<ComplexPatternOperandMatcher>(OP))
716*0fca6ea1SDimitry Andric EpilogueMatchers.emplace_back(std::move(OP));
717*0fca6ea1SDimitry Andric OM->eraseNullPredicates();
718*0fca6ea1SDimitry Andric }
719*0fca6ea1SDimitry Andric InsnMatcher.optimize();
720*0fca6ea1SDimitry Andric }
721*0fca6ea1SDimitry Andric llvm::sort(EpilogueMatchers, [](const std::unique_ptr<PredicateMatcher> &L,
722*0fca6ea1SDimitry Andric const std::unique_ptr<PredicateMatcher> &R) {
723*0fca6ea1SDimitry Andric return std::tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) <
724*0fca6ea1SDimitry Andric std::tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx());
725*0fca6ea1SDimitry Andric });
726*0fca6ea1SDimitry Andric
727*0fca6ea1SDimitry Andric // Deduplicate EraseInst actions, and if an EraseInst erases the root, place
728*0fca6ea1SDimitry Andric // it at the end to favor generation of GIR_EraseRootFromParent_Done
729*0fca6ea1SDimitry Andric DenseSet<unsigned> AlreadySeenEraseInsts;
730*0fca6ea1SDimitry Andric auto EraseRootIt = Actions.end();
731*0fca6ea1SDimitry Andric auto It = Actions.begin();
732*0fca6ea1SDimitry Andric while (It != Actions.end()) {
733*0fca6ea1SDimitry Andric if (const auto *EI = dyn_cast<EraseInstAction>(It->get())) {
734*0fca6ea1SDimitry Andric unsigned InstID = EI->getInsnID();
735*0fca6ea1SDimitry Andric if (!AlreadySeenEraseInsts.insert(InstID).second) {
736*0fca6ea1SDimitry Andric It = Actions.erase(It);
737*0fca6ea1SDimitry Andric continue;
738*0fca6ea1SDimitry Andric }
739*0fca6ea1SDimitry Andric
740*0fca6ea1SDimitry Andric if (InstID == 0)
741*0fca6ea1SDimitry Andric EraseRootIt = It;
742*0fca6ea1SDimitry Andric }
743*0fca6ea1SDimitry Andric
744*0fca6ea1SDimitry Andric ++It;
745*0fca6ea1SDimitry Andric }
746*0fca6ea1SDimitry Andric
747*0fca6ea1SDimitry Andric if (EraseRootIt != Actions.end())
748*0fca6ea1SDimitry Andric Actions.splice(Actions.end(), Actions, EraseRootIt);
749*0fca6ea1SDimitry Andric }
750*0fca6ea1SDimitry Andric
hasFirstCondition() const751*0fca6ea1SDimitry Andric bool RuleMatcher::hasFirstCondition() const {
752*0fca6ea1SDimitry Andric if (insnmatchers_empty())
753*0fca6ea1SDimitry Andric return false;
754*0fca6ea1SDimitry Andric InstructionMatcher &Matcher = insnmatchers_front();
755*0fca6ea1SDimitry Andric if (!Matcher.predicates_empty())
756*0fca6ea1SDimitry Andric return true;
757*0fca6ea1SDimitry Andric for (auto &OM : Matcher.operands())
758*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
759*0fca6ea1SDimitry Andric if (!isa<InstructionOperandMatcher>(OP))
760*0fca6ea1SDimitry Andric return true;
761*0fca6ea1SDimitry Andric return false;
762*0fca6ea1SDimitry Andric }
763*0fca6ea1SDimitry Andric
getFirstCondition() const764*0fca6ea1SDimitry Andric const PredicateMatcher &RuleMatcher::getFirstCondition() const {
765*0fca6ea1SDimitry Andric assert(!insnmatchers_empty() &&
766*0fca6ea1SDimitry Andric "Trying to get a condition from an empty RuleMatcher");
767*0fca6ea1SDimitry Andric
768*0fca6ea1SDimitry Andric InstructionMatcher &Matcher = insnmatchers_front();
769*0fca6ea1SDimitry Andric if (!Matcher.predicates_empty())
770*0fca6ea1SDimitry Andric return **Matcher.predicates_begin();
771*0fca6ea1SDimitry Andric // If there is no more predicate on the instruction itself, look at its
772*0fca6ea1SDimitry Andric // operands.
773*0fca6ea1SDimitry Andric for (auto &OM : Matcher.operands())
774*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
775*0fca6ea1SDimitry Andric if (!isa<InstructionOperandMatcher>(OP))
776*0fca6ea1SDimitry Andric return *OP;
777*0fca6ea1SDimitry Andric
778*0fca6ea1SDimitry Andric llvm_unreachable("Trying to get a condition from an InstructionMatcher with "
779*0fca6ea1SDimitry Andric "no conditions");
780*0fca6ea1SDimitry Andric }
781*0fca6ea1SDimitry Andric
popFirstCondition()782*0fca6ea1SDimitry Andric std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() {
783*0fca6ea1SDimitry Andric assert(!insnmatchers_empty() &&
784*0fca6ea1SDimitry Andric "Trying to pop a condition from an empty RuleMatcher");
785*0fca6ea1SDimitry Andric
786*0fca6ea1SDimitry Andric InstructionMatcher &Matcher = insnmatchers_front();
787*0fca6ea1SDimitry Andric if (!Matcher.predicates_empty())
788*0fca6ea1SDimitry Andric return Matcher.predicates_pop_front();
789*0fca6ea1SDimitry Andric // If there is no more predicate on the instruction itself, look at its
790*0fca6ea1SDimitry Andric // operands.
791*0fca6ea1SDimitry Andric for (auto &OM : Matcher.operands())
792*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
793*0fca6ea1SDimitry Andric if (!isa<InstructionOperandMatcher>(OP)) {
794*0fca6ea1SDimitry Andric std::unique_ptr<PredicateMatcher> Result = std::move(OP);
795*0fca6ea1SDimitry Andric OM->eraseNullPredicates();
796*0fca6ea1SDimitry Andric return Result;
797*0fca6ea1SDimitry Andric }
798*0fca6ea1SDimitry Andric
799*0fca6ea1SDimitry Andric llvm_unreachable("Trying to pop a condition from an InstructionMatcher with "
800*0fca6ea1SDimitry Andric "no conditions");
801*0fca6ea1SDimitry Andric }
802*0fca6ea1SDimitry Andric
updateGISelFlag(GISelFlags CurFlags,const Record * R,StringRef FlagName,GISelFlags FlagBit)803*0fca6ea1SDimitry Andric GISelFlags RuleMatcher::updateGISelFlag(GISelFlags CurFlags, const Record *R,
804*0fca6ea1SDimitry Andric StringRef FlagName,
805*0fca6ea1SDimitry Andric GISelFlags FlagBit) {
806*0fca6ea1SDimitry Andric // If the value of a flag is unset, ignore it.
807*0fca6ea1SDimitry Andric // If it's set, it always takes precedence over the existing value so
808*0fca6ea1SDimitry Andric // clear/set the corresponding bit.
809*0fca6ea1SDimitry Andric bool Unset = false;
810*0fca6ea1SDimitry Andric bool Value = R->getValueAsBitOrUnset("GIIgnoreCopies", Unset);
811*0fca6ea1SDimitry Andric if (!Unset)
812*0fca6ea1SDimitry Andric return Value ? (CurFlags | FlagBit) : (CurFlags & ~FlagBit);
813*0fca6ea1SDimitry Andric return CurFlags;
814*0fca6ea1SDimitry Andric }
815*0fca6ea1SDimitry Andric
setGISelFlags(const Record * R)816*0fca6ea1SDimitry Andric SaveAndRestore<GISelFlags> RuleMatcher::setGISelFlags(const Record *R) {
817*0fca6ea1SDimitry Andric if (!R || !R->isSubClassOf("GISelFlags"))
818*0fca6ea1SDimitry Andric return {Flags, Flags};
819*0fca6ea1SDimitry Andric
820*0fca6ea1SDimitry Andric assert((R->isSubClassOf("PatFrags") || R->isSubClassOf("Pattern")) &&
821*0fca6ea1SDimitry Andric "GISelFlags is only expected on Pattern/PatFrags!");
822*0fca6ea1SDimitry Andric
823*0fca6ea1SDimitry Andric GISelFlags NewFlags =
824*0fca6ea1SDimitry Andric updateGISelFlag(Flags, R, "GIIgnoreCopies", GISF_IgnoreCopies);
825*0fca6ea1SDimitry Andric return {Flags, NewFlags};
826*0fca6ea1SDimitry Andric }
827*0fca6ea1SDimitry Andric
defineComplexSubOperand(StringRef SymbolicName,Record * ComplexPattern,unsigned RendererID,unsigned SubOperandID,StringRef ParentSymbolicName)828*0fca6ea1SDimitry Andric Error RuleMatcher::defineComplexSubOperand(StringRef SymbolicName,
829*0fca6ea1SDimitry Andric Record *ComplexPattern,
830*0fca6ea1SDimitry Andric unsigned RendererID,
831*0fca6ea1SDimitry Andric unsigned SubOperandID,
832*0fca6ea1SDimitry Andric StringRef ParentSymbolicName) {
833*0fca6ea1SDimitry Andric std::string ParentName(ParentSymbolicName);
834*0fca6ea1SDimitry Andric if (ComplexSubOperands.count(SymbolicName)) {
835*0fca6ea1SDimitry Andric const std::string &RecordedParentName =
836*0fca6ea1SDimitry Andric ComplexSubOperandsParentName[SymbolicName];
837*0fca6ea1SDimitry Andric if (RecordedParentName != ParentName)
838*0fca6ea1SDimitry Andric return failUnsupported("Error: Complex suboperand " + SymbolicName +
839*0fca6ea1SDimitry Andric " referenced by different operands: " +
840*0fca6ea1SDimitry Andric RecordedParentName + " and " + ParentName + ".");
841*0fca6ea1SDimitry Andric // Complex suboperand referenced more than once from same the operand is
842*0fca6ea1SDimitry Andric // used to generate 'same operand check'. Emitting of
843*0fca6ea1SDimitry Andric // GIR_ComplexSubOperandRenderer for them is already handled.
844*0fca6ea1SDimitry Andric return Error::success();
845*0fca6ea1SDimitry Andric }
846*0fca6ea1SDimitry Andric
847*0fca6ea1SDimitry Andric ComplexSubOperands[SymbolicName] =
848*0fca6ea1SDimitry Andric std::tuple(ComplexPattern, RendererID, SubOperandID);
849*0fca6ea1SDimitry Andric ComplexSubOperandsParentName[SymbolicName] = ParentName;
850*0fca6ea1SDimitry Andric
851*0fca6ea1SDimitry Andric return Error::success();
852*0fca6ea1SDimitry Andric }
853*0fca6ea1SDimitry Andric
addInstructionMatcher(StringRef SymbolicName)854*0fca6ea1SDimitry Andric InstructionMatcher &RuleMatcher::addInstructionMatcher(StringRef SymbolicName) {
855*0fca6ea1SDimitry Andric Matchers.emplace_back(new InstructionMatcher(*this, SymbolicName));
856*0fca6ea1SDimitry Andric MutatableInsns.insert(Matchers.back().get());
857*0fca6ea1SDimitry Andric return *Matchers.back();
858*0fca6ea1SDimitry Andric }
859*0fca6ea1SDimitry Andric
addRequiredSimplePredicate(StringRef PredName)860*0fca6ea1SDimitry Andric void RuleMatcher::addRequiredSimplePredicate(StringRef PredName) {
861*0fca6ea1SDimitry Andric RequiredSimplePredicates.push_back(PredName.str());
862*0fca6ea1SDimitry Andric }
863*0fca6ea1SDimitry Andric
getRequiredSimplePredicates()864*0fca6ea1SDimitry Andric const std::vector<std::string> &RuleMatcher::getRequiredSimplePredicates() {
865*0fca6ea1SDimitry Andric return RequiredSimplePredicates;
866*0fca6ea1SDimitry Andric }
867*0fca6ea1SDimitry Andric
addRequiredFeature(Record * Feature)868*0fca6ea1SDimitry Andric void RuleMatcher::addRequiredFeature(Record *Feature) {
869*0fca6ea1SDimitry Andric RequiredFeatures.push_back(Feature);
870*0fca6ea1SDimitry Andric }
871*0fca6ea1SDimitry Andric
getRequiredFeatures() const872*0fca6ea1SDimitry Andric const std::vector<Record *> &RuleMatcher::getRequiredFeatures() const {
873*0fca6ea1SDimitry Andric return RequiredFeatures;
874*0fca6ea1SDimitry Andric }
875*0fca6ea1SDimitry Andric
implicitlyDefineInsnVar(InstructionMatcher & Matcher)876*0fca6ea1SDimitry Andric unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {
877*0fca6ea1SDimitry Andric unsigned NewInsnVarID = NextInsnVarID++;
878*0fca6ea1SDimitry Andric InsnVariableIDs[&Matcher] = NewInsnVarID;
879*0fca6ea1SDimitry Andric return NewInsnVarID;
880*0fca6ea1SDimitry Andric }
881*0fca6ea1SDimitry Andric
getInsnVarID(InstructionMatcher & InsnMatcher) const882*0fca6ea1SDimitry Andric unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const {
883*0fca6ea1SDimitry Andric const auto &I = InsnVariableIDs.find(&InsnMatcher);
884*0fca6ea1SDimitry Andric if (I != InsnVariableIDs.end())
885*0fca6ea1SDimitry Andric return I->second;
886*0fca6ea1SDimitry Andric llvm_unreachable("Matched Insn was not captured in a local variable");
887*0fca6ea1SDimitry Andric }
888*0fca6ea1SDimitry Andric
defineOperand(StringRef SymbolicName,OperandMatcher & OM)889*0fca6ea1SDimitry Andric void RuleMatcher::defineOperand(StringRef SymbolicName, OperandMatcher &OM) {
890*0fca6ea1SDimitry Andric if (!DefinedOperands.contains(SymbolicName)) {
891*0fca6ea1SDimitry Andric DefinedOperands[SymbolicName] = &OM;
892*0fca6ea1SDimitry Andric return;
893*0fca6ea1SDimitry Andric }
894*0fca6ea1SDimitry Andric
895*0fca6ea1SDimitry Andric // If the operand is already defined, then we must ensure both references in
896*0fca6ea1SDimitry Andric // the matcher have the exact same node.
897*0fca6ea1SDimitry Andric RuleMatcher &RM = OM.getInstructionMatcher().getRuleMatcher();
898*0fca6ea1SDimitry Andric OM.addPredicate<SameOperandMatcher>(
899*0fca6ea1SDimitry Andric OM.getSymbolicName(), getOperandMatcher(OM.getSymbolicName()).getOpIdx(),
900*0fca6ea1SDimitry Andric RM.getGISelFlags());
901*0fca6ea1SDimitry Andric }
902*0fca6ea1SDimitry Andric
definePhysRegOperand(Record * Reg,OperandMatcher & OM)903*0fca6ea1SDimitry Andric void RuleMatcher::definePhysRegOperand(Record *Reg, OperandMatcher &OM) {
904*0fca6ea1SDimitry Andric if (!PhysRegOperands.contains(Reg)) {
905*0fca6ea1SDimitry Andric PhysRegOperands[Reg] = &OM;
906*0fca6ea1SDimitry Andric return;
907*0fca6ea1SDimitry Andric }
908*0fca6ea1SDimitry Andric }
909*0fca6ea1SDimitry Andric
910*0fca6ea1SDimitry Andric InstructionMatcher &
getInstructionMatcher(StringRef SymbolicName) const911*0fca6ea1SDimitry Andric RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
912*0fca6ea1SDimitry Andric for (const auto &I : InsnVariableIDs)
913*0fca6ea1SDimitry Andric if (I.first->getSymbolicName() == SymbolicName)
914*0fca6ea1SDimitry Andric return *I.first;
915*0fca6ea1SDimitry Andric llvm_unreachable(
916*0fca6ea1SDimitry Andric ("Failed to lookup instruction " + SymbolicName).str().c_str());
917*0fca6ea1SDimitry Andric }
918*0fca6ea1SDimitry Andric
getPhysRegOperandMatcher(Record * Reg) const919*0fca6ea1SDimitry Andric const OperandMatcher &RuleMatcher::getPhysRegOperandMatcher(Record *Reg) const {
920*0fca6ea1SDimitry Andric const auto &I = PhysRegOperands.find(Reg);
921*0fca6ea1SDimitry Andric
922*0fca6ea1SDimitry Andric if (I == PhysRegOperands.end()) {
923*0fca6ea1SDimitry Andric PrintFatalError(SrcLoc, "Register " + Reg->getName() +
924*0fca6ea1SDimitry Andric " was not declared in matcher");
925*0fca6ea1SDimitry Andric }
926*0fca6ea1SDimitry Andric
927*0fca6ea1SDimitry Andric return *I->second;
928*0fca6ea1SDimitry Andric }
929*0fca6ea1SDimitry Andric
getOperandMatcher(StringRef Name)930*0fca6ea1SDimitry Andric OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) {
931*0fca6ea1SDimitry Andric const auto &I = DefinedOperands.find(Name);
932*0fca6ea1SDimitry Andric
933*0fca6ea1SDimitry Andric if (I == DefinedOperands.end())
934*0fca6ea1SDimitry Andric PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
935*0fca6ea1SDimitry Andric
936*0fca6ea1SDimitry Andric return *I->second;
937*0fca6ea1SDimitry Andric }
938*0fca6ea1SDimitry Andric
getOperandMatcher(StringRef Name) const939*0fca6ea1SDimitry Andric const OperandMatcher &RuleMatcher::getOperandMatcher(StringRef Name) const {
940*0fca6ea1SDimitry Andric const auto &I = DefinedOperands.find(Name);
941*0fca6ea1SDimitry Andric
942*0fca6ea1SDimitry Andric if (I == DefinedOperands.end())
943*0fca6ea1SDimitry Andric PrintFatalError(SrcLoc, "Operand " + Name + " was not declared in matcher");
944*0fca6ea1SDimitry Andric
945*0fca6ea1SDimitry Andric return *I->second;
946*0fca6ea1SDimitry Andric }
947*0fca6ea1SDimitry Andric
emit(MatchTable & Table)948*0fca6ea1SDimitry Andric void RuleMatcher::emit(MatchTable &Table) {
949*0fca6ea1SDimitry Andric if (Matchers.empty())
950*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected empty matcher!");
951*0fca6ea1SDimitry Andric
952*0fca6ea1SDimitry Andric // The representation supports rules that require multiple roots such as:
953*0fca6ea1SDimitry Andric // %ptr(p0) = ...
954*0fca6ea1SDimitry Andric // %elt0(s32) = G_LOAD %ptr
955*0fca6ea1SDimitry Andric // %1(p0) = G_ADD %ptr, 4
956*0fca6ea1SDimitry Andric // %elt1(s32) = G_LOAD p0 %1
957*0fca6ea1SDimitry Andric // which could be usefully folded into:
958*0fca6ea1SDimitry Andric // %ptr(p0) = ...
959*0fca6ea1SDimitry Andric // %elt0(s32), %elt1(s32) = TGT_LOAD_PAIR %ptr
960*0fca6ea1SDimitry Andric // on some targets but we don't need to make use of that yet.
961*0fca6ea1SDimitry Andric assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
962*0fca6ea1SDimitry Andric
963*0fca6ea1SDimitry Andric unsigned LabelID = Table.allocateLabelID();
964*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_Try", +1)
965*0fca6ea1SDimitry Andric << MatchTable::Comment("On fail goto")
966*0fca6ea1SDimitry Andric << MatchTable::JumpTarget(LabelID)
967*0fca6ea1SDimitry Andric << MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str())
968*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
969*0fca6ea1SDimitry Andric
970*0fca6ea1SDimitry Andric if (!RequiredFeatures.empty() || HwModeIdx >= 0) {
971*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckFeatures")
972*0fca6ea1SDimitry Andric << MatchTable::NamedValue(
973*0fca6ea1SDimitry Andric 2, getNameForFeatureBitset(RequiredFeatures, HwModeIdx))
974*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
975*0fca6ea1SDimitry Andric }
976*0fca6ea1SDimitry Andric
977*0fca6ea1SDimitry Andric if (!RequiredSimplePredicates.empty()) {
978*0fca6ea1SDimitry Andric for (const auto &Pred : RequiredSimplePredicates) {
979*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckSimplePredicate")
980*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, Pred) << MatchTable::LineBreak;
981*0fca6ea1SDimitry Andric }
982*0fca6ea1SDimitry Andric }
983*0fca6ea1SDimitry Andric
984*0fca6ea1SDimitry Andric Matchers.front()->emitPredicateOpcodes(Table, *this);
985*0fca6ea1SDimitry Andric
986*0fca6ea1SDimitry Andric // Check if it's safe to replace registers.
987*0fca6ea1SDimitry Andric for (const auto &MA : Actions)
988*0fca6ea1SDimitry Andric MA->emitAdditionalPredicates(Table, *this);
989*0fca6ea1SDimitry Andric
990*0fca6ea1SDimitry Andric // We must also check if it's safe to fold the matched instructions.
991*0fca6ea1SDimitry Andric if (InsnVariableIDs.size() >= 2) {
992*0fca6ea1SDimitry Andric
993*0fca6ea1SDimitry Andric // FIXME: Emit checks to determine it's _actually_ safe to fold and/or
994*0fca6ea1SDimitry Andric // account for unsafe cases.
995*0fca6ea1SDimitry Andric //
996*0fca6ea1SDimitry Andric // Example:
997*0fca6ea1SDimitry Andric // MI1--> %0 = ...
998*0fca6ea1SDimitry Andric // %1 = ... %0
999*0fca6ea1SDimitry Andric // MI0--> %2 = ... %0
1000*0fca6ea1SDimitry Andric // It's not safe to erase MI1. We currently handle this by not
1001*0fca6ea1SDimitry Andric // erasing %0 (even when it's dead).
1002*0fca6ea1SDimitry Andric //
1003*0fca6ea1SDimitry Andric // Example:
1004*0fca6ea1SDimitry Andric // MI1--> %0 = load volatile @a
1005*0fca6ea1SDimitry Andric // %1 = load volatile @a
1006*0fca6ea1SDimitry Andric // MI0--> %2 = ... %0
1007*0fca6ea1SDimitry Andric // It's not safe to sink %0's def past %1. We currently handle
1008*0fca6ea1SDimitry Andric // this by rejecting all loads.
1009*0fca6ea1SDimitry Andric //
1010*0fca6ea1SDimitry Andric // Example:
1011*0fca6ea1SDimitry Andric // MI1--> %0 = load @a
1012*0fca6ea1SDimitry Andric // %1 = store @a
1013*0fca6ea1SDimitry Andric // MI0--> %2 = ... %0
1014*0fca6ea1SDimitry Andric // It's not safe to sink %0's def past %1. We currently handle
1015*0fca6ea1SDimitry Andric // this by rejecting all loads.
1016*0fca6ea1SDimitry Andric //
1017*0fca6ea1SDimitry Andric // Example:
1018*0fca6ea1SDimitry Andric // G_CONDBR %cond, @BB1
1019*0fca6ea1SDimitry Andric // BB0:
1020*0fca6ea1SDimitry Andric // MI1--> %0 = load @a
1021*0fca6ea1SDimitry Andric // G_BR @BB1
1022*0fca6ea1SDimitry Andric // BB1:
1023*0fca6ea1SDimitry Andric // MI0--> %2 = ... %0
1024*0fca6ea1SDimitry Andric // It's not always safe to sink %0 across control flow. In this
1025*0fca6ea1SDimitry Andric // case it may introduce a memory fault. We currentl handle
1026*0fca6ea1SDimitry Andric // this by rejecting all loads.
1027*0fca6ea1SDimitry Andric
1028*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIsSafeToFold")
1029*0fca6ea1SDimitry Andric << MatchTable::Comment("NumInsns")
1030*0fca6ea1SDimitry Andric << MatchTable::IntValue(1, InsnVariableIDs.size() - 1)
1031*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1032*0fca6ea1SDimitry Andric }
1033*0fca6ea1SDimitry Andric
1034*0fca6ea1SDimitry Andric for (const auto &PM : EpilogueMatchers)
1035*0fca6ea1SDimitry Andric PM->emitPredicateOpcodes(Table, *this);
1036*0fca6ea1SDimitry Andric
1037*0fca6ea1SDimitry Andric if (!CustomCXXAction.empty()) {
1038*0fca6ea1SDimitry Andric /// Handle combiners relying on custom C++ code instead of actions.
1039*0fca6ea1SDimitry Andric assert(Table.isCombiner() && "CustomCXXAction is only for combiners!");
1040*0fca6ea1SDimitry Andric // We cannot have actions other than debug comments.
1041*0fca6ea1SDimitry Andric assert(none_of(Actions, [](auto &A) {
1042*0fca6ea1SDimitry Andric return A->getKind() != MatchAction::AK_DebugComment;
1043*0fca6ea1SDimitry Andric }));
1044*0fca6ea1SDimitry Andric for (const auto &MA : Actions)
1045*0fca6ea1SDimitry Andric MA->emitActionOpcodes(Table, *this);
1046*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_DoneWithCustomAction", -1)
1047*0fca6ea1SDimitry Andric << MatchTable::Comment("Fn")
1048*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, CustomCXXAction)
1049*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1050*0fca6ea1SDimitry Andric } else {
1051*0fca6ea1SDimitry Andric // Emit all actions except the last one, then emit coverage and emit the
1052*0fca6ea1SDimitry Andric // final action.
1053*0fca6ea1SDimitry Andric //
1054*0fca6ea1SDimitry Andric // This is because some actions, such as GIR_EraseRootFromParent_Done, also
1055*0fca6ea1SDimitry Andric // double as a GIR_Done and terminate execution of the rule.
1056*0fca6ea1SDimitry Andric if (!Actions.empty()) {
1057*0fca6ea1SDimitry Andric for (const auto &MA : drop_end(Actions))
1058*0fca6ea1SDimitry Andric MA->emitActionOpcodes(Table, *this);
1059*0fca6ea1SDimitry Andric }
1060*0fca6ea1SDimitry Andric
1061*0fca6ea1SDimitry Andric assert((Table.isWithCoverage() ? !Table.isCombiner() : true) &&
1062*0fca6ea1SDimitry Andric "Combiner tables don't support coverage!");
1063*0fca6ea1SDimitry Andric if (Table.isWithCoverage())
1064*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_Coverage")
1065*0fca6ea1SDimitry Andric << MatchTable::IntValue(4, RuleID) << MatchTable::LineBreak;
1066*0fca6ea1SDimitry Andric else if (!Table.isCombiner())
1067*0fca6ea1SDimitry Andric Table << MatchTable::Comment(
1068*0fca6ea1SDimitry Andric ("GIR_Coverage, " + Twine(RuleID) + ",").str())
1069*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1070*0fca6ea1SDimitry Andric
1071*0fca6ea1SDimitry Andric if (Actions.empty() ||
1072*0fca6ea1SDimitry Andric !Actions.back()->emitActionOpcodesAndDone(Table, *this)) {
1073*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak;
1074*0fca6ea1SDimitry Andric }
1075*0fca6ea1SDimitry Andric }
1076*0fca6ea1SDimitry Andric
1077*0fca6ea1SDimitry Andric Table << MatchTable::Label(LabelID);
1078*0fca6ea1SDimitry Andric ++NumPatternEmitted;
1079*0fca6ea1SDimitry Andric }
1080*0fca6ea1SDimitry Andric
isHigherPriorityThan(const RuleMatcher & B) const1081*0fca6ea1SDimitry Andric bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const {
1082*0fca6ea1SDimitry Andric // Rules involving more match roots have higher priority.
1083*0fca6ea1SDimitry Andric if (Matchers.size() > B.Matchers.size())
1084*0fca6ea1SDimitry Andric return true;
1085*0fca6ea1SDimitry Andric if (Matchers.size() < B.Matchers.size())
1086*0fca6ea1SDimitry Andric return false;
1087*0fca6ea1SDimitry Andric
1088*0fca6ea1SDimitry Andric for (auto Matcher : zip(Matchers, B.Matchers)) {
1089*0fca6ea1SDimitry Andric if (std::get<0>(Matcher)->isHigherPriorityThan(*std::get<1>(Matcher)))
1090*0fca6ea1SDimitry Andric return true;
1091*0fca6ea1SDimitry Andric if (std::get<1>(Matcher)->isHigherPriorityThan(*std::get<0>(Matcher)))
1092*0fca6ea1SDimitry Andric return false;
1093*0fca6ea1SDimitry Andric }
1094*0fca6ea1SDimitry Andric
1095*0fca6ea1SDimitry Andric return false;
1096*0fca6ea1SDimitry Andric }
1097*0fca6ea1SDimitry Andric
countRendererFns() const1098*0fca6ea1SDimitry Andric unsigned RuleMatcher::countRendererFns() const {
1099*0fca6ea1SDimitry Andric return std::accumulate(
1100*0fca6ea1SDimitry Andric Matchers.begin(), Matchers.end(), 0,
1101*0fca6ea1SDimitry Andric [](unsigned A, const std::unique_ptr<InstructionMatcher> &Matcher) {
1102*0fca6ea1SDimitry Andric return A + Matcher->countRendererFns();
1103*0fca6ea1SDimitry Andric });
1104*0fca6ea1SDimitry Andric }
1105*0fca6ea1SDimitry Andric
1106*0fca6ea1SDimitry Andric //===- PredicateMatcher ---------------------------------------------------===//
1107*0fca6ea1SDimitry Andric
~PredicateMatcher()1108*0fca6ea1SDimitry Andric PredicateMatcher::~PredicateMatcher() {}
1109*0fca6ea1SDimitry Andric
1110*0fca6ea1SDimitry Andric //===- OperandPredicateMatcher --------------------------------------------===//
1111*0fca6ea1SDimitry Andric
~OperandPredicateMatcher()1112*0fca6ea1SDimitry Andric OperandPredicateMatcher::~OperandPredicateMatcher() {}
1113*0fca6ea1SDimitry Andric
isHigherPriorityThan(const OperandPredicateMatcher & B) const1114*0fca6ea1SDimitry Andric bool OperandPredicateMatcher::isHigherPriorityThan(
1115*0fca6ea1SDimitry Andric const OperandPredicateMatcher &B) const {
1116*0fca6ea1SDimitry Andric // Generally speaking, an instruction is more important than an Int or a
1117*0fca6ea1SDimitry Andric // LiteralInt because it can cover more nodes but there's an exception to
1118*0fca6ea1SDimitry Andric // this. G_CONSTANT's are less important than either of those two because they
1119*0fca6ea1SDimitry Andric // are more permissive.
1120*0fca6ea1SDimitry Andric
1121*0fca6ea1SDimitry Andric const auto *AOM = dyn_cast<InstructionOperandMatcher>(this);
1122*0fca6ea1SDimitry Andric const auto *BOM = dyn_cast<InstructionOperandMatcher>(&B);
1123*0fca6ea1SDimitry Andric bool AIsConstantInsn = AOM && AOM->getInsnMatcher().isConstantInstruction();
1124*0fca6ea1SDimitry Andric bool BIsConstantInsn = BOM && BOM->getInsnMatcher().isConstantInstruction();
1125*0fca6ea1SDimitry Andric
1126*0fca6ea1SDimitry Andric // The relative priorities between a G_CONSTANT and any other instruction
1127*0fca6ea1SDimitry Andric // don't actually matter but this code is needed to ensure a strict weak
1128*0fca6ea1SDimitry Andric // ordering. This is particularly important on Windows where the rules will
1129*0fca6ea1SDimitry Andric // be incorrectly sorted without it.
1130*0fca6ea1SDimitry Andric if (AOM && BOM)
1131*0fca6ea1SDimitry Andric return !AIsConstantInsn && BIsConstantInsn;
1132*0fca6ea1SDimitry Andric
1133*0fca6ea1SDimitry Andric if (AIsConstantInsn && (B.Kind == OPM_Int || B.Kind == OPM_LiteralInt))
1134*0fca6ea1SDimitry Andric return false;
1135*0fca6ea1SDimitry Andric if (BIsConstantInsn && (Kind == OPM_Int || Kind == OPM_LiteralInt))
1136*0fca6ea1SDimitry Andric return true;
1137*0fca6ea1SDimitry Andric
1138*0fca6ea1SDimitry Andric return Kind < B.Kind;
1139*0fca6ea1SDimitry Andric }
1140*0fca6ea1SDimitry Andric
1141*0fca6ea1SDimitry Andric //===- SameOperandMatcher -------------------------------------------------===//
1142*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1143*0fca6ea1SDimitry Andric void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1144*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1145*0fca6ea1SDimitry Andric const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName);
1146*0fca6ea1SDimitry Andric unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());
1147*0fca6ea1SDimitry Andric assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID());
1148*0fca6ea1SDimitry Andric const bool IgnoreCopies = Flags & GISF_IgnoreCopies;
1149*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(IgnoreCopies
1150*0fca6ea1SDimitry Andric ? "GIM_CheckIsSameOperandIgnoreCopies"
1151*0fca6ea1SDimitry Andric : "GIM_CheckIsSameOperand")
1152*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1153*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)
1154*0fca6ea1SDimitry Andric << MatchTable::Comment("OtherMI")
1155*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OtherInsnVarID)
1156*0fca6ea1SDimitry Andric << MatchTable::Comment("OtherOpIdx")
1157*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OtherOM.getOpIdx())
1158*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1159*0fca6ea1SDimitry Andric }
1160*0fca6ea1SDimitry Andric
1161*0fca6ea1SDimitry Andric //===- LLTOperandMatcher --------------------------------------------------===//
1162*0fca6ea1SDimitry Andric
1163*0fca6ea1SDimitry Andric std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;
1164*0fca6ea1SDimitry Andric
getValue() const1165*0fca6ea1SDimitry Andric MatchTableRecord LLTOperandMatcher::getValue() const {
1166*0fca6ea1SDimitry Andric const auto VI = TypeIDValues.find(Ty);
1167*0fca6ea1SDimitry Andric if (VI == TypeIDValues.end())
1168*0fca6ea1SDimitry Andric return MatchTable::NamedValue(1, getTy().getCxxEnumValue());
1169*0fca6ea1SDimitry Andric return MatchTable::NamedValue(1, getTy().getCxxEnumValue(), VI->second);
1170*0fca6ea1SDimitry Andric }
1171*0fca6ea1SDimitry Andric
hasValue() const1172*0fca6ea1SDimitry Andric bool LLTOperandMatcher::hasValue() const {
1173*0fca6ea1SDimitry Andric if (TypeIDValues.size() != KnownTypes.size())
1174*0fca6ea1SDimitry Andric initTypeIDValuesMap();
1175*0fca6ea1SDimitry Andric return TypeIDValues.count(Ty);
1176*0fca6ea1SDimitry Andric }
1177*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1178*0fca6ea1SDimitry Andric void LLTOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1179*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1180*0fca6ea1SDimitry Andric if (InsnVarID == 0) {
1181*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_RootCheckType");
1182*0fca6ea1SDimitry Andric } else {
1183*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")
1184*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID);
1185*0fca6ea1SDimitry Andric }
1186*0fca6ea1SDimitry Andric Table << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1187*0fca6ea1SDimitry Andric << MatchTable::Comment("Type") << getValue() << MatchTable::LineBreak;
1188*0fca6ea1SDimitry Andric }
1189*0fca6ea1SDimitry Andric
1190*0fca6ea1SDimitry Andric //===- PointerToAnyOperandMatcher -----------------------------------------===//
1191*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1192*0fca6ea1SDimitry Andric void PointerToAnyOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1193*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1194*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckPointerToAny")
1195*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1196*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1197*0fca6ea1SDimitry Andric << MatchTable::Comment("SizeInBits")
1198*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(SizeInBits) << MatchTable::LineBreak;
1199*0fca6ea1SDimitry Andric }
1200*0fca6ea1SDimitry Andric
1201*0fca6ea1SDimitry Andric //===- RecordNamedOperandMatcher ------------------------------------------===//
1202*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1203*0fca6ea1SDimitry Andric void RecordNamedOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1204*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1205*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_RecordNamedOperand")
1206*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1207*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1208*0fca6ea1SDimitry Andric << MatchTable::Comment("StoreIdx") << MatchTable::ULEB128Value(StoreIdx)
1209*0fca6ea1SDimitry Andric << MatchTable::Comment("Name : " + Name) << MatchTable::LineBreak;
1210*0fca6ea1SDimitry Andric }
1211*0fca6ea1SDimitry Andric
1212*0fca6ea1SDimitry Andric //===- RecordRegisterType ------------------------------------------===//
1213*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1214*0fca6ea1SDimitry Andric void RecordRegisterType::emitPredicateOpcodes(MatchTable &Table,
1215*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1216*0fca6ea1SDimitry Andric assert(Idx < 0 && "Temp types always have negative indexes!");
1217*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_RecordRegType") << MatchTable::Comment("MI")
1218*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
1219*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpIdx) << MatchTable::Comment("TempTypeIdx")
1220*0fca6ea1SDimitry Andric << MatchTable::IntValue(1, Idx) << MatchTable::LineBreak;
1221*0fca6ea1SDimitry Andric }
1222*0fca6ea1SDimitry Andric
1223*0fca6ea1SDimitry Andric //===- ComplexPatternOperandMatcher ---------------------------------------===//
1224*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1225*0fca6ea1SDimitry Andric void ComplexPatternOperandMatcher::emitPredicateOpcodes(
1226*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1227*0fca6ea1SDimitry Andric unsigned ID = getAllocatedTemporariesBaseID();
1228*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckComplexPattern")
1229*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1230*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1231*0fca6ea1SDimitry Andric << MatchTable::Comment("Renderer") << MatchTable::IntValue(2, ID)
1232*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, ("GICP_" + TheDef.getName()).str())
1233*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1234*0fca6ea1SDimitry Andric }
1235*0fca6ea1SDimitry Andric
getAllocatedTemporariesBaseID() const1236*0fca6ea1SDimitry Andric unsigned ComplexPatternOperandMatcher::getAllocatedTemporariesBaseID() const {
1237*0fca6ea1SDimitry Andric return Operand.getAllocatedTemporariesBaseID();
1238*0fca6ea1SDimitry Andric }
1239*0fca6ea1SDimitry Andric
1240*0fca6ea1SDimitry Andric //===- RegisterBankOperandMatcher -----------------------------------------===//
1241*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1242*0fca6ea1SDimitry Andric bool RegisterBankOperandMatcher::isIdentical(const PredicateMatcher &B) const {
1243*0fca6ea1SDimitry Andric return OperandPredicateMatcher::isIdentical(B) &&
1244*0fca6ea1SDimitry Andric RC.getDef() == cast<RegisterBankOperandMatcher>(&B)->RC.getDef();
1245*0fca6ea1SDimitry Andric }
1246*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1247*0fca6ea1SDimitry Andric void RegisterBankOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1248*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1249*0fca6ea1SDimitry Andric if (InsnVarID == 0) {
1250*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_RootCheckRegBankForClass");
1251*0fca6ea1SDimitry Andric } else {
1252*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckRegBankForClass")
1253*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID);
1254*0fca6ea1SDimitry Andric }
1255*0fca6ea1SDimitry Andric
1256*0fca6ea1SDimitry Andric Table << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1257*0fca6ea1SDimitry Andric << MatchTable::Comment("RC")
1258*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, RC.getQualifiedIdName())
1259*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1260*0fca6ea1SDimitry Andric }
1261*0fca6ea1SDimitry Andric
1262*0fca6ea1SDimitry Andric //===- MBBOperandMatcher --------------------------------------------------===//
1263*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1264*0fca6ea1SDimitry Andric void MBBOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1265*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1266*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI")
1267*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
1268*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
1269*0fca6ea1SDimitry Andric }
1270*0fca6ea1SDimitry Andric
1271*0fca6ea1SDimitry Andric //===- ImmOperandMatcher --------------------------------------------------===//
1272*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1273*0fca6ea1SDimitry Andric void ImmOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1274*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1275*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIsImm") << MatchTable::Comment("MI")
1276*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Op")
1277*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
1278*0fca6ea1SDimitry Andric }
1279*0fca6ea1SDimitry Andric
1280*0fca6ea1SDimitry Andric //===- ConstantIntOperandMatcher ------------------------------------------===//
1281*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1282*0fca6ea1SDimitry Andric void ConstantIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1283*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1284*0fca6ea1SDimitry Andric const bool IsInt8 = isInt<8>(Value);
1285*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(IsInt8 ? "GIM_CheckConstantInt8"
1286*0fca6ea1SDimitry Andric : "GIM_CheckConstantInt")
1287*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1288*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1289*0fca6ea1SDimitry Andric << MatchTable::IntValue(IsInt8 ? 1 : 8, Value) << MatchTable::LineBreak;
1290*0fca6ea1SDimitry Andric }
1291*0fca6ea1SDimitry Andric
1292*0fca6ea1SDimitry Andric //===- LiteralIntOperandMatcher -------------------------------------------===//
1293*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1294*0fca6ea1SDimitry Andric void LiteralIntOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1295*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1296*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckLiteralInt")
1297*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1298*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1299*0fca6ea1SDimitry Andric << MatchTable::IntValue(8, Value) << MatchTable::LineBreak;
1300*0fca6ea1SDimitry Andric }
1301*0fca6ea1SDimitry Andric
1302*0fca6ea1SDimitry Andric //===- CmpPredicateOperandMatcher -----------------------------------------===//
1303*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1304*0fca6ea1SDimitry Andric void CmpPredicateOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1305*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1306*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckCmpPredicate")
1307*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1308*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1309*0fca6ea1SDimitry Andric << MatchTable::Comment("Predicate")
1310*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, "CmpInst", PredName)
1311*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1312*0fca6ea1SDimitry Andric }
1313*0fca6ea1SDimitry Andric
1314*0fca6ea1SDimitry Andric //===- IntrinsicIDOperandMatcher ------------------------------------------===//
1315*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1316*0fca6ea1SDimitry Andric void IntrinsicIDOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1317*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1318*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIntrinsicID")
1319*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1320*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
1321*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, "Intrinsic::" + II->EnumName)
1322*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1323*0fca6ea1SDimitry Andric }
1324*0fca6ea1SDimitry Andric
1325*0fca6ea1SDimitry Andric //===- OperandImmPredicateMatcher -----------------------------------------===//
1326*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1327*0fca6ea1SDimitry Andric void OperandImmPredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
1328*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1329*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckImmOperandPredicate")
1330*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1331*0fca6ea1SDimitry Andric << MatchTable::Comment("MO") << MatchTable::ULEB128Value(OpIdx)
1332*0fca6ea1SDimitry Andric << MatchTable::Comment("Predicate")
1333*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))
1334*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1335*0fca6ea1SDimitry Andric }
1336*0fca6ea1SDimitry Andric
1337*0fca6ea1SDimitry Andric //===- OperandMatcher -----------------------------------------------------===//
1338*0fca6ea1SDimitry Andric
getOperandExpr(unsigned InsnVarID) const1339*0fca6ea1SDimitry Andric std::string OperandMatcher::getOperandExpr(unsigned InsnVarID) const {
1340*0fca6ea1SDimitry Andric return "State.MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" +
1341*0fca6ea1SDimitry Andric llvm::to_string(OpIdx) + ")";
1342*0fca6ea1SDimitry Andric }
1343*0fca6ea1SDimitry Andric
getInsnVarID() const1344*0fca6ea1SDimitry Andric unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }
1345*0fca6ea1SDimitry Andric
getTempTypeIdx(RuleMatcher & Rule)1346*0fca6ea1SDimitry Andric TempTypeIdx OperandMatcher::getTempTypeIdx(RuleMatcher &Rule) {
1347*0fca6ea1SDimitry Andric if (TTIdx >= 0) {
1348*0fca6ea1SDimitry Andric // Temp type index not assigned yet, so assign one and add the necessary
1349*0fca6ea1SDimitry Andric // predicate.
1350*0fca6ea1SDimitry Andric TTIdx = Rule.getNextTempTypeIdx();
1351*0fca6ea1SDimitry Andric assert(TTIdx < 0);
1352*0fca6ea1SDimitry Andric addPredicate<RecordRegisterType>(TTIdx);
1353*0fca6ea1SDimitry Andric return TTIdx;
1354*0fca6ea1SDimitry Andric }
1355*0fca6ea1SDimitry Andric return TTIdx;
1356*0fca6ea1SDimitry Andric }
1357*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule)1358*0fca6ea1SDimitry Andric void OperandMatcher::emitPredicateOpcodes(MatchTable &Table,
1359*0fca6ea1SDimitry Andric RuleMatcher &Rule) {
1360*0fca6ea1SDimitry Andric if (!Optimized) {
1361*0fca6ea1SDimitry Andric std::string Comment;
1362*0fca6ea1SDimitry Andric raw_string_ostream CommentOS(Comment);
1363*0fca6ea1SDimitry Andric CommentOS << "MIs[" << getInsnVarID() << "] ";
1364*0fca6ea1SDimitry Andric if (SymbolicName.empty())
1365*0fca6ea1SDimitry Andric CommentOS << "Operand " << OpIdx;
1366*0fca6ea1SDimitry Andric else
1367*0fca6ea1SDimitry Andric CommentOS << SymbolicName;
1368*0fca6ea1SDimitry Andric Table << MatchTable::Comment(Comment) << MatchTable::LineBreak;
1369*0fca6ea1SDimitry Andric }
1370*0fca6ea1SDimitry Andric
1371*0fca6ea1SDimitry Andric emitPredicateListOpcodes(Table, Rule);
1372*0fca6ea1SDimitry Andric }
1373*0fca6ea1SDimitry Andric
isHigherPriorityThan(OperandMatcher & B)1374*0fca6ea1SDimitry Andric bool OperandMatcher::isHigherPriorityThan(OperandMatcher &B) {
1375*0fca6ea1SDimitry Andric // Operand matchers involving more predicates have higher priority.
1376*0fca6ea1SDimitry Andric if (predicates_size() > B.predicates_size())
1377*0fca6ea1SDimitry Andric return true;
1378*0fca6ea1SDimitry Andric if (predicates_size() < B.predicates_size())
1379*0fca6ea1SDimitry Andric return false;
1380*0fca6ea1SDimitry Andric
1381*0fca6ea1SDimitry Andric // This assumes that predicates are added in a consistent order.
1382*0fca6ea1SDimitry Andric for (auto &&Predicate : zip(predicates(), B.predicates())) {
1383*0fca6ea1SDimitry Andric if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
1384*0fca6ea1SDimitry Andric return true;
1385*0fca6ea1SDimitry Andric if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
1386*0fca6ea1SDimitry Andric return false;
1387*0fca6ea1SDimitry Andric }
1388*0fca6ea1SDimitry Andric
1389*0fca6ea1SDimitry Andric return false;
1390*0fca6ea1SDimitry Andric }
1391*0fca6ea1SDimitry Andric
countRendererFns()1392*0fca6ea1SDimitry Andric unsigned OperandMatcher::countRendererFns() {
1393*0fca6ea1SDimitry Andric return std::accumulate(
1394*0fca6ea1SDimitry Andric predicates().begin(), predicates().end(), 0,
1395*0fca6ea1SDimitry Andric [](unsigned A,
1396*0fca6ea1SDimitry Andric const std::unique_ptr<OperandPredicateMatcher> &Predicate) {
1397*0fca6ea1SDimitry Andric return A + Predicate->countRendererFns();
1398*0fca6ea1SDimitry Andric });
1399*0fca6ea1SDimitry Andric }
1400*0fca6ea1SDimitry Andric
addTypeCheckPredicate(const TypeSetByHwMode & VTy,bool OperandIsAPointer)1401*0fca6ea1SDimitry Andric Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,
1402*0fca6ea1SDimitry Andric bool OperandIsAPointer) {
1403*0fca6ea1SDimitry Andric if (!VTy.isMachineValueType())
1404*0fca6ea1SDimitry Andric return failUnsupported("unsupported typeset");
1405*0fca6ea1SDimitry Andric
1406*0fca6ea1SDimitry Andric if (VTy.getMachineValueType() == MVT::iPTR && OperandIsAPointer) {
1407*0fca6ea1SDimitry Andric addPredicate<PointerToAnyOperandMatcher>(0);
1408*0fca6ea1SDimitry Andric return Error::success();
1409*0fca6ea1SDimitry Andric }
1410*0fca6ea1SDimitry Andric
1411*0fca6ea1SDimitry Andric auto OpTyOrNone = MVTToLLT(VTy.getMachineValueType().SimpleTy);
1412*0fca6ea1SDimitry Andric if (!OpTyOrNone)
1413*0fca6ea1SDimitry Andric return failUnsupported("unsupported type");
1414*0fca6ea1SDimitry Andric
1415*0fca6ea1SDimitry Andric if (OperandIsAPointer)
1416*0fca6ea1SDimitry Andric addPredicate<PointerToAnyOperandMatcher>(OpTyOrNone->get().getSizeInBits());
1417*0fca6ea1SDimitry Andric else if (VTy.isPointer())
1418*0fca6ea1SDimitry Andric addPredicate<LLTOperandMatcher>(
1419*0fca6ea1SDimitry Andric LLT::pointer(VTy.getPtrAddrSpace(), OpTyOrNone->get().getSizeInBits()));
1420*0fca6ea1SDimitry Andric else
1421*0fca6ea1SDimitry Andric addPredicate<LLTOperandMatcher>(*OpTyOrNone);
1422*0fca6ea1SDimitry Andric return Error::success();
1423*0fca6ea1SDimitry Andric }
1424*0fca6ea1SDimitry Andric
1425*0fca6ea1SDimitry Andric //===- InstructionOpcodeMatcher -------------------------------------------===//
1426*0fca6ea1SDimitry Andric
1427*0fca6ea1SDimitry Andric DenseMap<const CodeGenInstruction *, unsigned>
1428*0fca6ea1SDimitry Andric InstructionOpcodeMatcher::OpcodeValues;
1429*0fca6ea1SDimitry Andric
1430*0fca6ea1SDimitry Andric MatchTableRecord
getInstValue(const CodeGenInstruction * I) const1431*0fca6ea1SDimitry Andric InstructionOpcodeMatcher::getInstValue(const CodeGenInstruction *I) const {
1432*0fca6ea1SDimitry Andric const auto VI = OpcodeValues.find(I);
1433*0fca6ea1SDimitry Andric if (VI != OpcodeValues.end())
1434*0fca6ea1SDimitry Andric return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),
1435*0fca6ea1SDimitry Andric VI->second);
1436*0fca6ea1SDimitry Andric return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());
1437*0fca6ea1SDimitry Andric }
1438*0fca6ea1SDimitry Andric
initOpcodeValuesMap(const CodeGenTarget & Target)1439*0fca6ea1SDimitry Andric void InstructionOpcodeMatcher::initOpcodeValuesMap(
1440*0fca6ea1SDimitry Andric const CodeGenTarget &Target) {
1441*0fca6ea1SDimitry Andric OpcodeValues.clear();
1442*0fca6ea1SDimitry Andric
1443*0fca6ea1SDimitry Andric for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())
1444*0fca6ea1SDimitry Andric OpcodeValues[I] = Target.getInstrIntValue(I->TheDef);
1445*0fca6ea1SDimitry Andric }
1446*0fca6ea1SDimitry Andric
getValue() const1447*0fca6ea1SDimitry Andric MatchTableRecord InstructionOpcodeMatcher::getValue() const {
1448*0fca6ea1SDimitry Andric assert(Insts.size() == 1);
1449*0fca6ea1SDimitry Andric
1450*0fca6ea1SDimitry Andric const CodeGenInstruction *I = Insts[0];
1451*0fca6ea1SDimitry Andric const auto VI = OpcodeValues.find(I);
1452*0fca6ea1SDimitry Andric if (VI != OpcodeValues.end())
1453*0fca6ea1SDimitry Andric return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName(),
1454*0fca6ea1SDimitry Andric VI->second);
1455*0fca6ea1SDimitry Andric return MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName());
1456*0fca6ea1SDimitry Andric }
1457*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1458*0fca6ea1SDimitry Andric void InstructionOpcodeMatcher::emitPredicateOpcodes(MatchTable &Table,
1459*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1460*0fca6ea1SDimitry Andric StringRef CheckType =
1461*0fca6ea1SDimitry Andric Insts.size() == 1 ? "GIM_CheckOpcode" : "GIM_CheckOpcodeIsEither";
1462*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(CheckType) << MatchTable::Comment("MI")
1463*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID);
1464*0fca6ea1SDimitry Andric
1465*0fca6ea1SDimitry Andric for (const CodeGenInstruction *I : Insts)
1466*0fca6ea1SDimitry Andric Table << getInstValue(I);
1467*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
1468*0fca6ea1SDimitry Andric }
1469*0fca6ea1SDimitry Andric
isHigherPriorityThan(const InstructionPredicateMatcher & B) const1470*0fca6ea1SDimitry Andric bool InstructionOpcodeMatcher::isHigherPriorityThan(
1471*0fca6ea1SDimitry Andric const InstructionPredicateMatcher &B) const {
1472*0fca6ea1SDimitry Andric if (InstructionPredicateMatcher::isHigherPriorityThan(B))
1473*0fca6ea1SDimitry Andric return true;
1474*0fca6ea1SDimitry Andric if (B.InstructionPredicateMatcher::isHigherPriorityThan(*this))
1475*0fca6ea1SDimitry Andric return false;
1476*0fca6ea1SDimitry Andric
1477*0fca6ea1SDimitry Andric // Prioritize opcodes for cosmetic reasons in the generated source. Although
1478*0fca6ea1SDimitry Andric // this is cosmetic at the moment, we may want to drive a similar ordering
1479*0fca6ea1SDimitry Andric // using instruction frequency information to improve compile time.
1480*0fca6ea1SDimitry Andric if (const InstructionOpcodeMatcher *BO =
1481*0fca6ea1SDimitry Andric dyn_cast<InstructionOpcodeMatcher>(&B))
1482*0fca6ea1SDimitry Andric return Insts[0]->TheDef->getName() < BO->Insts[0]->TheDef->getName();
1483*0fca6ea1SDimitry Andric
1484*0fca6ea1SDimitry Andric return false;
1485*0fca6ea1SDimitry Andric }
1486*0fca6ea1SDimitry Andric
isConstantInstruction() const1487*0fca6ea1SDimitry Andric bool InstructionOpcodeMatcher::isConstantInstruction() const {
1488*0fca6ea1SDimitry Andric return Insts.size() == 1 && Insts[0]->TheDef->getName() == "G_CONSTANT";
1489*0fca6ea1SDimitry Andric }
1490*0fca6ea1SDimitry Andric
getOpcode() const1491*0fca6ea1SDimitry Andric StringRef InstructionOpcodeMatcher::getOpcode() const {
1492*0fca6ea1SDimitry Andric return Insts[0]->TheDef->getName();
1493*0fca6ea1SDimitry Andric }
1494*0fca6ea1SDimitry Andric
isVariadicNumOperands() const1495*0fca6ea1SDimitry Andric bool InstructionOpcodeMatcher::isVariadicNumOperands() const {
1496*0fca6ea1SDimitry Andric // If one is variadic, they all should be.
1497*0fca6ea1SDimitry Andric return Insts[0]->Operands.isVariadic;
1498*0fca6ea1SDimitry Andric }
1499*0fca6ea1SDimitry Andric
getOperandType(unsigned OpIdx) const1500*0fca6ea1SDimitry Andric StringRef InstructionOpcodeMatcher::getOperandType(unsigned OpIdx) const {
1501*0fca6ea1SDimitry Andric // Types expected to be uniform for all alternatives.
1502*0fca6ea1SDimitry Andric return Insts[0]->Operands[OpIdx].OperandType;
1503*0fca6ea1SDimitry Andric }
1504*0fca6ea1SDimitry Andric
1505*0fca6ea1SDimitry Andric //===- InstructionNumOperandsMatcher --------------------------------------===//
1506*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1507*0fca6ea1SDimitry Andric void InstructionNumOperandsMatcher::emitPredicateOpcodes(
1508*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1509*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckNumOperands")
1510*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1511*0fca6ea1SDimitry Andric << MatchTable::Comment("Expected")
1512*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NumOperands) << MatchTable::LineBreak;
1513*0fca6ea1SDimitry Andric }
1514*0fca6ea1SDimitry Andric
1515*0fca6ea1SDimitry Andric //===- InstructionImmPredicateMatcher -------------------------------------===//
1516*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1517*0fca6ea1SDimitry Andric bool InstructionImmPredicateMatcher::isIdentical(
1518*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1519*0fca6ea1SDimitry Andric return InstructionPredicateMatcher::isIdentical(B) &&
1520*0fca6ea1SDimitry Andric Predicate.getOrigPatFragRecord() ==
1521*0fca6ea1SDimitry Andric cast<InstructionImmPredicateMatcher>(&B)
1522*0fca6ea1SDimitry Andric ->Predicate.getOrigPatFragRecord();
1523*0fca6ea1SDimitry Andric }
1524*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1525*0fca6ea1SDimitry Andric void InstructionImmPredicateMatcher::emitPredicateOpcodes(
1526*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1527*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(getMatchOpcodeForImmPredicate(Predicate))
1528*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1529*0fca6ea1SDimitry Andric << MatchTable::Comment("Predicate")
1530*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, getEnumNameForPredicate(Predicate))
1531*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1532*0fca6ea1SDimitry Andric }
1533*0fca6ea1SDimitry Andric
1534*0fca6ea1SDimitry Andric //===- AtomicOrderingMMOPredicateMatcher ----------------------------------===//
1535*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1536*0fca6ea1SDimitry Andric bool AtomicOrderingMMOPredicateMatcher::isIdentical(
1537*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1538*0fca6ea1SDimitry Andric if (!InstructionPredicateMatcher::isIdentical(B))
1539*0fca6ea1SDimitry Andric return false;
1540*0fca6ea1SDimitry Andric const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B);
1541*0fca6ea1SDimitry Andric return Order == R.Order && Comparator == R.Comparator;
1542*0fca6ea1SDimitry Andric }
1543*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1544*0fca6ea1SDimitry Andric void AtomicOrderingMMOPredicateMatcher::emitPredicateOpcodes(
1545*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1546*0fca6ea1SDimitry Andric StringRef Opcode = "GIM_CheckAtomicOrdering";
1547*0fca6ea1SDimitry Andric
1548*0fca6ea1SDimitry Andric if (Comparator == AO_OrStronger)
1549*0fca6ea1SDimitry Andric Opcode = "GIM_CheckAtomicOrderingOrStrongerThan";
1550*0fca6ea1SDimitry Andric if (Comparator == AO_WeakerThan)
1551*0fca6ea1SDimitry Andric Opcode = "GIM_CheckAtomicOrderingWeakerThan";
1552*0fca6ea1SDimitry Andric
1553*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(Opcode) << MatchTable::Comment("MI")
1554*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnVarID) << MatchTable::Comment("Order")
1555*0fca6ea1SDimitry Andric << MatchTable::NamedValue(1,
1556*0fca6ea1SDimitry Andric ("(uint8_t)AtomicOrdering::" + Order).str())
1557*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1558*0fca6ea1SDimitry Andric }
1559*0fca6ea1SDimitry Andric
1560*0fca6ea1SDimitry Andric //===- MemorySizePredicateMatcher -----------------------------------------===//
1561*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1562*0fca6ea1SDimitry Andric void MemorySizePredicateMatcher::emitPredicateOpcodes(MatchTable &Table,
1563*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1564*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckMemorySizeEqualTo")
1565*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1566*0fca6ea1SDimitry Andric << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
1567*0fca6ea1SDimitry Andric << MatchTable::Comment("Size") << MatchTable::IntValue(4, Size)
1568*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1569*0fca6ea1SDimitry Andric }
1570*0fca6ea1SDimitry Andric
1571*0fca6ea1SDimitry Andric //===- MemoryAddressSpacePredicateMatcher ---------------------------------===//
1572*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1573*0fca6ea1SDimitry Andric bool MemoryAddressSpacePredicateMatcher::isIdentical(
1574*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1575*0fca6ea1SDimitry Andric if (!InstructionPredicateMatcher::isIdentical(B))
1576*0fca6ea1SDimitry Andric return false;
1577*0fca6ea1SDimitry Andric auto *Other = cast<MemoryAddressSpacePredicateMatcher>(&B);
1578*0fca6ea1SDimitry Andric return MMOIdx == Other->MMOIdx && AddrSpaces == Other->AddrSpaces;
1579*0fca6ea1SDimitry Andric }
1580*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1581*0fca6ea1SDimitry Andric void MemoryAddressSpacePredicateMatcher::emitPredicateOpcodes(
1582*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1583*0fca6ea1SDimitry Andric assert(AddrSpaces.size() < 256);
1584*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckMemoryAddressSpace")
1585*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1586*0fca6ea1SDimitry Andric << MatchTable::Comment("MMO")
1587*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(MMOIdx)
1588*0fca6ea1SDimitry Andric // Encode number of address spaces to expect.
1589*0fca6ea1SDimitry Andric << MatchTable::Comment("NumAddrSpace")
1590*0fca6ea1SDimitry Andric << MatchTable::IntValue(1, AddrSpaces.size());
1591*0fca6ea1SDimitry Andric for (unsigned AS : AddrSpaces)
1592*0fca6ea1SDimitry Andric Table << MatchTable::Comment("AddrSpace") << MatchTable::ULEB128Value(AS);
1593*0fca6ea1SDimitry Andric
1594*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
1595*0fca6ea1SDimitry Andric }
1596*0fca6ea1SDimitry Andric
1597*0fca6ea1SDimitry Andric //===- MemoryAlignmentPredicateMatcher ------------------------------------===//
1598*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1599*0fca6ea1SDimitry Andric bool MemoryAlignmentPredicateMatcher::isIdentical(
1600*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1601*0fca6ea1SDimitry Andric if (!InstructionPredicateMatcher::isIdentical(B))
1602*0fca6ea1SDimitry Andric return false;
1603*0fca6ea1SDimitry Andric auto *Other = cast<MemoryAlignmentPredicateMatcher>(&B);
1604*0fca6ea1SDimitry Andric return MMOIdx == Other->MMOIdx && MinAlign == Other->MinAlign;
1605*0fca6ea1SDimitry Andric }
1606*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1607*0fca6ea1SDimitry Andric void MemoryAlignmentPredicateMatcher::emitPredicateOpcodes(
1608*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1609*0fca6ea1SDimitry Andric // TODO: we could support more, just need to emit the right opcode or switch
1610*0fca6ea1SDimitry Andric // to log alignment.
1611*0fca6ea1SDimitry Andric assert(MinAlign < 256);
1612*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckMemoryAlignment")
1613*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1614*0fca6ea1SDimitry Andric << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
1615*0fca6ea1SDimitry Andric << MatchTable::Comment("MinAlign") << MatchTable::IntValue(1, MinAlign)
1616*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1617*0fca6ea1SDimitry Andric }
1618*0fca6ea1SDimitry Andric
1619*0fca6ea1SDimitry Andric //===- MemoryVsLLTSizePredicateMatcher ------------------------------------===//
1620*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1621*0fca6ea1SDimitry Andric bool MemoryVsLLTSizePredicateMatcher::isIdentical(
1622*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1623*0fca6ea1SDimitry Andric return InstructionPredicateMatcher::isIdentical(B) &&
1624*0fca6ea1SDimitry Andric MMOIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->MMOIdx &&
1625*0fca6ea1SDimitry Andric Relation == cast<MemoryVsLLTSizePredicateMatcher>(&B)->Relation &&
1626*0fca6ea1SDimitry Andric OpIdx == cast<MemoryVsLLTSizePredicateMatcher>(&B)->OpIdx;
1627*0fca6ea1SDimitry Andric }
1628*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1629*0fca6ea1SDimitry Andric void MemoryVsLLTSizePredicateMatcher::emitPredicateOpcodes(
1630*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1631*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(
1632*0fca6ea1SDimitry Andric Relation == EqualTo ? "GIM_CheckMemorySizeEqualToLLT"
1633*0fca6ea1SDimitry Andric : Relation == GreaterThan ? "GIM_CheckMemorySizeGreaterThanLLT"
1634*0fca6ea1SDimitry Andric : "GIM_CheckMemorySizeLessThanLLT")
1635*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1636*0fca6ea1SDimitry Andric << MatchTable::Comment("MMO") << MatchTable::ULEB128Value(MMOIdx)
1637*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)
1638*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1639*0fca6ea1SDimitry Andric }
1640*0fca6ea1SDimitry Andric
1641*0fca6ea1SDimitry Andric //===- VectorSplatImmPredicateMatcher -------------------------------------===//
1642*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1643*0fca6ea1SDimitry Andric void VectorSplatImmPredicateMatcher::emitPredicateOpcodes(
1644*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1645*0fca6ea1SDimitry Andric if (Kind == AllOnes)
1646*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllOnes");
1647*0fca6ea1SDimitry Andric else
1648*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckIsBuildVectorAllZeros");
1649*0fca6ea1SDimitry Andric
1650*0fca6ea1SDimitry Andric Table << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID);
1651*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
1652*0fca6ea1SDimitry Andric }
1653*0fca6ea1SDimitry Andric
1654*0fca6ea1SDimitry Andric //===- GenericInstructionPredicateMatcher ---------------------------------===//
1655*0fca6ea1SDimitry Andric
GenericInstructionPredicateMatcher(unsigned InsnVarID,TreePredicateFn Predicate)1656*0fca6ea1SDimitry Andric GenericInstructionPredicateMatcher::GenericInstructionPredicateMatcher(
1657*0fca6ea1SDimitry Andric unsigned InsnVarID, TreePredicateFn Predicate)
1658*0fca6ea1SDimitry Andric : GenericInstructionPredicateMatcher(InsnVarID,
1659*0fca6ea1SDimitry Andric getEnumNameForPredicate(Predicate)) {}
1660*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1661*0fca6ea1SDimitry Andric bool GenericInstructionPredicateMatcher::isIdentical(
1662*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1663*0fca6ea1SDimitry Andric return InstructionPredicateMatcher::isIdentical(B) &&
1664*0fca6ea1SDimitry Andric EnumVal ==
1665*0fca6ea1SDimitry Andric static_cast<const GenericInstructionPredicateMatcher &>(B).EnumVal;
1666*0fca6ea1SDimitry Andric }
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1667*0fca6ea1SDimitry Andric void GenericInstructionPredicateMatcher::emitPredicateOpcodes(
1668*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1669*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckCxxInsnPredicate")
1670*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1671*0fca6ea1SDimitry Andric << MatchTable::Comment("FnId") << MatchTable::NamedValue(2, EnumVal)
1672*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1673*0fca6ea1SDimitry Andric }
1674*0fca6ea1SDimitry Andric
1675*0fca6ea1SDimitry Andric //===- MIFlagsInstructionPredicateMatcher ---------------------------------===//
1676*0fca6ea1SDimitry Andric
isIdentical(const PredicateMatcher & B) const1677*0fca6ea1SDimitry Andric bool MIFlagsInstructionPredicateMatcher::isIdentical(
1678*0fca6ea1SDimitry Andric const PredicateMatcher &B) const {
1679*0fca6ea1SDimitry Andric if (!InstructionPredicateMatcher::isIdentical(B))
1680*0fca6ea1SDimitry Andric return false;
1681*0fca6ea1SDimitry Andric const auto &Other =
1682*0fca6ea1SDimitry Andric static_cast<const MIFlagsInstructionPredicateMatcher &>(B);
1683*0fca6ea1SDimitry Andric return Flags == Other.Flags && CheckNot == Other.CheckNot;
1684*0fca6ea1SDimitry Andric }
1685*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule) const1686*0fca6ea1SDimitry Andric void MIFlagsInstructionPredicateMatcher::emitPredicateOpcodes(
1687*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
1688*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(CheckNot ? "GIM_MIFlagsNot" : "GIM_MIFlags")
1689*0fca6ea1SDimitry Andric << MatchTable::Comment("MI") << MatchTable::ULEB128Value(InsnVarID)
1690*0fca6ea1SDimitry Andric << MatchTable::NamedValue(4, join(Flags, " | "))
1691*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1692*0fca6ea1SDimitry Andric }
1693*0fca6ea1SDimitry Andric
1694*0fca6ea1SDimitry Andric //===- InstructionMatcher -------------------------------------------------===//
1695*0fca6ea1SDimitry Andric
1696*0fca6ea1SDimitry Andric OperandMatcher &
addOperand(unsigned OpIdx,const std::string & SymbolicName,unsigned AllocatedTemporariesBaseID)1697*0fca6ea1SDimitry Andric InstructionMatcher::addOperand(unsigned OpIdx, const std::string &SymbolicName,
1698*0fca6ea1SDimitry Andric unsigned AllocatedTemporariesBaseID) {
1699*0fca6ea1SDimitry Andric Operands.emplace_back(new OperandMatcher(*this, OpIdx, SymbolicName,
1700*0fca6ea1SDimitry Andric AllocatedTemporariesBaseID));
1701*0fca6ea1SDimitry Andric if (!SymbolicName.empty())
1702*0fca6ea1SDimitry Andric Rule.defineOperand(SymbolicName, *Operands.back());
1703*0fca6ea1SDimitry Andric
1704*0fca6ea1SDimitry Andric return *Operands.back();
1705*0fca6ea1SDimitry Andric }
1706*0fca6ea1SDimitry Andric
getOperand(unsigned OpIdx)1707*0fca6ea1SDimitry Andric OperandMatcher &InstructionMatcher::getOperand(unsigned OpIdx) {
1708*0fca6ea1SDimitry Andric auto I = llvm::find_if(Operands,
1709*0fca6ea1SDimitry Andric [&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
1710*0fca6ea1SDimitry Andric return X->getOpIdx() == OpIdx;
1711*0fca6ea1SDimitry Andric });
1712*0fca6ea1SDimitry Andric if (I != Operands.end())
1713*0fca6ea1SDimitry Andric return **I;
1714*0fca6ea1SDimitry Andric llvm_unreachable("Failed to lookup operand");
1715*0fca6ea1SDimitry Andric }
1716*0fca6ea1SDimitry Andric
addPhysRegInput(Record * Reg,unsigned OpIdx,unsigned TempOpIdx)1717*0fca6ea1SDimitry Andric OperandMatcher &InstructionMatcher::addPhysRegInput(Record *Reg, unsigned OpIdx,
1718*0fca6ea1SDimitry Andric unsigned TempOpIdx) {
1719*0fca6ea1SDimitry Andric assert(SymbolicName.empty());
1720*0fca6ea1SDimitry Andric OperandMatcher *OM = new OperandMatcher(*this, OpIdx, "", TempOpIdx);
1721*0fca6ea1SDimitry Andric Operands.emplace_back(OM);
1722*0fca6ea1SDimitry Andric Rule.definePhysRegOperand(Reg, *OM);
1723*0fca6ea1SDimitry Andric PhysRegInputs.emplace_back(Reg, OpIdx);
1724*0fca6ea1SDimitry Andric return *OM;
1725*0fca6ea1SDimitry Andric }
1726*0fca6ea1SDimitry Andric
emitPredicateOpcodes(MatchTable & Table,RuleMatcher & Rule)1727*0fca6ea1SDimitry Andric void InstructionMatcher::emitPredicateOpcodes(MatchTable &Table,
1728*0fca6ea1SDimitry Andric RuleMatcher &Rule) {
1729*0fca6ea1SDimitry Andric if (NumOperandsCheck)
1730*0fca6ea1SDimitry Andric InstructionNumOperandsMatcher(InsnVarID, getNumOperands())
1731*0fca6ea1SDimitry Andric .emitPredicateOpcodes(Table, Rule);
1732*0fca6ea1SDimitry Andric
1733*0fca6ea1SDimitry Andric // First emit all instruction level predicates need to be verified before we
1734*0fca6ea1SDimitry Andric // can verify operands.
1735*0fca6ea1SDimitry Andric emitFilteredPredicateListOpcodes(
1736*0fca6ea1SDimitry Andric [](const PredicateMatcher &P) { return !P.dependsOnOperands(); }, Table,
1737*0fca6ea1SDimitry Andric Rule);
1738*0fca6ea1SDimitry Andric
1739*0fca6ea1SDimitry Andric // Emit all operand constraints.
1740*0fca6ea1SDimitry Andric for (const auto &Operand : Operands)
1741*0fca6ea1SDimitry Andric Operand->emitPredicateOpcodes(Table, Rule);
1742*0fca6ea1SDimitry Andric
1743*0fca6ea1SDimitry Andric // All of the tablegen defined predicates should now be matched. Now emit
1744*0fca6ea1SDimitry Andric // any custom predicates that rely on all generated checks.
1745*0fca6ea1SDimitry Andric emitFilteredPredicateListOpcodes(
1746*0fca6ea1SDimitry Andric [](const PredicateMatcher &P) { return P.dependsOnOperands(); }, Table,
1747*0fca6ea1SDimitry Andric Rule);
1748*0fca6ea1SDimitry Andric }
1749*0fca6ea1SDimitry Andric
isHigherPriorityThan(InstructionMatcher & B)1750*0fca6ea1SDimitry Andric bool InstructionMatcher::isHigherPriorityThan(InstructionMatcher &B) {
1751*0fca6ea1SDimitry Andric // Instruction matchers involving more operands have higher priority.
1752*0fca6ea1SDimitry Andric if (Operands.size() > B.Operands.size())
1753*0fca6ea1SDimitry Andric return true;
1754*0fca6ea1SDimitry Andric if (Operands.size() < B.Operands.size())
1755*0fca6ea1SDimitry Andric return false;
1756*0fca6ea1SDimitry Andric
1757*0fca6ea1SDimitry Andric for (auto &&P : zip(predicates(), B.predicates())) {
1758*0fca6ea1SDimitry Andric auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get());
1759*0fca6ea1SDimitry Andric auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get());
1760*0fca6ea1SDimitry Andric if (L->isHigherPriorityThan(*R))
1761*0fca6ea1SDimitry Andric return true;
1762*0fca6ea1SDimitry Andric if (R->isHigherPriorityThan(*L))
1763*0fca6ea1SDimitry Andric return false;
1764*0fca6ea1SDimitry Andric }
1765*0fca6ea1SDimitry Andric
1766*0fca6ea1SDimitry Andric for (auto Operand : zip(Operands, B.Operands)) {
1767*0fca6ea1SDimitry Andric if (std::get<0>(Operand)->isHigherPriorityThan(*std::get<1>(Operand)))
1768*0fca6ea1SDimitry Andric return true;
1769*0fca6ea1SDimitry Andric if (std::get<1>(Operand)->isHigherPriorityThan(*std::get<0>(Operand)))
1770*0fca6ea1SDimitry Andric return false;
1771*0fca6ea1SDimitry Andric }
1772*0fca6ea1SDimitry Andric
1773*0fca6ea1SDimitry Andric return false;
1774*0fca6ea1SDimitry Andric }
1775*0fca6ea1SDimitry Andric
countRendererFns()1776*0fca6ea1SDimitry Andric unsigned InstructionMatcher::countRendererFns() {
1777*0fca6ea1SDimitry Andric return std::accumulate(
1778*0fca6ea1SDimitry Andric predicates().begin(), predicates().end(), 0,
1779*0fca6ea1SDimitry Andric [](unsigned A,
1780*0fca6ea1SDimitry Andric const std::unique_ptr<PredicateMatcher> &Predicate) {
1781*0fca6ea1SDimitry Andric return A + Predicate->countRendererFns();
1782*0fca6ea1SDimitry Andric }) +
1783*0fca6ea1SDimitry Andric std::accumulate(
1784*0fca6ea1SDimitry Andric Operands.begin(), Operands.end(), 0,
1785*0fca6ea1SDimitry Andric [](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) {
1786*0fca6ea1SDimitry Andric return A + Operand->countRendererFns();
1787*0fca6ea1SDimitry Andric });
1788*0fca6ea1SDimitry Andric }
1789*0fca6ea1SDimitry Andric
optimize()1790*0fca6ea1SDimitry Andric void InstructionMatcher::optimize() {
1791*0fca6ea1SDimitry Andric SmallVector<std::unique_ptr<PredicateMatcher>, 8> Stash;
1792*0fca6ea1SDimitry Andric const auto &OpcMatcher = getOpcodeMatcher();
1793*0fca6ea1SDimitry Andric
1794*0fca6ea1SDimitry Andric Stash.push_back(predicates_pop_front());
1795*0fca6ea1SDimitry Andric if (Stash.back().get() == &OpcMatcher) {
1796*0fca6ea1SDimitry Andric if (NumOperandsCheck && OpcMatcher.isVariadicNumOperands() &&
1797*0fca6ea1SDimitry Andric getNumOperands() != 0)
1798*0fca6ea1SDimitry Andric Stash.emplace_back(
1799*0fca6ea1SDimitry Andric new InstructionNumOperandsMatcher(InsnVarID, getNumOperands()));
1800*0fca6ea1SDimitry Andric NumOperandsCheck = false;
1801*0fca6ea1SDimitry Andric
1802*0fca6ea1SDimitry Andric for (auto &OM : Operands)
1803*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
1804*0fca6ea1SDimitry Andric if (isa<IntrinsicIDOperandMatcher>(OP)) {
1805*0fca6ea1SDimitry Andric Stash.push_back(std::move(OP));
1806*0fca6ea1SDimitry Andric OM->eraseNullPredicates();
1807*0fca6ea1SDimitry Andric break;
1808*0fca6ea1SDimitry Andric }
1809*0fca6ea1SDimitry Andric }
1810*0fca6ea1SDimitry Andric
1811*0fca6ea1SDimitry Andric if (InsnVarID > 0) {
1812*0fca6ea1SDimitry Andric assert(!Operands.empty() && "Nested instruction is expected to def a vreg");
1813*0fca6ea1SDimitry Andric for (auto &OP : Operands[0]->predicates())
1814*0fca6ea1SDimitry Andric OP.reset();
1815*0fca6ea1SDimitry Andric Operands[0]->eraseNullPredicates();
1816*0fca6ea1SDimitry Andric }
1817*0fca6ea1SDimitry Andric for (auto &OM : Operands) {
1818*0fca6ea1SDimitry Andric for (auto &OP : OM->predicates())
1819*0fca6ea1SDimitry Andric if (isa<LLTOperandMatcher>(OP))
1820*0fca6ea1SDimitry Andric Stash.push_back(std::move(OP));
1821*0fca6ea1SDimitry Andric OM->eraseNullPredicates();
1822*0fca6ea1SDimitry Andric }
1823*0fca6ea1SDimitry Andric while (!Stash.empty())
1824*0fca6ea1SDimitry Andric prependPredicate(Stash.pop_back_val());
1825*0fca6ea1SDimitry Andric }
1826*0fca6ea1SDimitry Andric
1827*0fca6ea1SDimitry Andric //===- InstructionOperandMatcher ------------------------------------------===//
1828*0fca6ea1SDimitry Andric
emitCaptureOpcodes(MatchTable & Table,RuleMatcher & Rule) const1829*0fca6ea1SDimitry Andric void InstructionOperandMatcher::emitCaptureOpcodes(MatchTable &Table,
1830*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1831*0fca6ea1SDimitry Andric const unsigned NewInsnVarID = InsnMatcher->getInsnVarID();
1832*0fca6ea1SDimitry Andric const bool IgnoreCopies = Flags & GISF_IgnoreCopies;
1833*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(IgnoreCopies ? "GIM_RecordInsnIgnoreCopies"
1834*0fca6ea1SDimitry Andric : "GIM_RecordInsn")
1835*0fca6ea1SDimitry Andric << MatchTable::Comment("DefineMI")
1836*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnVarID) << MatchTable::Comment("MI")
1837*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(getInsnVarID())
1838*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(getOpIdx())
1839*0fca6ea1SDimitry Andric << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")
1840*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
1841*0fca6ea1SDimitry Andric }
1842*0fca6ea1SDimitry Andric
isHigherPriorityThan(const OperandPredicateMatcher & B) const1843*0fca6ea1SDimitry Andric bool InstructionOperandMatcher::isHigherPriorityThan(
1844*0fca6ea1SDimitry Andric const OperandPredicateMatcher &B) const {
1845*0fca6ea1SDimitry Andric if (OperandPredicateMatcher::isHigherPriorityThan(B))
1846*0fca6ea1SDimitry Andric return true;
1847*0fca6ea1SDimitry Andric if (B.OperandPredicateMatcher::isHigherPriorityThan(*this))
1848*0fca6ea1SDimitry Andric return false;
1849*0fca6ea1SDimitry Andric
1850*0fca6ea1SDimitry Andric if (const InstructionOperandMatcher *BP =
1851*0fca6ea1SDimitry Andric dyn_cast<InstructionOperandMatcher>(&B))
1852*0fca6ea1SDimitry Andric if (InsnMatcher->isHigherPriorityThan(*BP->InsnMatcher))
1853*0fca6ea1SDimitry Andric return true;
1854*0fca6ea1SDimitry Andric return false;
1855*0fca6ea1SDimitry Andric }
1856*0fca6ea1SDimitry Andric
1857*0fca6ea1SDimitry Andric //===- OperandRenderer ----------------------------------------------------===//
1858*0fca6ea1SDimitry Andric
~OperandRenderer()1859*0fca6ea1SDimitry Andric OperandRenderer::~OperandRenderer() {}
1860*0fca6ea1SDimitry Andric
1861*0fca6ea1SDimitry Andric //===- CopyRenderer -------------------------------------------------------===//
1862*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule,unsigned NewInsnID,unsigned OldInsnID,unsigned OpIdx,StringRef Name)1863*0fca6ea1SDimitry Andric void CopyRenderer::emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule,
1864*0fca6ea1SDimitry Andric unsigned NewInsnID, unsigned OldInsnID,
1865*0fca6ea1SDimitry Andric unsigned OpIdx, StringRef Name) {
1866*0fca6ea1SDimitry Andric if (NewInsnID == 0 && OldInsnID == 0) {
1867*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_RootToRootCopy");
1868*0fca6ea1SDimitry Andric } else {
1869*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
1870*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnID)
1871*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
1872*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnID);
1873*0fca6ea1SDimitry Andric }
1874*0fca6ea1SDimitry Andric
1875*0fca6ea1SDimitry Andric Table << MatchTable::Comment("OpIdx") << MatchTable::ULEB128Value(OpIdx)
1876*0fca6ea1SDimitry Andric << MatchTable::Comment(Name) << MatchTable::LineBreak;
1877*0fca6ea1SDimitry Andric }
1878*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1879*0fca6ea1SDimitry Andric void CopyRenderer::emitRenderOpcodes(MatchTable &Table,
1880*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1881*0fca6ea1SDimitry Andric const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
1882*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
1883*0fca6ea1SDimitry Andric emitRenderOpcodes(Table, Rule, NewInsnID, OldInsnVarID, Operand.getOpIdx(),
1884*0fca6ea1SDimitry Andric SymbolicName);
1885*0fca6ea1SDimitry Andric }
1886*0fca6ea1SDimitry Andric
1887*0fca6ea1SDimitry Andric //===- CopyPhysRegRenderer ------------------------------------------------===//
1888*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1889*0fca6ea1SDimitry Andric void CopyPhysRegRenderer::emitRenderOpcodes(MatchTable &Table,
1890*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1891*0fca6ea1SDimitry Andric const OperandMatcher &Operand = Rule.getPhysRegOperandMatcher(PhysReg);
1892*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
1893*0fca6ea1SDimitry Andric CopyRenderer::emitRenderOpcodes(Table, Rule, NewInsnID, OldInsnVarID,
1894*0fca6ea1SDimitry Andric Operand.getOpIdx(), PhysReg->getName());
1895*0fca6ea1SDimitry Andric }
1896*0fca6ea1SDimitry Andric
1897*0fca6ea1SDimitry Andric //===- CopyOrAddZeroRegRenderer -------------------------------------------===//
1898*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1899*0fca6ea1SDimitry Andric void CopyOrAddZeroRegRenderer::emitRenderOpcodes(MatchTable &Table,
1900*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1901*0fca6ea1SDimitry Andric const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
1902*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
1903*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CopyOrAddZeroReg")
1904*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnID")
1905*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnID)
1906*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
1907*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnVarID)
1908*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx")
1909*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(Operand.getOpIdx())
1910*0fca6ea1SDimitry Andric << MatchTable::NamedValue(
1911*0fca6ea1SDimitry Andric 2,
1912*0fca6ea1SDimitry Andric (ZeroRegisterDef->getValue("Namespace")
1913*0fca6ea1SDimitry Andric ? ZeroRegisterDef->getValueAsString("Namespace")
1914*0fca6ea1SDimitry Andric : ""),
1915*0fca6ea1SDimitry Andric ZeroRegisterDef->getName())
1916*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
1917*0fca6ea1SDimitry Andric }
1918*0fca6ea1SDimitry Andric
1919*0fca6ea1SDimitry Andric //===- CopyConstantAsImmRenderer ------------------------------------------===//
1920*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1921*0fca6ea1SDimitry Andric void CopyConstantAsImmRenderer::emitRenderOpcodes(MatchTable &Table,
1922*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1923*0fca6ea1SDimitry Andric InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
1924*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
1925*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"
1926*0fca6ea1SDimitry Andric : "GIR_CopyConstantAsUImm")
1927*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnID")
1928*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnID)
1929*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
1930*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnVarID)
1931*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
1932*0fca6ea1SDimitry Andric }
1933*0fca6ea1SDimitry Andric
1934*0fca6ea1SDimitry Andric //===- CopyFConstantAsFPImmRenderer ---------------------------------------===//
1935*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1936*0fca6ea1SDimitry Andric void CopyFConstantAsFPImmRenderer::emitRenderOpcodes(MatchTable &Table,
1937*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1938*0fca6ea1SDimitry Andric InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
1939*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
1940*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")
1941*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnID")
1942*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnID)
1943*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
1944*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnVarID)
1945*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
1946*0fca6ea1SDimitry Andric }
1947*0fca6ea1SDimitry Andric
1948*0fca6ea1SDimitry Andric //===- CopySubRegRenderer -------------------------------------------------===//
1949*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1950*0fca6ea1SDimitry Andric void CopySubRegRenderer::emitRenderOpcodes(MatchTable &Table,
1951*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1952*0fca6ea1SDimitry Andric const OperandMatcher &Operand = Rule.getOperandMatcher(SymbolicName);
1953*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher());
1954*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CopySubReg")
1955*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnID")
1956*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnID)
1957*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
1958*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnVarID)
1959*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx")
1960*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(Operand.getOpIdx())
1961*0fca6ea1SDimitry Andric << MatchTable::Comment("SubRegIdx")
1962*0fca6ea1SDimitry Andric << MatchTable::IntValue(2, SubReg->EnumValue)
1963*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
1964*0fca6ea1SDimitry Andric }
1965*0fca6ea1SDimitry Andric
1966*0fca6ea1SDimitry Andric //===- AddRegisterRenderer ------------------------------------------------===//
1967*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1968*0fca6ea1SDimitry Andric void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
1969*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1970*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddRegister")
1971*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID);
1972*0fca6ea1SDimitry Andric if (RegisterDef->getName() != "zero_reg") {
1973*0fca6ea1SDimitry Andric Table << MatchTable::NamedValue(
1974*0fca6ea1SDimitry Andric 2,
1975*0fca6ea1SDimitry Andric (RegisterDef->getValue("Namespace")
1976*0fca6ea1SDimitry Andric ? RegisterDef->getValueAsString("Namespace")
1977*0fca6ea1SDimitry Andric : ""),
1978*0fca6ea1SDimitry Andric RegisterDef->getName());
1979*0fca6ea1SDimitry Andric } else {
1980*0fca6ea1SDimitry Andric Table << MatchTable::NamedValue(2, Target.getRegNamespace(), "NoRegister");
1981*0fca6ea1SDimitry Andric }
1982*0fca6ea1SDimitry Andric Table << MatchTable::Comment("AddRegisterRegFlags");
1983*0fca6ea1SDimitry Andric
1984*0fca6ea1SDimitry Andric // TODO: This is encoded as a 64-bit element, but only 16 or 32-bits are
1985*0fca6ea1SDimitry Andric // really needed for a physical register reference. We can pack the
1986*0fca6ea1SDimitry Andric // register and flags in a single field.
1987*0fca6ea1SDimitry Andric if (IsDef)
1988*0fca6ea1SDimitry Andric Table << MatchTable::NamedValue(2, "RegState::Define");
1989*0fca6ea1SDimitry Andric else
1990*0fca6ea1SDimitry Andric Table << MatchTable::IntValue(2, 0);
1991*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
1992*0fca6ea1SDimitry Andric }
1993*0fca6ea1SDimitry Andric
1994*0fca6ea1SDimitry Andric //===- TempRegRenderer ----------------------------------------------------===//
1995*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const1996*0fca6ea1SDimitry Andric void TempRegRenderer::emitRenderOpcodes(MatchTable &Table,
1997*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
1998*0fca6ea1SDimitry Andric const bool NeedsFlags = (SubRegIdx || IsDef);
1999*0fca6ea1SDimitry Andric if (SubRegIdx) {
2000*0fca6ea1SDimitry Andric assert(!IsDef);
2001*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddTempSubRegister");
2002*0fca6ea1SDimitry Andric } else
2003*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(NeedsFlags ? "GIR_AddTempRegister"
2004*0fca6ea1SDimitry Andric : "GIR_AddSimpleTempRegister");
2005*0fca6ea1SDimitry Andric
2006*0fca6ea1SDimitry Andric Table << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2007*0fca6ea1SDimitry Andric << MatchTable::Comment("TempRegID")
2008*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(TempRegID);
2009*0fca6ea1SDimitry Andric
2010*0fca6ea1SDimitry Andric if (!NeedsFlags) {
2011*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
2012*0fca6ea1SDimitry Andric return;
2013*0fca6ea1SDimitry Andric }
2014*0fca6ea1SDimitry Andric
2015*0fca6ea1SDimitry Andric Table << MatchTable::Comment("TempRegFlags");
2016*0fca6ea1SDimitry Andric if (IsDef) {
2017*0fca6ea1SDimitry Andric SmallString<32> RegFlags;
2018*0fca6ea1SDimitry Andric RegFlags += "RegState::Define";
2019*0fca6ea1SDimitry Andric if (IsDead)
2020*0fca6ea1SDimitry Andric RegFlags += "|RegState::Dead";
2021*0fca6ea1SDimitry Andric Table << MatchTable::NamedValue(2, RegFlags);
2022*0fca6ea1SDimitry Andric } else
2023*0fca6ea1SDimitry Andric Table << MatchTable::IntValue(2, 0);
2024*0fca6ea1SDimitry Andric
2025*0fca6ea1SDimitry Andric if (SubRegIdx)
2026*0fca6ea1SDimitry Andric Table << MatchTable::NamedValue(2, SubRegIdx->getQualifiedName());
2027*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
2028*0fca6ea1SDimitry Andric }
2029*0fca6ea1SDimitry Andric
2030*0fca6ea1SDimitry Andric //===- ImmRenderer --------------------------------------------------------===//
2031*0fca6ea1SDimitry Andric
emitAddImm(MatchTable & Table,RuleMatcher & RM,unsigned InsnID,int64_t Imm,StringRef ImmName)2032*0fca6ea1SDimitry Andric void ImmRenderer::emitAddImm(MatchTable &Table, RuleMatcher &RM,
2033*0fca6ea1SDimitry Andric unsigned InsnID, int64_t Imm, StringRef ImmName) {
2034*0fca6ea1SDimitry Andric const bool IsInt8 = isInt<8>(Imm);
2035*0fca6ea1SDimitry Andric
2036*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(IsInt8 ? "GIR_AddImm8" : "GIR_AddImm")
2037*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2038*0fca6ea1SDimitry Andric << MatchTable::Comment(ImmName)
2039*0fca6ea1SDimitry Andric << MatchTable::IntValue(IsInt8 ? 1 : 8, Imm) << MatchTable::LineBreak;
2040*0fca6ea1SDimitry Andric }
2041*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2042*0fca6ea1SDimitry Andric void ImmRenderer::emitRenderOpcodes(MatchTable &Table,
2043*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2044*0fca6ea1SDimitry Andric if (CImmLLT) {
2045*0fca6ea1SDimitry Andric assert(Table.isCombiner() &&
2046*0fca6ea1SDimitry Andric "ConstantInt immediate are only for combiners!");
2047*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddCImm") << MatchTable::Comment("InsnID")
2048*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnID) << MatchTable::Comment("Type")
2049*0fca6ea1SDimitry Andric << *CImmLLT << MatchTable::Comment("Imm")
2050*0fca6ea1SDimitry Andric << MatchTable::IntValue(8, Imm) << MatchTable::LineBreak;
2051*0fca6ea1SDimitry Andric } else
2052*0fca6ea1SDimitry Andric emitAddImm(Table, Rule, InsnID, Imm);
2053*0fca6ea1SDimitry Andric }
2054*0fca6ea1SDimitry Andric
2055*0fca6ea1SDimitry Andric //===- SubRegIndexRenderer ------------------------------------------------===//
2056*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2057*0fca6ea1SDimitry Andric void SubRegIndexRenderer::emitRenderOpcodes(MatchTable &Table,
2058*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2059*0fca6ea1SDimitry Andric ImmRenderer::emitAddImm(Table, Rule, InsnID, SubRegIdx->EnumValue,
2060*0fca6ea1SDimitry Andric "SubRegIndex");
2061*0fca6ea1SDimitry Andric }
2062*0fca6ea1SDimitry Andric
2063*0fca6ea1SDimitry Andric //===- RenderComplexPatternOperand ----------------------------------------===//
2064*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2065*0fca6ea1SDimitry Andric void RenderComplexPatternOperand::emitRenderOpcodes(MatchTable &Table,
2066*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2067*0fca6ea1SDimitry Andric Table << MatchTable::Opcode(
2068*0fca6ea1SDimitry Andric SubOperand ? (SubReg ? "GIR_ComplexSubOperandSubRegRenderer"
2069*0fca6ea1SDimitry Andric : "GIR_ComplexSubOperandRenderer")
2070*0fca6ea1SDimitry Andric : "GIR_ComplexRenderer")
2071*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2072*0fca6ea1SDimitry Andric << MatchTable::Comment("RendererID")
2073*0fca6ea1SDimitry Andric << MatchTable::IntValue(2, RendererID);
2074*0fca6ea1SDimitry Andric if (SubOperand)
2075*0fca6ea1SDimitry Andric Table << MatchTable::Comment("SubOperand")
2076*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(*SubOperand);
2077*0fca6ea1SDimitry Andric if (SubReg)
2078*0fca6ea1SDimitry Andric Table << MatchTable::Comment("SubRegIdx")
2079*0fca6ea1SDimitry Andric << MatchTable::IntValue(2, SubReg->EnumValue);
2080*0fca6ea1SDimitry Andric Table << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
2081*0fca6ea1SDimitry Andric }
2082*0fca6ea1SDimitry Andric
2083*0fca6ea1SDimitry Andric //===- IntrinsicIDRenderer ------------------------------------------------===//
2084*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2085*0fca6ea1SDimitry Andric void IntrinsicIDRenderer::emitRenderOpcodes(MatchTable &Table,
2086*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2087*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddIntrinsicID") << MatchTable::Comment("MI")
2088*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnID)
2089*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, "Intrinsic::" + II->EnumName)
2090*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2091*0fca6ea1SDimitry Andric }
2092*0fca6ea1SDimitry Andric
2093*0fca6ea1SDimitry Andric //===- CustomRenderer -----------------------------------------------------===//
2094*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2095*0fca6ea1SDimitry Andric void CustomRenderer::emitRenderOpcodes(MatchTable &Table,
2096*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2097*0fca6ea1SDimitry Andric InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
2098*0fca6ea1SDimitry Andric unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
2099*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CustomRenderer")
2100*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2101*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2102*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnVarID)
2103*0fca6ea1SDimitry Andric << MatchTable::Comment("Renderer")
2104*0fca6ea1SDimitry Andric << MatchTable::NamedValue(
2105*0fca6ea1SDimitry Andric 2, "GICR_" + Renderer.getValueAsString("RendererFn").str())
2106*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
2107*0fca6ea1SDimitry Andric }
2108*0fca6ea1SDimitry Andric
2109*0fca6ea1SDimitry Andric //===- CustomOperandRenderer ----------------------------------------------===//
2110*0fca6ea1SDimitry Andric
emitRenderOpcodes(MatchTable & Table,RuleMatcher & Rule) const2111*0fca6ea1SDimitry Andric void CustomOperandRenderer::emitRenderOpcodes(MatchTable &Table,
2112*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2113*0fca6ea1SDimitry Andric const OperandMatcher &OpdMatcher = Rule.getOperandMatcher(SymbolicName);
2114*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CustomOperandRenderer")
2115*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2116*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2117*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpdMatcher.getInsnVarID())
2118*0fca6ea1SDimitry Andric << MatchTable::Comment("OpIdx")
2119*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpdMatcher.getOpIdx())
2120*0fca6ea1SDimitry Andric << MatchTable::Comment("OperandRenderer")
2121*0fca6ea1SDimitry Andric << MatchTable::NamedValue(
2122*0fca6ea1SDimitry Andric 2, "GICR_" + Renderer.getValueAsString("RendererFn").str())
2123*0fca6ea1SDimitry Andric << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
2124*0fca6ea1SDimitry Andric }
2125*0fca6ea1SDimitry Andric
2126*0fca6ea1SDimitry Andric //===- BuildMIAction ------------------------------------------------------===//
2127*0fca6ea1SDimitry Andric
canMutate(RuleMatcher & Rule,const InstructionMatcher * Insn) const2128*0fca6ea1SDimitry Andric bool BuildMIAction::canMutate(RuleMatcher &Rule,
2129*0fca6ea1SDimitry Andric const InstructionMatcher *Insn) const {
2130*0fca6ea1SDimitry Andric if (!Insn)
2131*0fca6ea1SDimitry Andric return false;
2132*0fca6ea1SDimitry Andric
2133*0fca6ea1SDimitry Andric if (OperandRenderers.size() != Insn->getNumOperands())
2134*0fca6ea1SDimitry Andric return false;
2135*0fca6ea1SDimitry Andric
2136*0fca6ea1SDimitry Andric for (const auto &Renderer : enumerate(OperandRenderers)) {
2137*0fca6ea1SDimitry Andric if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
2138*0fca6ea1SDimitry Andric const OperandMatcher &OM =
2139*0fca6ea1SDimitry Andric Rule.getOperandMatcher(Copy->getSymbolicName());
2140*0fca6ea1SDimitry Andric if (Insn != &OM.getInstructionMatcher() ||
2141*0fca6ea1SDimitry Andric OM.getOpIdx() != Renderer.index())
2142*0fca6ea1SDimitry Andric return false;
2143*0fca6ea1SDimitry Andric } else
2144*0fca6ea1SDimitry Andric return false;
2145*0fca6ea1SDimitry Andric }
2146*0fca6ea1SDimitry Andric
2147*0fca6ea1SDimitry Andric return true;
2148*0fca6ea1SDimitry Andric }
2149*0fca6ea1SDimitry Andric
chooseInsnToMutate(RuleMatcher & Rule)2150*0fca6ea1SDimitry Andric void BuildMIAction::chooseInsnToMutate(RuleMatcher &Rule) {
2151*0fca6ea1SDimitry Andric for (auto *MutateCandidate : Rule.mutatable_insns()) {
2152*0fca6ea1SDimitry Andric if (canMutate(Rule, MutateCandidate)) {
2153*0fca6ea1SDimitry Andric // Take the first one we're offered that we're able to mutate.
2154*0fca6ea1SDimitry Andric Rule.reserveInsnMatcherForMutation(MutateCandidate);
2155*0fca6ea1SDimitry Andric Matched = MutateCandidate;
2156*0fca6ea1SDimitry Andric return;
2157*0fca6ea1SDimitry Andric }
2158*0fca6ea1SDimitry Andric }
2159*0fca6ea1SDimitry Andric }
2160*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2161*0fca6ea1SDimitry Andric void BuildMIAction::emitActionOpcodes(MatchTable &Table,
2162*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2163*0fca6ea1SDimitry Andric const auto AddMIFlags = [&]() {
2164*0fca6ea1SDimitry Andric for (const InstructionMatcher *IM : CopiedFlags) {
2165*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_CopyMIFlags")
2166*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2167*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2168*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(IM->getInsnVarID())
2169*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2170*0fca6ea1SDimitry Andric }
2171*0fca6ea1SDimitry Andric
2172*0fca6ea1SDimitry Andric if (!SetFlags.empty()) {
2173*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_SetMIFlags")
2174*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2175*0fca6ea1SDimitry Andric << MatchTable::NamedValue(4, join(SetFlags, " | "))
2176*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2177*0fca6ea1SDimitry Andric }
2178*0fca6ea1SDimitry Andric
2179*0fca6ea1SDimitry Andric if (!UnsetFlags.empty()) {
2180*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_UnsetMIFlags")
2181*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2182*0fca6ea1SDimitry Andric << MatchTable::NamedValue(4, join(UnsetFlags, " | "))
2183*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2184*0fca6ea1SDimitry Andric }
2185*0fca6ea1SDimitry Andric };
2186*0fca6ea1SDimitry Andric
2187*0fca6ea1SDimitry Andric if (Matched) {
2188*0fca6ea1SDimitry Andric assert(canMutate(Rule, Matched) &&
2189*0fca6ea1SDimitry Andric "Arranged to mutate an insn that isn't mutatable");
2190*0fca6ea1SDimitry Andric
2191*0fca6ea1SDimitry Andric unsigned RecycleInsnID = Rule.getInsnVarID(*Matched);
2192*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_MutateOpcode")
2193*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2194*0fca6ea1SDimitry Andric << MatchTable::Comment("RecycleInsnID")
2195*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(RecycleInsnID)
2196*0fca6ea1SDimitry Andric << MatchTable::Comment("Opcode")
2197*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())
2198*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2199*0fca6ea1SDimitry Andric
2200*0fca6ea1SDimitry Andric if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) {
2201*0fca6ea1SDimitry Andric for (auto *Def : I->ImplicitDefs) {
2202*0fca6ea1SDimitry Andric auto Namespace = Def->getValue("Namespace")
2203*0fca6ea1SDimitry Andric ? Def->getValueAsString("Namespace")
2204*0fca6ea1SDimitry Andric : "";
2205*0fca6ea1SDimitry Andric const bool IsDead = DeadImplicitDefs.contains(Def);
2206*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddImplicitDef")
2207*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID")
2208*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnID)
2209*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, Namespace, Def->getName())
2210*0fca6ea1SDimitry Andric << (IsDead ? MatchTable::NamedValue(2, "RegState", "Dead")
2211*0fca6ea1SDimitry Andric : MatchTable::IntValue(2, 0))
2212*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2213*0fca6ea1SDimitry Andric }
2214*0fca6ea1SDimitry Andric for (auto *Use : I->ImplicitUses) {
2215*0fca6ea1SDimitry Andric auto Namespace = Use->getValue("Namespace")
2216*0fca6ea1SDimitry Andric ? Use->getValueAsString("Namespace")
2217*0fca6ea1SDimitry Andric : "";
2218*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_AddImplicitUse")
2219*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID")
2220*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnID)
2221*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, Namespace, Use->getName())
2222*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2223*0fca6ea1SDimitry Andric }
2224*0fca6ea1SDimitry Andric }
2225*0fca6ea1SDimitry Andric
2226*0fca6ea1SDimitry Andric AddMIFlags();
2227*0fca6ea1SDimitry Andric
2228*0fca6ea1SDimitry Andric // Mark the mutated instruction as erased.
2229*0fca6ea1SDimitry Andric Rule.tryEraseInsnID(RecycleInsnID);
2230*0fca6ea1SDimitry Andric return;
2231*0fca6ea1SDimitry Andric }
2232*0fca6ea1SDimitry Andric
2233*0fca6ea1SDimitry Andric // TODO: Simple permutation looks like it could be almost as common as
2234*0fca6ea1SDimitry Andric // mutation due to commutative operations.
2235*0fca6ea1SDimitry Andric
2236*0fca6ea1SDimitry Andric if (InsnID == 0) {
2237*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_BuildRootMI");
2238*0fca6ea1SDimitry Andric } else {
2239*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID")
2240*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(InsnID);
2241*0fca6ea1SDimitry Andric }
2242*0fca6ea1SDimitry Andric
2243*0fca6ea1SDimitry Andric Table << MatchTable::Comment("Opcode")
2244*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, I->Namespace, I->TheDef->getName())
2245*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2246*0fca6ea1SDimitry Andric
2247*0fca6ea1SDimitry Andric for (const auto &Renderer : OperandRenderers)
2248*0fca6ea1SDimitry Andric Renderer->emitRenderOpcodes(Table, Rule);
2249*0fca6ea1SDimitry Andric
2250*0fca6ea1SDimitry Andric for (auto [OpIdx, Def] : enumerate(I->ImplicitDefs)) {
2251*0fca6ea1SDimitry Andric auto Namespace =
2252*0fca6ea1SDimitry Andric Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : "";
2253*0fca6ea1SDimitry Andric if (DeadImplicitDefs.contains(Def)) {
2254*0fca6ea1SDimitry Andric Table
2255*0fca6ea1SDimitry Andric << MatchTable::Opcode("GIR_SetImplicitDefDead")
2256*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2257*0fca6ea1SDimitry Andric << MatchTable::Comment(
2258*0fca6ea1SDimitry Andric ("OpIdx for " + Namespace + "::" + Def->getName() + "").str())
2259*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OpIdx) << MatchTable::LineBreak;
2260*0fca6ea1SDimitry Andric }
2261*0fca6ea1SDimitry Andric }
2262*0fca6ea1SDimitry Andric
2263*0fca6ea1SDimitry Andric if (I->mayLoad || I->mayStore) {
2264*0fca6ea1SDimitry Andric // Emit the ID's for all the instructions that are matched by this rule.
2265*0fca6ea1SDimitry Andric // TODO: Limit this to matched instructions that mayLoad/mayStore or have
2266*0fca6ea1SDimitry Andric // some other means of having a memoperand. Also limit this to
2267*0fca6ea1SDimitry Andric // emitted instructions that expect to have a memoperand too. For
2268*0fca6ea1SDimitry Andric // example, (G_SEXT (G_LOAD x)) that results in separate load and
2269*0fca6ea1SDimitry Andric // sign-extend instructions shouldn't put the memoperand on the
2270*0fca6ea1SDimitry Andric // sign-extend since it has no effect there.
2271*0fca6ea1SDimitry Andric
2272*0fca6ea1SDimitry Andric std::vector<unsigned> MergeInsnIDs;
2273*0fca6ea1SDimitry Andric for (const auto &IDMatcherPair : Rule.defined_insn_vars())
2274*0fca6ea1SDimitry Andric MergeInsnIDs.push_back(IDMatcherPair.second);
2275*0fca6ea1SDimitry Andric llvm::sort(MergeInsnIDs);
2276*0fca6ea1SDimitry Andric
2277*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_MergeMemOperands")
2278*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2279*0fca6ea1SDimitry Andric << MatchTable::Comment("NumInsns")
2280*0fca6ea1SDimitry Andric << MatchTable::IntValue(1, MergeInsnIDs.size())
2281*0fca6ea1SDimitry Andric << MatchTable::Comment("MergeInsnID's");
2282*0fca6ea1SDimitry Andric for (const auto &MergeInsnID : MergeInsnIDs)
2283*0fca6ea1SDimitry Andric Table << MatchTable::ULEB128Value(MergeInsnID);
2284*0fca6ea1SDimitry Andric Table << MatchTable::LineBreak;
2285*0fca6ea1SDimitry Andric }
2286*0fca6ea1SDimitry Andric
2287*0fca6ea1SDimitry Andric AddMIFlags();
2288*0fca6ea1SDimitry Andric }
2289*0fca6ea1SDimitry Andric
2290*0fca6ea1SDimitry Andric //===- BuildConstantAction ------------------------------------------------===//
2291*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2292*0fca6ea1SDimitry Andric void BuildConstantAction::emitActionOpcodes(MatchTable &Table,
2293*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2294*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_BuildConstant")
2295*0fca6ea1SDimitry Andric << MatchTable::Comment("TempRegID")
2296*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("Val")
2297*0fca6ea1SDimitry Andric << MatchTable::IntValue(8, Val) << MatchTable::LineBreak;
2298*0fca6ea1SDimitry Andric }
2299*0fca6ea1SDimitry Andric
2300*0fca6ea1SDimitry Andric //===- EraseInstAction ----------------------------------------------------===//
2301*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2302*0fca6ea1SDimitry Andric void EraseInstAction::emitActionOpcodes(MatchTable &Table,
2303*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2304*0fca6ea1SDimitry Andric // Avoid erasing the same inst twice.
2305*0fca6ea1SDimitry Andric if (!Rule.tryEraseInsnID(InsnID))
2306*0fca6ea1SDimitry Andric return;
2307*0fca6ea1SDimitry Andric
2308*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_EraseFromParent")
2309*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2310*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2311*0fca6ea1SDimitry Andric }
2312*0fca6ea1SDimitry Andric
emitActionOpcodesAndDone(MatchTable & Table,RuleMatcher & Rule) const2313*0fca6ea1SDimitry Andric bool EraseInstAction::emitActionOpcodesAndDone(MatchTable &Table,
2314*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2315*0fca6ea1SDimitry Andric if (InsnID != 0) {
2316*0fca6ea1SDimitry Andric emitActionOpcodes(Table, Rule);
2317*0fca6ea1SDimitry Andric return false;
2318*0fca6ea1SDimitry Andric }
2319*0fca6ea1SDimitry Andric
2320*0fca6ea1SDimitry Andric if (!Rule.tryEraseInsnID(0))
2321*0fca6ea1SDimitry Andric return false;
2322*0fca6ea1SDimitry Andric
2323*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_EraseRootFromParent_Done", -1)
2324*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2325*0fca6ea1SDimitry Andric return true;
2326*0fca6ea1SDimitry Andric }
2327*0fca6ea1SDimitry Andric
2328*0fca6ea1SDimitry Andric //===- ReplaceRegAction ---------------------------------------------------===//
2329*0fca6ea1SDimitry Andric
emitAdditionalPredicates(MatchTable & Table,RuleMatcher & Rule) const2330*0fca6ea1SDimitry Andric void ReplaceRegAction::emitAdditionalPredicates(MatchTable &Table,
2331*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2332*0fca6ea1SDimitry Andric if (TempRegID != (unsigned)-1)
2333*0fca6ea1SDimitry Andric return;
2334*0fca6ea1SDimitry Andric
2335*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIM_CheckCanReplaceReg")
2336*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2337*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnID)
2338*0fca6ea1SDimitry Andric << MatchTable::Comment("OldOpIdx") << MatchTable::ULEB128Value(OldOpIdx)
2339*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnId")
2340*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnId)
2341*0fca6ea1SDimitry Andric << MatchTable::Comment("NewOpIdx") << MatchTable::ULEB128Value(NewOpIdx)
2342*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2343*0fca6ea1SDimitry Andric }
2344*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2345*0fca6ea1SDimitry Andric void ReplaceRegAction::emitActionOpcodes(MatchTable &Table,
2346*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2347*0fca6ea1SDimitry Andric if (TempRegID != (unsigned)-1) {
2348*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_ReplaceRegWithTempReg")
2349*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2350*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnID)
2351*0fca6ea1SDimitry Andric << MatchTable::Comment("OldOpIdx")
2352*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldOpIdx)
2353*0fca6ea1SDimitry Andric << MatchTable::Comment("TempRegID")
2354*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(TempRegID) << MatchTable::LineBreak;
2355*0fca6ea1SDimitry Andric } else {
2356*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_ReplaceReg")
2357*0fca6ea1SDimitry Andric << MatchTable::Comment("OldInsnID")
2358*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldInsnID)
2359*0fca6ea1SDimitry Andric << MatchTable::Comment("OldOpIdx")
2360*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(OldOpIdx)
2361*0fca6ea1SDimitry Andric << MatchTable::Comment("NewInsnId")
2362*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewInsnId)
2363*0fca6ea1SDimitry Andric << MatchTable::Comment("NewOpIdx")
2364*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(NewOpIdx) << MatchTable::LineBreak;
2365*0fca6ea1SDimitry Andric }
2366*0fca6ea1SDimitry Andric }
2367*0fca6ea1SDimitry Andric
2368*0fca6ea1SDimitry Andric //===- ConstrainOperandToRegClassAction -----------------------------------===//
2369*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2370*0fca6ea1SDimitry Andric void ConstrainOperandToRegClassAction::emitActionOpcodes(
2371*0fca6ea1SDimitry Andric MatchTable &Table, RuleMatcher &Rule) const {
2372*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_ConstrainOperandRC")
2373*0fca6ea1SDimitry Andric << MatchTable::Comment("InsnID") << MatchTable::ULEB128Value(InsnID)
2374*0fca6ea1SDimitry Andric << MatchTable::Comment("Op") << MatchTable::ULEB128Value(OpIdx)
2375*0fca6ea1SDimitry Andric << MatchTable::NamedValue(2, RC.getQualifiedIdName())
2376*0fca6ea1SDimitry Andric << MatchTable::LineBreak;
2377*0fca6ea1SDimitry Andric }
2378*0fca6ea1SDimitry Andric
2379*0fca6ea1SDimitry Andric //===- MakeTempRegisterAction ---------------------------------------------===//
2380*0fca6ea1SDimitry Andric
emitActionOpcodes(MatchTable & Table,RuleMatcher & Rule) const2381*0fca6ea1SDimitry Andric void MakeTempRegisterAction::emitActionOpcodes(MatchTable &Table,
2382*0fca6ea1SDimitry Andric RuleMatcher &Rule) const {
2383*0fca6ea1SDimitry Andric Table << MatchTable::Opcode("GIR_MakeTempReg")
2384*0fca6ea1SDimitry Andric << MatchTable::Comment("TempRegID")
2385*0fca6ea1SDimitry Andric << MatchTable::ULEB128Value(TempRegID) << MatchTable::Comment("TypeID")
2386*0fca6ea1SDimitry Andric << Ty << MatchTable::LineBreak;
2387*0fca6ea1SDimitry Andric }
2388*0fca6ea1SDimitry Andric
2389*0fca6ea1SDimitry Andric } // namespace gi
2390*0fca6ea1SDimitry Andric } // namespace llvm
2391