xref: /llvm-project/llvm/utils/TableGen/Common/GlobalISel/Patterns.cpp (revision 62e2c7fb2d18b43149a07526f6a3c0563d50e2fa)
1fa3d789dSPierre van Houtryve //===- Patterns.cpp --------------------------------------------*- C++ -*-===//
2fa3d789dSPierre van Houtryve //
3fa3d789dSPierre van Houtryve // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fa3d789dSPierre van Houtryve // See https://llvm.org/LICENSE.txt for license information.
5fa3d789dSPierre van Houtryve // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fa3d789dSPierre van Houtryve //
7fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
8fa3d789dSPierre van Houtryve 
9fa3d789dSPierre van Houtryve #include "Patterns.h"
10fa3d789dSPierre van Houtryve #include "Basic/CodeGenIntrinsics.h"
11fa3d789dSPierre van Houtryve #include "CXXPredicates.h"
12fa3d789dSPierre van Houtryve #include "CodeExpander.h"
13fa3d789dSPierre van Houtryve #include "CodeExpansions.h"
14fa3d789dSPierre van Houtryve #include "Common/CodeGenInstruction.h"
15fa3d789dSPierre van Houtryve #include "llvm/ADT/StringSet.h"
16fa3d789dSPierre van Houtryve #include "llvm/Support/Debug.h"
17fa3d789dSPierre van Houtryve #include "llvm/Support/raw_ostream.h"
18fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h"
19fa3d789dSPierre van Houtryve #include "llvm/TableGen/Record.h"
20fa3d789dSPierre van Houtryve 
21fa3d789dSPierre van Houtryve namespace llvm {
22fa3d789dSPierre van Houtryve namespace gi {
23fa3d789dSPierre van Houtryve 
24fa3d789dSPierre van Houtryve //===- PatternType --------------------------------------------------------===//
25fa3d789dSPierre van Houtryve 
26fa3d789dSPierre van Houtryve std::optional<PatternType> PatternType::get(ArrayRef<SMLoc> DiagLoc,
27fa3d789dSPierre van Houtryve                                             const Record *R, Twine DiagCtx) {
28fa3d789dSPierre van Houtryve   assert(R);
29fa3d789dSPierre van Houtryve   if (R->isSubClassOf("ValueType")) {
30fa3d789dSPierre van Houtryve     PatternType PT(PT_ValueType);
31fa3d789dSPierre van Houtryve     PT.Data.Def = R;
32fa3d789dSPierre van Houtryve     return PT;
33fa3d789dSPierre van Houtryve   }
34fa3d789dSPierre van Houtryve 
35fa3d789dSPierre van Houtryve   if (R->isSubClassOf(TypeOfClassName)) {
36fa3d789dSPierre van Houtryve     auto RawOpName = R->getValueAsString("OpName");
37fa3d789dSPierre van Houtryve     if (!RawOpName.starts_with("$")) {
38fa3d789dSPierre van Houtryve       PrintError(DiagLoc, DiagCtx + ": invalid operand name format '" +
39fa3d789dSPierre van Houtryve                               RawOpName + "' in " + TypeOfClassName +
40fa3d789dSPierre van Houtryve                               ": expected '$' followed by an operand name");
41fa3d789dSPierre van Houtryve       return std::nullopt;
42fa3d789dSPierre van Houtryve     }
43fa3d789dSPierre van Houtryve 
44fa3d789dSPierre van Houtryve     PatternType PT(PT_TypeOf);
45fa3d789dSPierre van Houtryve     PT.Data.Str = RawOpName.drop_front(1);
46fa3d789dSPierre van Houtryve     return PT;
47fa3d789dSPierre van Houtryve   }
48fa3d789dSPierre van Houtryve 
49972c0292SPierre van Houtryve   if (R->isSubClassOf(VariadicClassName)) {
50972c0292SPierre van Houtryve     const int64_t Min = R->getValueAsInt("MinArgs");
51972c0292SPierre van Houtryve     const int64_t Max = R->getValueAsInt("MaxArgs");
52972c0292SPierre van Houtryve 
53972c0292SPierre van Houtryve     if (Min == 0) {
54972c0292SPierre van Houtryve       PrintError(
55972c0292SPierre van Houtryve           DiagLoc,
56972c0292SPierre van Houtryve           DiagCtx +
57972c0292SPierre van Houtryve               ": minimum number of arguments must be greater than zero in " +
58972c0292SPierre van Houtryve               VariadicClassName);
59972c0292SPierre van Houtryve       return std::nullopt;
60972c0292SPierre van Houtryve     }
61972c0292SPierre van Houtryve 
62972c0292SPierre van Houtryve     if (Max <= Min && Max != 0) {
63972c0292SPierre van Houtryve       PrintError(DiagLoc, DiagCtx + ": maximum number of arguments (" +
64972c0292SPierre van Houtryve                               Twine(Max) +
65972c0292SPierre van Houtryve                               ") must be zero, or greater "
66972c0292SPierre van Houtryve                               "than the minimum number of arguments (" +
67972c0292SPierre van Houtryve                               Twine(Min) + ") in " + VariadicClassName);
68972c0292SPierre van Houtryve       return std::nullopt;
69972c0292SPierre van Houtryve     }
70972c0292SPierre van Houtryve 
71972c0292SPierre van Houtryve     PatternType PT(PT_VariadicPack);
72972c0292SPierre van Houtryve     PT.Data.VPTI = {unsigned(Min), unsigned(Max)};
73972c0292SPierre van Houtryve     return PT;
74972c0292SPierre van Houtryve   }
75972c0292SPierre van Houtryve 
76fa3d789dSPierre van Houtryve   PrintError(DiagLoc, DiagCtx + ": unknown type '" + R->getName() + "'");
77fa3d789dSPierre van Houtryve   return std::nullopt;
78fa3d789dSPierre van Houtryve }
79fa3d789dSPierre van Houtryve 
80fa3d789dSPierre van Houtryve PatternType PatternType::getTypeOf(StringRef OpName) {
81fa3d789dSPierre van Houtryve   PatternType PT(PT_TypeOf);
82fa3d789dSPierre van Houtryve   PT.Data.Str = OpName;
83fa3d789dSPierre van Houtryve   return PT;
84fa3d789dSPierre van Houtryve }
85fa3d789dSPierre van Houtryve 
86fa3d789dSPierre van Houtryve StringRef PatternType::getTypeOfOpName() const {
87fa3d789dSPierre van Houtryve   assert(isTypeOf());
88fa3d789dSPierre van Houtryve   return Data.Str;
89fa3d789dSPierre van Houtryve }
90fa3d789dSPierre van Houtryve 
91fa3d789dSPierre van Houtryve const Record *PatternType::getLLTRecord() const {
92fa3d789dSPierre van Houtryve   assert(isLLT());
93fa3d789dSPierre van Houtryve   return Data.Def;
94fa3d789dSPierre van Houtryve }
95fa3d789dSPierre van Houtryve 
96972c0292SPierre van Houtryve VariadicPackTypeInfo PatternType::getVariadicPackTypeInfo() const {
97972c0292SPierre van Houtryve   assert(isVariadicPack());
98972c0292SPierre van Houtryve   return Data.VPTI;
99972c0292SPierre van Houtryve }
100972c0292SPierre van Houtryve 
101fa3d789dSPierre van Houtryve bool PatternType::operator==(const PatternType &Other) const {
102fa3d789dSPierre van Houtryve   if (Kind != Other.Kind)
103fa3d789dSPierre van Houtryve     return false;
104fa3d789dSPierre van Houtryve 
105fa3d789dSPierre van Houtryve   switch (Kind) {
106fa3d789dSPierre van Houtryve   case PT_None:
107fa3d789dSPierre van Houtryve     return true;
108fa3d789dSPierre van Houtryve   case PT_ValueType:
109fa3d789dSPierre van Houtryve     return Data.Def == Other.Data.Def;
110fa3d789dSPierre van Houtryve   case PT_TypeOf:
111fa3d789dSPierre van Houtryve     return Data.Str == Other.Data.Str;
112972c0292SPierre van Houtryve   case PT_VariadicPack:
113972c0292SPierre van Houtryve     return Data.VPTI == Other.Data.VPTI;
114fa3d789dSPierre van Houtryve   }
115fa3d789dSPierre van Houtryve 
116fa3d789dSPierre van Houtryve   llvm_unreachable("Unknown Type Kind");
117fa3d789dSPierre van Houtryve }
118fa3d789dSPierre van Houtryve 
119fa3d789dSPierre van Houtryve std::string PatternType::str() const {
120fa3d789dSPierre van Houtryve   switch (Kind) {
121fa3d789dSPierre van Houtryve   case PT_None:
122fa3d789dSPierre van Houtryve     return "";
123fa3d789dSPierre van Houtryve   case PT_ValueType:
124fa3d789dSPierre van Houtryve     return Data.Def->getName().str();
125fa3d789dSPierre van Houtryve   case PT_TypeOf:
126fa3d789dSPierre van Houtryve     return (TypeOfClassName + "<$" + getTypeOfOpName() + ">").str();
127972c0292SPierre van Houtryve   case PT_VariadicPack:
128972c0292SPierre van Houtryve     return (VariadicClassName + "<" + Twine(Data.VPTI.Min) + "," +
129972c0292SPierre van Houtryve             Twine(Data.VPTI.Max) + ">")
130972c0292SPierre van Houtryve         .str();
131fa3d789dSPierre van Houtryve   }
132fa3d789dSPierre van Houtryve 
133fa3d789dSPierre van Houtryve   llvm_unreachable("Unknown type!");
134fa3d789dSPierre van Houtryve }
135fa3d789dSPierre van Houtryve 
136fa3d789dSPierre van Houtryve //===- Pattern ------------------------------------------------------------===//
137fa3d789dSPierre van Houtryve 
138fa3d789dSPierre van Houtryve void Pattern::dump() const { return print(dbgs()); }
139fa3d789dSPierre van Houtryve 
140fa3d789dSPierre van Houtryve const char *Pattern::getKindName() const {
141fa3d789dSPierre van Houtryve   switch (Kind) {
142fa3d789dSPierre van Houtryve   case K_AnyOpcode:
143fa3d789dSPierre van Houtryve     return "AnyOpcodePattern";
144fa3d789dSPierre van Houtryve   case K_CXX:
145fa3d789dSPierre van Houtryve     return "CXXPattern";
146fa3d789dSPierre van Houtryve   case K_CodeGenInstruction:
147fa3d789dSPierre van Houtryve     return "CodeGenInstructionPattern";
148fa3d789dSPierre van Houtryve   case K_PatFrag:
149fa3d789dSPierre van Houtryve     return "PatFragPattern";
150fa3d789dSPierre van Houtryve   case K_Builtin:
151fa3d789dSPierre van Houtryve     return "BuiltinPattern";
152fa3d789dSPierre van Houtryve   }
153fa3d789dSPierre van Houtryve 
154fa3d789dSPierre van Houtryve   llvm_unreachable("unknown pattern kind!");
155fa3d789dSPierre van Houtryve }
156fa3d789dSPierre van Houtryve 
157fa3d789dSPierre van Houtryve void Pattern::printImpl(raw_ostream &OS, bool PrintName,
158fa3d789dSPierre van Houtryve                         function_ref<void()> ContentPrinter) const {
159fa3d789dSPierre van Houtryve   OS << "(" << getKindName() << " ";
160fa3d789dSPierre van Houtryve   if (PrintName)
161fa3d789dSPierre van Houtryve     OS << "name:" << getName() << " ";
162fa3d789dSPierre van Houtryve   ContentPrinter();
163fa3d789dSPierre van Houtryve   OS << ")";
164fa3d789dSPierre van Houtryve }
165fa3d789dSPierre van Houtryve 
166fa3d789dSPierre van Houtryve //===- AnyOpcodePattern ---------------------------------------------------===//
167fa3d789dSPierre van Houtryve 
168fa3d789dSPierre van Houtryve void AnyOpcodePattern::print(raw_ostream &OS, bool PrintName) const {
169fa3d789dSPierre van Houtryve   printImpl(OS, PrintName, [&OS, this]() {
170fa3d789dSPierre van Houtryve     OS << "["
171fa3d789dSPierre van Houtryve        << join(map_range(Insts,
172fa3d789dSPierre van Houtryve                          [](const auto *I) { return I->TheDef->getName(); }),
173fa3d789dSPierre van Houtryve                ", ")
174fa3d789dSPierre van Houtryve        << "]";
175fa3d789dSPierre van Houtryve   });
176fa3d789dSPierre van Houtryve }
177fa3d789dSPierre van Houtryve 
178fa3d789dSPierre van Houtryve //===- CXXPattern ---------------------------------------------------------===//
179fa3d789dSPierre van Houtryve 
180fa3d789dSPierre van Houtryve CXXPattern::CXXPattern(const StringInit &Code, StringRef Name)
181fa3d789dSPierre van Houtryve     : CXXPattern(Code.getAsUnquotedString(), Name) {}
182fa3d789dSPierre van Houtryve 
183fa3d789dSPierre van Houtryve const CXXPredicateCode &
184fa3d789dSPierre van Houtryve CXXPattern::expandCode(const CodeExpansions &CE, ArrayRef<SMLoc> Locs,
185fa3d789dSPierre van Houtryve                        function_ref<void(raw_ostream &)> AddComment) const {
1867d810623SPierre van Houtryve   assert(!IsApply && "'apply' CXX patterns should be handled differently!");
1877d810623SPierre van Houtryve 
188fa3d789dSPierre van Houtryve   std::string Result;
189fa3d789dSPierre van Houtryve   raw_string_ostream OS(Result);
190fa3d789dSPierre van Houtryve 
191fa3d789dSPierre van Houtryve   if (AddComment)
192fa3d789dSPierre van Houtryve     AddComment(OS);
193fa3d789dSPierre van Houtryve 
194fa3d789dSPierre van Houtryve   CodeExpander Expander(RawCode, CE, Locs, /*ShowExpansions*/ false);
195fa3d789dSPierre van Houtryve   Expander.emit(OS);
196fa3d789dSPierre van Houtryve   return CXXPredicateCode::getMatchCode(std::move(Result));
197fa3d789dSPierre van Houtryve }
198fa3d789dSPierre van Houtryve 
199fa3d789dSPierre van Houtryve void CXXPattern::print(raw_ostream &OS, bool PrintName) const {
200fa3d789dSPierre van Houtryve   printImpl(OS, PrintName, [&OS, this] {
201fa3d789dSPierre van Houtryve     OS << (IsApply ? "apply" : "match") << " code:\"";
202fa3d789dSPierre van Houtryve     printEscapedString(getRawCode(), OS);
203fa3d789dSPierre van Houtryve     OS << "\"";
204fa3d789dSPierre van Houtryve   });
205fa3d789dSPierre van Houtryve }
206fa3d789dSPierre van Houtryve 
207fa3d789dSPierre van Houtryve //===- InstructionOperand -------------------------------------------------===//
208fa3d789dSPierre van Houtryve 
209fa3d789dSPierre van Houtryve std::string InstructionOperand::describe() const {
210fa3d789dSPierre van Houtryve   if (!hasImmValue())
211fa3d789dSPierre van Houtryve     return "MachineOperand $" + getOperandName().str() + "";
212fa3d789dSPierre van Houtryve   std::string Str = "imm " + std::to_string(getImmValue());
213fa3d789dSPierre van Houtryve   if (isNamedImmediate())
214fa3d789dSPierre van Houtryve     Str += ":$" + getOperandName().str() + "";
215fa3d789dSPierre van Houtryve   return Str;
216fa3d789dSPierre van Houtryve }
217fa3d789dSPierre van Houtryve 
218fa3d789dSPierre van Houtryve void InstructionOperand::print(raw_ostream &OS) const {
219fa3d789dSPierre van Houtryve   if (isDef())
220fa3d789dSPierre van Houtryve     OS << "<def>";
221fa3d789dSPierre van Houtryve 
222fa3d789dSPierre van Houtryve   bool NeedsColon = true;
223fa3d789dSPierre van Houtryve   if (Type) {
224fa3d789dSPierre van Houtryve     if (hasImmValue())
225fa3d789dSPierre van Houtryve       OS << "(" << Type.str() << " " << getImmValue() << ")";
226fa3d789dSPierre van Houtryve     else
227fa3d789dSPierre van Houtryve       OS << Type.str();
228fa3d789dSPierre van Houtryve   } else if (hasImmValue())
229fa3d789dSPierre van Houtryve     OS << getImmValue();
230fa3d789dSPierre van Houtryve   else
231fa3d789dSPierre van Houtryve     NeedsColon = false;
232fa3d789dSPierre van Houtryve 
233fa3d789dSPierre van Houtryve   if (isNamedOperand())
234fa3d789dSPierre van Houtryve     OS << (NeedsColon ? ":" : "") << "$" << getOperandName();
235fa3d789dSPierre van Houtryve }
236fa3d789dSPierre van Houtryve 
237fa3d789dSPierre van Houtryve void InstructionOperand::dump() const { return print(dbgs()); }
238fa3d789dSPierre van Houtryve 
239fa3d789dSPierre van Houtryve //===- InstructionPattern -------------------------------------------------===//
240fa3d789dSPierre van Houtryve 
241fa3d789dSPierre van Houtryve bool InstructionPattern::diagnoseAllSpecialTypes(ArrayRef<SMLoc> Loc,
242fa3d789dSPierre van Houtryve                                                  Twine Msg) const {
243fa3d789dSPierre van Houtryve   bool HasDiag = false;
244fa3d789dSPierre van Houtryve   for (const auto &[Idx, Op] : enumerate(operands())) {
245fa3d789dSPierre van Houtryve     if (Op.getType().isSpecial()) {
246fa3d789dSPierre van Houtryve       PrintError(Loc, Msg);
247fa3d789dSPierre van Houtryve       PrintNote(Loc, "operand " + Twine(Idx) + " of '" + getName() +
248fa3d789dSPierre van Houtryve                          "' has type '" + Op.getType().str() + "'");
249fa3d789dSPierre van Houtryve       HasDiag = true;
250fa3d789dSPierre van Houtryve     }
251fa3d789dSPierre van Houtryve   }
252fa3d789dSPierre van Houtryve   return HasDiag;
253fa3d789dSPierre van Houtryve }
254fa3d789dSPierre van Houtryve 
255fa3d789dSPierre van Houtryve void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const {
256fa3d789dSPierre van Houtryve   PrintError(Locs, "pattern '" + getName() + "' ('" + getInstName() +
257fa3d789dSPierre van Houtryve                        "') is unreachable from the pattern root!");
258fa3d789dSPierre van Houtryve }
259fa3d789dSPierre van Houtryve 
260fa3d789dSPierre van Houtryve bool InstructionPattern::checkSemantics(ArrayRef<SMLoc> Loc) {
261fa3d789dSPierre van Houtryve   unsigned NumExpectedOperands = getNumInstOperands();
262fa3d789dSPierre van Houtryve 
263fa3d789dSPierre van Houtryve   if (isVariadic()) {
264fa3d789dSPierre van Houtryve     if (Operands.size() < NumExpectedOperands) {
265fa3d789dSPierre van Houtryve       PrintError(Loc, +"'" + getInstName() + "' expected at least " +
266fa3d789dSPierre van Houtryve                           Twine(NumExpectedOperands) + " operands, got " +
267fa3d789dSPierre van Houtryve                           Twine(Operands.size()));
268fa3d789dSPierre van Houtryve       return false;
269fa3d789dSPierre van Houtryve     }
270fa3d789dSPierre van Houtryve   } else if (NumExpectedOperands != Operands.size()) {
271fa3d789dSPierre van Houtryve     PrintError(Loc, +"'" + getInstName() + "' expected " +
272fa3d789dSPierre van Houtryve                         Twine(NumExpectedOperands) + " operands, got " +
273fa3d789dSPierre van Houtryve                         Twine(Operands.size()));
274fa3d789dSPierre van Houtryve     return false;
275fa3d789dSPierre van Houtryve   }
276fa3d789dSPierre van Houtryve 
277fa3d789dSPierre van Houtryve   unsigned OpIdx = 0;
278fa3d789dSPierre van Houtryve   unsigned NumDefs = getNumInstDefs();
279fa3d789dSPierre van Houtryve   for (auto &Op : Operands)
280fa3d789dSPierre van Houtryve     Op.setIsDef(OpIdx++ < NumDefs);
281fa3d789dSPierre van Houtryve 
282fa3d789dSPierre van Houtryve   return true;
283fa3d789dSPierre van Houtryve }
284fa3d789dSPierre van Houtryve 
285fa3d789dSPierre van Houtryve void InstructionPattern::print(raw_ostream &OS, bool PrintName) const {
286fa3d789dSPierre van Houtryve   printImpl(OS, PrintName, [&OS, this] {
287fa3d789dSPierre van Houtryve     OS << getInstName() << " operands:[";
288fa3d789dSPierre van Houtryve     StringRef Sep;
289fa3d789dSPierre van Houtryve     for (const auto &Op : Operands) {
290fa3d789dSPierre van Houtryve       OS << Sep;
291fa3d789dSPierre van Houtryve       Op.print(OS);
292fa3d789dSPierre van Houtryve       Sep = ", ";
293fa3d789dSPierre van Houtryve     }
294fa3d789dSPierre van Houtryve     OS << "]";
295fa3d789dSPierre van Houtryve 
296fa3d789dSPierre van Houtryve     printExtras(OS);
297fa3d789dSPierre van Houtryve   });
298fa3d789dSPierre van Houtryve }
299fa3d789dSPierre van Houtryve 
300fa3d789dSPierre van Houtryve //===- OperandTable -------------------------------------------------------===//
301fa3d789dSPierre van Houtryve 
302fa3d789dSPierre van Houtryve bool OperandTable::addPattern(InstructionPattern *P,
303fa3d789dSPierre van Houtryve                               function_ref<void(StringRef)> DiagnoseRedef) {
304fa3d789dSPierre van Houtryve   for (const auto &Op : P->named_operands()) {
305fa3d789dSPierre van Houtryve     StringRef OpName = Op.getOperandName();
306fa3d789dSPierre van Houtryve 
307fa3d789dSPierre van Houtryve     // We always create an entry in the OperandTable, even for uses.
308fa3d789dSPierre van Houtryve     // Uses of operands that don't have a def (= live-ins) will remain with a
309fa3d789dSPierre van Houtryve     // nullptr as the Def.
310fa3d789dSPierre van Houtryve     //
311fa3d789dSPierre van Houtryve     // This allows us tell whether an operand exists in a pattern or not. If
312fa3d789dSPierre van Houtryve     // there is no entry for it, it doesn't exist, if there is an entry, it's
313fa3d789dSPierre van Houtryve     // used/def'd at least once.
314fa3d789dSPierre van Houtryve     auto &Def = Table[OpName];
315fa3d789dSPierre van Houtryve 
316fa3d789dSPierre van Houtryve     if (!Op.isDef())
317fa3d789dSPierre van Houtryve       continue;
318fa3d789dSPierre van Houtryve 
319fa3d789dSPierre van Houtryve     if (Def) {
320fa3d789dSPierre van Houtryve       DiagnoseRedef(OpName);
321fa3d789dSPierre van Houtryve       return false;
322fa3d789dSPierre van Houtryve     }
323fa3d789dSPierre van Houtryve 
324fa3d789dSPierre van Houtryve     Def = P;
325fa3d789dSPierre van Houtryve   }
326fa3d789dSPierre van Houtryve 
327fa3d789dSPierre van Houtryve   return true;
328fa3d789dSPierre van Houtryve }
329fa3d789dSPierre van Houtryve 
330fa3d789dSPierre van Houtryve void OperandTable::print(raw_ostream &OS, StringRef Name,
331fa3d789dSPierre van Houtryve                          StringRef Indent) const {
332fa3d789dSPierre van Houtryve   OS << Indent << "(OperandTable ";
333fa3d789dSPierre van Houtryve   if (!Name.empty())
334fa3d789dSPierre van Houtryve     OS << Name << " ";
335fa3d789dSPierre van Houtryve   if (Table.empty()) {
336fa3d789dSPierre van Houtryve     OS << "<empty>)\n";
337fa3d789dSPierre van Houtryve     return;
338fa3d789dSPierre van Houtryve   }
339fa3d789dSPierre van Houtryve 
340fa3d789dSPierre van Houtryve   SmallVector<StringRef, 0> Keys(Table.keys());
341fa3d789dSPierre van Houtryve   sort(Keys);
342fa3d789dSPierre van Houtryve 
343fa3d789dSPierre van Houtryve   OS << '\n';
344fa3d789dSPierre van Houtryve   for (const auto &Key : Keys) {
345fa3d789dSPierre van Houtryve     const auto *Def = Table.at(Key);
346fa3d789dSPierre van Houtryve     OS << Indent << "  " << Key << " -> "
347fa3d789dSPierre van Houtryve        << (Def ? Def->getName() : "<live-in>") << '\n';
348fa3d789dSPierre van Houtryve   }
349fa3d789dSPierre van Houtryve   OS << Indent << ")\n";
350fa3d789dSPierre van Houtryve }
351fa3d789dSPierre van Houtryve 
352fa3d789dSPierre van Houtryve void OperandTable::dump() const { print(dbgs()); }
353fa3d789dSPierre van Houtryve 
354fa3d789dSPierre van Houtryve //===- MIFlagsInfo --------------------------------------------------------===//
355fa3d789dSPierre van Houtryve 
356fa3d789dSPierre van Houtryve void MIFlagsInfo::addSetFlag(const Record *R) {
357fa3d789dSPierre van Houtryve   SetF.insert(R->getValueAsString("EnumName"));
358fa3d789dSPierre van Houtryve }
359fa3d789dSPierre van Houtryve 
360fa3d789dSPierre van Houtryve void MIFlagsInfo::addUnsetFlag(const Record *R) {
361fa3d789dSPierre van Houtryve   UnsetF.insert(R->getValueAsString("EnumName"));
362fa3d789dSPierre van Houtryve }
363fa3d789dSPierre van Houtryve 
364fa3d789dSPierre van Houtryve void MIFlagsInfo::addCopyFlag(StringRef InstName) { CopyF.insert(InstName); }
365fa3d789dSPierre van Houtryve 
366fa3d789dSPierre van Houtryve //===- CodeGenInstructionPattern ------------------------------------------===//
367fa3d789dSPierre van Houtryve 
368fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::is(StringRef OpcodeName) const {
369fa3d789dSPierre van Houtryve   return I.TheDef->getName() == OpcodeName;
370fa3d789dSPierre van Houtryve }
371fa3d789dSPierre van Houtryve 
372fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::isVariadic() const {
373fa3d789dSPierre van Houtryve   return !isIntrinsic() && I.Operands.isVariadic;
374fa3d789dSPierre van Houtryve }
375fa3d789dSPierre van Houtryve 
376fa3d789dSPierre van Houtryve bool CodeGenInstructionPattern::hasVariadicDefs() const {
377fa3d789dSPierre van Houtryve   // Note: we cannot use variadicOpsAreDefs, it's not set for
378fa3d789dSPierre van Houtryve   // GenericInstructions.
379fa3d789dSPierre van Houtryve   if (!isVariadic())
380fa3d789dSPierre van Houtryve     return false;
381fa3d789dSPierre van Houtryve 
382fa3d789dSPierre van Houtryve   if (I.variadicOpsAreDefs)
383fa3d789dSPierre van Houtryve     return true;
384fa3d789dSPierre van Houtryve 
385*62e2c7fbSRahul Joshi   const DagInit *OutOps = I.TheDef->getValueAsDag("OutOperandList");
386fa3d789dSPierre van Houtryve   if (OutOps->arg_empty())
387fa3d789dSPierre van Houtryve     return false;
388fa3d789dSPierre van Houtryve 
389fa3d789dSPierre van Houtryve   auto *LastArgTy = dyn_cast<DefInit>(OutOps->getArg(OutOps->arg_size() - 1));
390fa3d789dSPierre van Houtryve   return LastArgTy && LastArgTy->getDef()->getName() == "variable_ops";
391fa3d789dSPierre van Houtryve }
392fa3d789dSPierre van Houtryve 
393fa3d789dSPierre van Houtryve unsigned CodeGenInstructionPattern::getNumInstDefs() const {
394fa3d789dSPierre van Houtryve   if (isIntrinsic())
395fa3d789dSPierre van Houtryve     return IntrinInfo->IS.RetTys.size();
396fa3d789dSPierre van Houtryve 
397fa3d789dSPierre van Houtryve   if (!isVariadic() || !hasVariadicDefs())
398fa3d789dSPierre van Houtryve     return I.Operands.NumDefs;
399fa3d789dSPierre van Houtryve   unsigned NumOuts = I.Operands.size() - I.Operands.NumDefs;
400fa3d789dSPierre van Houtryve   assert(Operands.size() > NumOuts);
401fa3d789dSPierre van Houtryve   return std::max<unsigned>(I.Operands.NumDefs, Operands.size() - NumOuts);
402fa3d789dSPierre van Houtryve }
403fa3d789dSPierre van Houtryve 
404fa3d789dSPierre van Houtryve unsigned CodeGenInstructionPattern::getNumInstOperands() const {
405fa3d789dSPierre van Houtryve   if (isIntrinsic())
406fa3d789dSPierre van Houtryve     return IntrinInfo->IS.RetTys.size() + IntrinInfo->IS.ParamTys.size();
407fa3d789dSPierre van Houtryve 
408fa3d789dSPierre van Houtryve   unsigned NumCGIOps = I.Operands.size();
409fa3d789dSPierre van Houtryve   return isVariadic() ? std::max<unsigned>(NumCGIOps, Operands.size())
410fa3d789dSPierre van Houtryve                       : NumCGIOps;
411fa3d789dSPierre van Houtryve }
412fa3d789dSPierre van Houtryve 
413fa3d789dSPierre van Houtryve MIFlagsInfo &CodeGenInstructionPattern::getOrCreateMIFlagsInfo() {
414fa3d789dSPierre van Houtryve   if (!FI)
415fa3d789dSPierre van Houtryve     FI = std::make_unique<MIFlagsInfo>();
416fa3d789dSPierre van Houtryve   return *FI;
417fa3d789dSPierre van Houtryve }
418fa3d789dSPierre van Houtryve 
419fa3d789dSPierre van Houtryve StringRef CodeGenInstructionPattern::getInstName() const {
420fa3d789dSPierre van Houtryve   return I.TheDef->getName();
421fa3d789dSPierre van Houtryve }
422fa3d789dSPierre van Houtryve 
423fa3d789dSPierre van Houtryve void CodeGenInstructionPattern::printExtras(raw_ostream &OS) const {
424fa3d789dSPierre van Houtryve   if (isIntrinsic())
425fa3d789dSPierre van Houtryve     OS << " intrinsic(@" << IntrinInfo->Name << ")";
426fa3d789dSPierre van Houtryve 
427fa3d789dSPierre van Houtryve   if (!FI)
428fa3d789dSPierre van Houtryve     return;
429fa3d789dSPierre van Houtryve 
430fa3d789dSPierre van Houtryve   OS << " (MIFlags";
431fa3d789dSPierre van Houtryve   if (!FI->set_flags().empty())
432fa3d789dSPierre van Houtryve     OS << " (set " << join(FI->set_flags(), ", ") << ")";
433fa3d789dSPierre van Houtryve   if (!FI->unset_flags().empty())
434fa3d789dSPierre van Houtryve     OS << " (unset " << join(FI->unset_flags(), ", ") << ")";
435fa3d789dSPierre van Houtryve   if (!FI->copy_flags().empty())
436fa3d789dSPierre van Houtryve     OS << " (copy " << join(FI->copy_flags(), ", ") << ")";
437fa3d789dSPierre van Houtryve   OS << ')';
438fa3d789dSPierre van Houtryve }
439fa3d789dSPierre van Houtryve 
440fa3d789dSPierre van Houtryve //===- OperandTypeChecker -------------------------------------------------===//
441fa3d789dSPierre van Houtryve 
442fa3d789dSPierre van Houtryve bool OperandTypeChecker::check(
443fa3d789dSPierre van Houtryve     InstructionPattern &P,
444fa3d789dSPierre van Houtryve     std::function<bool(const PatternType &)> VerifyTypeOfOperand) {
445fa3d789dSPierre van Houtryve   Pats.push_back(&P);
446fa3d789dSPierre van Houtryve 
447fa3d789dSPierre van Houtryve   for (auto &Op : P.operands()) {
448fa3d789dSPierre van Houtryve     const auto Ty = Op.getType();
449fa3d789dSPierre van Houtryve     if (!Ty)
450fa3d789dSPierre van Houtryve       continue;
451fa3d789dSPierre van Houtryve 
452fa3d789dSPierre van Houtryve     if (Ty.isTypeOf() && !VerifyTypeOfOperand(Ty))
453fa3d789dSPierre van Houtryve       return false;
454fa3d789dSPierre van Houtryve 
455fa3d789dSPierre van Houtryve     if (!Op.isNamedOperand())
456fa3d789dSPierre van Houtryve       continue;
457fa3d789dSPierre van Houtryve 
458fa3d789dSPierre van Houtryve     StringRef OpName = Op.getOperandName();
459fa3d789dSPierre van Houtryve     auto &Info = Types[OpName];
460fa3d789dSPierre van Houtryve     if (!Info.Type) {
461fa3d789dSPierre van Houtryve       Info.Type = Ty;
462fa3d789dSPierre van Houtryve       Info.PrintTypeSrcNote = [this, OpName, Ty, &P]() {
463fa3d789dSPierre van Houtryve         PrintSeenWithTypeIn(P, OpName, Ty);
464fa3d789dSPierre van Houtryve       };
465fa3d789dSPierre van Houtryve       continue;
466fa3d789dSPierre van Houtryve     }
467fa3d789dSPierre van Houtryve 
468fa3d789dSPierre van Houtryve     if (Info.Type != Ty) {
469fa3d789dSPierre van Houtryve       PrintError(DiagLoc, "conflicting types for operand '" +
470fa3d789dSPierre van Houtryve                               Op.getOperandName() + "': '" + Info.Type.str() +
471fa3d789dSPierre van Houtryve                               "' vs '" + Ty.str() + "'");
472fa3d789dSPierre van Houtryve       PrintSeenWithTypeIn(P, OpName, Ty);
473fa3d789dSPierre van Houtryve       Info.PrintTypeSrcNote();
474fa3d789dSPierre van Houtryve       return false;
475fa3d789dSPierre van Houtryve     }
476fa3d789dSPierre van Houtryve   }
477fa3d789dSPierre van Houtryve 
478fa3d789dSPierre van Houtryve   return true;
479fa3d789dSPierre van Houtryve }
480fa3d789dSPierre van Houtryve 
481fa3d789dSPierre van Houtryve void OperandTypeChecker::propagateTypes() {
482fa3d789dSPierre van Houtryve   for (auto *Pat : Pats) {
483fa3d789dSPierre van Houtryve     for (auto &Op : Pat->named_operands()) {
484fa3d789dSPierre van Houtryve       if (auto &Info = Types[Op.getOperandName()]; Info.Type)
485fa3d789dSPierre van Houtryve         Op.setType(Info.Type);
486fa3d789dSPierre van Houtryve     }
487fa3d789dSPierre van Houtryve   }
488fa3d789dSPierre van Houtryve }
489fa3d789dSPierre van Houtryve 
490fa3d789dSPierre van Houtryve void OperandTypeChecker::PrintSeenWithTypeIn(InstructionPattern &P,
491fa3d789dSPierre van Houtryve                                              StringRef OpName,
492fa3d789dSPierre van Houtryve                                              PatternType Ty) const {
493fa3d789dSPierre van Houtryve   PrintNote(DiagLoc, "'" + OpName + "' seen with type '" + Ty.str() + "' in '" +
494fa3d789dSPierre van Houtryve                          P.getName() + "'");
495fa3d789dSPierre van Houtryve }
496fa3d789dSPierre van Houtryve 
497fa3d789dSPierre van Houtryve StringRef PatFrag::getParamKindStr(ParamKind OK) {
498fa3d789dSPierre van Houtryve   switch (OK) {
499fa3d789dSPierre van Houtryve   case PK_Root:
500fa3d789dSPierre van Houtryve     return "root";
501fa3d789dSPierre van Houtryve   case PK_MachineOperand:
502fa3d789dSPierre van Houtryve     return "machine_operand";
503fa3d789dSPierre van Houtryve   case PK_Imm:
504fa3d789dSPierre van Houtryve     return "imm";
505fa3d789dSPierre van Houtryve   }
506fa3d789dSPierre van Houtryve 
507fa3d789dSPierre van Houtryve   llvm_unreachable("Unknown operand kind!");
508fa3d789dSPierre van Houtryve }
509fa3d789dSPierre van Houtryve 
510fa3d789dSPierre van Houtryve //===- PatFrag -----------------------------------------------------------===//
511fa3d789dSPierre van Houtryve 
512fa3d789dSPierre van Houtryve PatFrag::PatFrag(const Record &Def) : Def(Def) {
513fa3d789dSPierre van Houtryve   assert(Def.isSubClassOf(ClassName));
514fa3d789dSPierre van Houtryve }
515fa3d789dSPierre van Houtryve 
516fa3d789dSPierre van Houtryve StringRef PatFrag::getName() const { return Def.getName(); }
517fa3d789dSPierre van Houtryve 
518fa3d789dSPierre van Houtryve ArrayRef<SMLoc> PatFrag::getLoc() const { return Def.getLoc(); }
519fa3d789dSPierre van Houtryve 
520fa3d789dSPierre van Houtryve void PatFrag::addInParam(StringRef Name, ParamKind Kind) {
521fa3d789dSPierre van Houtryve   Params.emplace_back(Param{Name, Kind});
522fa3d789dSPierre van Houtryve }
523fa3d789dSPierre van Houtryve 
524fa3d789dSPierre van Houtryve iterator_range<PatFrag::ParamIt> PatFrag::in_params() const {
525fa3d789dSPierre van Houtryve   return {Params.begin() + NumOutParams, Params.end()};
526fa3d789dSPierre van Houtryve }
527fa3d789dSPierre van Houtryve 
528fa3d789dSPierre van Houtryve void PatFrag::addOutParam(StringRef Name, ParamKind Kind) {
529fa3d789dSPierre van Houtryve   assert(NumOutParams == Params.size() &&
530fa3d789dSPierre van Houtryve          "Adding out-param after an in-param!");
531fa3d789dSPierre van Houtryve   Params.emplace_back(Param{Name, Kind});
532fa3d789dSPierre van Houtryve   ++NumOutParams;
533fa3d789dSPierre van Houtryve }
534fa3d789dSPierre van Houtryve 
535fa3d789dSPierre van Houtryve iterator_range<PatFrag::ParamIt> PatFrag::out_params() const {
536fa3d789dSPierre van Houtryve   return {Params.begin(), Params.begin() + NumOutParams};
537fa3d789dSPierre van Houtryve }
538fa3d789dSPierre van Houtryve 
539fa3d789dSPierre van Houtryve unsigned PatFrag::num_roots() const {
540fa3d789dSPierre van Houtryve   return count_if(out_params(),
541fa3d789dSPierre van Houtryve                   [&](const auto &P) { return P.Kind == PK_Root; });
542fa3d789dSPierre van Houtryve }
543fa3d789dSPierre van Houtryve 
544fa3d789dSPierre van Houtryve unsigned PatFrag::getParamIdx(StringRef Name) const {
545fa3d789dSPierre van Houtryve   for (const auto &[Idx, Op] : enumerate(Params)) {
546fa3d789dSPierre van Houtryve     if (Op.Name == Name)
547fa3d789dSPierre van Houtryve       return Idx;
548fa3d789dSPierre van Houtryve   }
549fa3d789dSPierre van Houtryve 
550fa3d789dSPierre van Houtryve   return -1;
551fa3d789dSPierre van Houtryve }
552fa3d789dSPierre van Houtryve 
553fa3d789dSPierre van Houtryve bool PatFrag::checkSemantics() {
554fa3d789dSPierre van Houtryve   for (const auto &Alt : Alts) {
555fa3d789dSPierre van Houtryve     for (const auto &Pat : Alt.Pats) {
556fa3d789dSPierre van Houtryve       switch (Pat->getKind()) {
557fa3d789dSPierre van Houtryve       case Pattern::K_AnyOpcode:
558fa3d789dSPierre van Houtryve         PrintError("wip_match_opcode cannot be used in " + ClassName);
559fa3d789dSPierre van Houtryve         return false;
560fa3d789dSPierre van Houtryve       case Pattern::K_Builtin:
561fa3d789dSPierre van Houtryve         PrintError("Builtin instructions cannot be used in " + ClassName);
562fa3d789dSPierre van Houtryve         return false;
563fa3d789dSPierre van Houtryve       case Pattern::K_CXX:
564fa3d789dSPierre van Houtryve         continue;
565fa3d789dSPierre van Houtryve       case Pattern::K_CodeGenInstruction:
566972c0292SPierre van Houtryve         // TODO: Allow VarArgs?
567fa3d789dSPierre van Houtryve         if (cast<CodeGenInstructionPattern>(Pat.get())->diagnoseAllSpecialTypes(
568fa3d789dSPierre van Houtryve                 Def.getLoc(), PatternType::SpecialTyClassName +
569fa3d789dSPierre van Houtryve                                   " is not supported in " + ClassName))
570fa3d789dSPierre van Houtryve           return false;
571fa3d789dSPierre van Houtryve         continue;
572fa3d789dSPierre van Houtryve       case Pattern::K_PatFrag:
573fa3d789dSPierre van Houtryve         // TODO: It's just that the emitter doesn't handle it but technically
574fa3d789dSPierre van Houtryve         // there is no reason why we can't. We just have to be careful with
575fa3d789dSPierre van Houtryve         // operand mappings, it could get complex.
576fa3d789dSPierre van Houtryve         PrintError("nested " + ClassName + " are not supported");
577fa3d789dSPierre van Houtryve         return false;
578fa3d789dSPierre van Houtryve       }
579fa3d789dSPierre van Houtryve     }
580fa3d789dSPierre van Houtryve   }
581fa3d789dSPierre van Houtryve 
582fa3d789dSPierre van Houtryve   StringSet<> SeenOps;
583fa3d789dSPierre van Houtryve   for (const auto &Op : in_params()) {
584fa3d789dSPierre van Houtryve     if (SeenOps.count(Op.Name)) {
585fa3d789dSPierre van Houtryve       PrintError("duplicate parameter '" + Op.Name + "'");
586fa3d789dSPierre van Houtryve       return false;
587fa3d789dSPierre van Houtryve     }
588fa3d789dSPierre van Houtryve 
589fa3d789dSPierre van Houtryve     // Check this operand is NOT defined in any alternative's patterns.
590fa3d789dSPierre van Houtryve     for (const auto &Alt : Alts) {
591fa3d789dSPierre van Houtryve       if (Alt.OpTable.lookup(Op.Name).Def) {
592fa3d789dSPierre van Houtryve         PrintError("input parameter '" + Op.Name + "' cannot be redefined!");
593fa3d789dSPierre van Houtryve         return false;
594fa3d789dSPierre van Houtryve       }
595fa3d789dSPierre van Houtryve     }
596fa3d789dSPierre van Houtryve 
597fa3d789dSPierre van Houtryve     if (Op.Kind == PK_Root) {
598fa3d789dSPierre van Houtryve       PrintError("input parameterr '" + Op.Name + "' cannot be a root!");
599fa3d789dSPierre van Houtryve       return false;
600fa3d789dSPierre van Houtryve     }
601fa3d789dSPierre van Houtryve 
602fa3d789dSPierre van Houtryve     SeenOps.insert(Op.Name);
603fa3d789dSPierre van Houtryve   }
604fa3d789dSPierre van Houtryve 
605fa3d789dSPierre van Houtryve   for (const auto &Op : out_params()) {
606fa3d789dSPierre van Houtryve     if (Op.Kind != PK_Root && Op.Kind != PK_MachineOperand) {
607fa3d789dSPierre van Houtryve       PrintError("output parameter '" + Op.Name +
608fa3d789dSPierre van Houtryve                  "' must be 'root' or 'gi_mo'");
609fa3d789dSPierre van Houtryve       return false;
610fa3d789dSPierre van Houtryve     }
611fa3d789dSPierre van Houtryve 
612fa3d789dSPierre van Houtryve     if (SeenOps.count(Op.Name)) {
613fa3d789dSPierre van Houtryve       PrintError("duplicate parameter '" + Op.Name + "'");
614fa3d789dSPierre van Houtryve       return false;
615fa3d789dSPierre van Houtryve     }
616fa3d789dSPierre van Houtryve 
617fa3d789dSPierre van Houtryve     // Check this operand is defined in all alternative's patterns.
618fa3d789dSPierre van Houtryve     for (const auto &Alt : Alts) {
619fa3d789dSPierre van Houtryve       const auto *OpDef = Alt.OpTable.getDef(Op.Name);
620fa3d789dSPierre van Houtryve       if (!OpDef) {
621fa3d789dSPierre van Houtryve         PrintError("output parameter '" + Op.Name +
622fa3d789dSPierre van Houtryve                    "' must be defined by all alternative patterns in '" +
623fa3d789dSPierre van Houtryve                    Def.getName() + "'");
624fa3d789dSPierre van Houtryve         return false;
625fa3d789dSPierre van Houtryve       }
626fa3d789dSPierre van Houtryve 
627fa3d789dSPierre van Houtryve       if (Op.Kind == PK_Root && OpDef->getNumInstDefs() != 1) {
628fa3d789dSPierre van Houtryve         // The instruction that defines the root must have a single def.
629fa3d789dSPierre van Houtryve         // Otherwise we'd need to support multiple roots and it gets messy.
630fa3d789dSPierre van Houtryve         //
631fa3d789dSPierre van Houtryve         // e.g. this is not supported:
632fa3d789dSPierre van Houtryve         //   (pattern (G_UNMERGE_VALUES $x, $root, $vec))
633fa3d789dSPierre van Houtryve         PrintError("all instructions that define root '" + Op.Name + "' in '" +
634fa3d789dSPierre van Houtryve                    Def.getName() + "' can only have a single output operand");
635fa3d789dSPierre van Houtryve         return false;
636fa3d789dSPierre van Houtryve       }
637fa3d789dSPierre van Houtryve     }
638fa3d789dSPierre van Houtryve 
639fa3d789dSPierre van Houtryve     SeenOps.insert(Op.Name);
640fa3d789dSPierre van Houtryve   }
641fa3d789dSPierre van Houtryve 
642fa3d789dSPierre van Houtryve   if (num_out_params() != 0 && num_roots() == 0) {
643fa3d789dSPierre van Houtryve     PrintError(ClassName + " must have one root in its 'out' operands");
644fa3d789dSPierre van Houtryve     return false;
645fa3d789dSPierre van Houtryve   }
646fa3d789dSPierre van Houtryve 
647fa3d789dSPierre van Houtryve   if (num_roots() > 1) {
648fa3d789dSPierre van Houtryve     PrintError(ClassName + " can only have one root");
649fa3d789dSPierre van Houtryve     return false;
650fa3d789dSPierre van Houtryve   }
651fa3d789dSPierre van Houtryve 
652fa3d789dSPierre van Houtryve   // TODO: find unused params
653fa3d789dSPierre van Houtryve 
654fa3d789dSPierre van Houtryve   const auto CheckTypeOf = [&](const PatternType &) -> bool {
655fa3d789dSPierre van Houtryve     llvm_unreachable("GITypeOf should have been rejected earlier!");
656fa3d789dSPierre van Houtryve   };
657fa3d789dSPierre van Houtryve 
658fa3d789dSPierre van Houtryve   // Now, typecheck all alternatives.
659fa3d789dSPierre van Houtryve   for (auto &Alt : Alts) {
660fa3d789dSPierre van Houtryve     OperandTypeChecker OTC(Def.getLoc());
661fa3d789dSPierre van Houtryve     for (auto &Pat : Alt.Pats) {
662fa3d789dSPierre van Houtryve       if (auto *IP = dyn_cast<InstructionPattern>(Pat.get())) {
663fa3d789dSPierre van Houtryve         if (!OTC.check(*IP, CheckTypeOf))
664fa3d789dSPierre van Houtryve           return false;
665fa3d789dSPierre van Houtryve       }
666fa3d789dSPierre van Houtryve     }
667fa3d789dSPierre van Houtryve     OTC.propagateTypes();
668fa3d789dSPierre van Houtryve   }
669fa3d789dSPierre van Houtryve 
670fa3d789dSPierre van Houtryve   return true;
671fa3d789dSPierre van Houtryve }
672fa3d789dSPierre van Houtryve 
673fa3d789dSPierre van Houtryve bool PatFrag::handleUnboundInParam(StringRef ParamName, StringRef ArgName,
674fa3d789dSPierre van Houtryve                                    ArrayRef<SMLoc> DiagLoc) const {
675fa3d789dSPierre van Houtryve   // The parameter must be a live-in of all alternatives for this to work.
676fa3d789dSPierre van Houtryve   // Otherwise, we risk having unbound parameters being used (= crashes).
677fa3d789dSPierre van Houtryve   //
678fa3d789dSPierre van Houtryve   // Examples:
679fa3d789dSPierre van Houtryve   //
680fa3d789dSPierre van Houtryve   // in (ins $y), (patterns (G_FNEG $dst, $y), "return matchFnegOp(${y})")
681fa3d789dSPierre van Houtryve   //    even if $y is unbound, we'll lazily bind it when emitting the G_FNEG.
682fa3d789dSPierre van Houtryve   //
683fa3d789dSPierre van Houtryve   // in (ins $y), (patterns "return matchFnegOp(${y})")
684fa3d789dSPierre van Houtryve   //    if $y is unbound when this fragment is emitted, C++ code expansion will
685fa3d789dSPierre van Houtryve   //    fail.
686fa3d789dSPierre van Houtryve   for (const auto &Alt : Alts) {
687fa3d789dSPierre van Houtryve     auto &OT = Alt.OpTable;
688fa3d789dSPierre van Houtryve     if (!OT.lookup(ParamName).Found) {
689fa3d789dSPierre van Houtryve       llvm::PrintError(DiagLoc, "operand '" + ArgName + "' (for parameter '" +
690fa3d789dSPierre van Houtryve                                     ParamName + "' of '" + getName() +
691fa3d789dSPierre van Houtryve                                     "') cannot be unbound");
692fa3d789dSPierre van Houtryve       PrintNote(
693fa3d789dSPierre van Houtryve           DiagLoc,
694fa3d789dSPierre van Houtryve           "one or more alternatives of '" + getName() + "' do not bind '" +
695fa3d789dSPierre van Houtryve               ParamName +
696fa3d789dSPierre van Houtryve               "' to an instruction operand; either use a bound operand or "
697fa3d789dSPierre van Houtryve               "ensure '" +
698fa3d789dSPierre van Houtryve               Def.getName() + "' binds '" + ParamName +
699fa3d789dSPierre van Houtryve               "' in all alternatives");
700fa3d789dSPierre van Houtryve       return false;
701fa3d789dSPierre van Houtryve     }
702fa3d789dSPierre van Houtryve   }
703fa3d789dSPierre van Houtryve 
704fa3d789dSPierre van Houtryve   return true;
705fa3d789dSPierre van Houtryve }
706fa3d789dSPierre van Houtryve 
707fa3d789dSPierre van Houtryve bool PatFrag::buildOperandsTables() {
708fa3d789dSPierre van Houtryve   // enumerate(...) doesn't seem to allow lvalues so we need to count the old
709fa3d789dSPierre van Houtryve   // way.
710fa3d789dSPierre van Houtryve   unsigned Idx = 0;
711fa3d789dSPierre van Houtryve 
712fa3d789dSPierre van Houtryve   const auto DiagnoseRedef = [this, &Idx](StringRef OpName) {
713fa3d789dSPierre van Houtryve     PrintError("Operand '" + OpName +
714fa3d789dSPierre van Houtryve                "' is defined multiple times in patterns of alternative #" +
715fa3d789dSPierre van Houtryve                std::to_string(Idx));
716fa3d789dSPierre van Houtryve   };
717fa3d789dSPierre van Houtryve 
718fa3d789dSPierre van Houtryve   for (auto &Alt : Alts) {
719fa3d789dSPierre van Houtryve     for (auto &Pat : Alt.Pats) {
720fa3d789dSPierre van Houtryve       auto *IP = dyn_cast<InstructionPattern>(Pat.get());
721fa3d789dSPierre van Houtryve       if (!IP)
722fa3d789dSPierre van Houtryve         continue;
723fa3d789dSPierre van Houtryve 
724fa3d789dSPierre van Houtryve       if (!Alt.OpTable.addPattern(IP, DiagnoseRedef))
725fa3d789dSPierre van Houtryve         return false;
726fa3d789dSPierre van Houtryve     }
727fa3d789dSPierre van Houtryve 
728fa3d789dSPierre van Houtryve     ++Idx;
729fa3d789dSPierre van Houtryve   }
730fa3d789dSPierre van Houtryve 
731fa3d789dSPierre van Houtryve   return true;
732fa3d789dSPierre van Houtryve }
733fa3d789dSPierre van Houtryve 
734fa3d789dSPierre van Houtryve void PatFrag::print(raw_ostream &OS, StringRef Indent) const {
735fa3d789dSPierre van Houtryve   OS << Indent << "(PatFrag name:" << getName() << '\n';
736fa3d789dSPierre van Houtryve   if (!in_params().empty()) {
737fa3d789dSPierre van Houtryve     OS << Indent << "  (ins ";
738fa3d789dSPierre van Houtryve     printParamsList(OS, in_params());
739fa3d789dSPierre van Houtryve     OS << ")\n";
740fa3d789dSPierre van Houtryve   }
741fa3d789dSPierre van Houtryve 
742fa3d789dSPierre van Houtryve   if (!out_params().empty()) {
743fa3d789dSPierre van Houtryve     OS << Indent << "  (outs ";
744fa3d789dSPierre van Houtryve     printParamsList(OS, out_params());
745fa3d789dSPierre van Houtryve     OS << ")\n";
746fa3d789dSPierre van Houtryve   }
747fa3d789dSPierre van Houtryve 
748fa3d789dSPierre van Houtryve   // TODO: Dump OperandTable as well.
749fa3d789dSPierre van Houtryve   OS << Indent << "  (alternatives [\n";
750fa3d789dSPierre van Houtryve   for (const auto &Alt : Alts) {
751fa3d789dSPierre van Houtryve     OS << Indent << "    [\n";
752fa3d789dSPierre van Houtryve     for (const auto &Pat : Alt.Pats) {
753fa3d789dSPierre van Houtryve       OS << Indent << "      ";
754fa3d789dSPierre van Houtryve       Pat->print(OS, /*PrintName=*/true);
755fa3d789dSPierre van Houtryve       OS << ",\n";
756fa3d789dSPierre van Houtryve     }
757fa3d789dSPierre van Houtryve     OS << Indent << "    ],\n";
758fa3d789dSPierre van Houtryve   }
759fa3d789dSPierre van Houtryve   OS << Indent << "  ])\n";
760fa3d789dSPierre van Houtryve 
761fa3d789dSPierre van Houtryve   OS << Indent << ')';
762fa3d789dSPierre van Houtryve }
763fa3d789dSPierre van Houtryve 
764fa3d789dSPierre van Houtryve void PatFrag::dump() const { print(dbgs()); }
765fa3d789dSPierre van Houtryve 
766fa3d789dSPierre van Houtryve void PatFrag::printParamsList(raw_ostream &OS, iterator_range<ParamIt> Params) {
767fa3d789dSPierre van Houtryve   OS << '['
768fa3d789dSPierre van Houtryve      << join(map_range(Params,
769fa3d789dSPierre van Houtryve                        [](auto &O) {
770fa3d789dSPierre van Houtryve                          return (O.Name + ":" + getParamKindStr(O.Kind)).str();
771fa3d789dSPierre van Houtryve                        }),
772fa3d789dSPierre van Houtryve              ", ")
773fa3d789dSPierre van Houtryve      << ']';
774fa3d789dSPierre van Houtryve }
775fa3d789dSPierre van Houtryve 
776fa3d789dSPierre van Houtryve void PatFrag::PrintError(Twine Msg) const { llvm::PrintError(&Def, Msg); }
777fa3d789dSPierre van Houtryve 
778fa3d789dSPierre van Houtryve ArrayRef<InstructionOperand> PatFragPattern::getApplyDefsNeeded() const {
779fa3d789dSPierre van Houtryve   assert(PF.num_roots() == 1);
780fa3d789dSPierre van Houtryve   // Only roots need to be redef.
781fa3d789dSPierre van Houtryve   for (auto [Idx, Param] : enumerate(PF.out_params())) {
782fa3d789dSPierre van Houtryve     if (Param.Kind == PatFrag::PK_Root)
783fa3d789dSPierre van Houtryve       return getOperand(Idx);
784fa3d789dSPierre van Houtryve   }
785fa3d789dSPierre van Houtryve   llvm_unreachable("root not found!");
786fa3d789dSPierre van Houtryve }
787fa3d789dSPierre van Houtryve 
788fa3d789dSPierre van Houtryve //===- PatFragPattern -----------------------------------------------------===//
789fa3d789dSPierre van Houtryve 
790fa3d789dSPierre van Houtryve bool PatFragPattern::checkSemantics(ArrayRef<SMLoc> DiagLoc) {
791fa3d789dSPierre van Houtryve   if (!InstructionPattern::checkSemantics(DiagLoc))
792fa3d789dSPierre van Houtryve     return false;
793fa3d789dSPierre van Houtryve 
794fa3d789dSPierre van Houtryve   for (const auto &[Idx, Op] : enumerate(Operands)) {
795fa3d789dSPierre van Houtryve     switch (PF.getParam(Idx).Kind) {
796fa3d789dSPierre van Houtryve     case PatFrag::PK_Imm:
797fa3d789dSPierre van Houtryve       if (!Op.hasImmValue()) {
798fa3d789dSPierre van Houtryve         PrintError(DiagLoc, "expected operand " + std::to_string(Idx) +
799fa3d789dSPierre van Houtryve                                 " of '" + getInstName() +
800fa3d789dSPierre van Houtryve                                 "' to be an immediate; got " + Op.describe());
801fa3d789dSPierre van Houtryve         return false;
802fa3d789dSPierre van Houtryve       }
803fa3d789dSPierre van Houtryve       if (Op.isNamedImmediate()) {
804fa3d789dSPierre van Houtryve         PrintError(DiagLoc, "operand " + std::to_string(Idx) + " of '" +
805fa3d789dSPierre van Houtryve                                 getInstName() +
806fa3d789dSPierre van Houtryve                                 "' cannot be a named immediate");
807fa3d789dSPierre van Houtryve         return false;
808fa3d789dSPierre van Houtryve       }
809fa3d789dSPierre van Houtryve       break;
810fa3d789dSPierre van Houtryve     case PatFrag::PK_Root:
811fa3d789dSPierre van Houtryve     case PatFrag::PK_MachineOperand:
812fa3d789dSPierre van Houtryve       if (!Op.isNamedOperand() || Op.isNamedImmediate()) {
813fa3d789dSPierre van Houtryve         PrintError(DiagLoc, "expected operand " + std::to_string(Idx) +
814fa3d789dSPierre van Houtryve                                 " of '" + getInstName() +
815fa3d789dSPierre van Houtryve                                 "' to be a MachineOperand; got " +
816fa3d789dSPierre van Houtryve                                 Op.describe());
817fa3d789dSPierre van Houtryve         return false;
818fa3d789dSPierre van Houtryve       }
819fa3d789dSPierre van Houtryve       break;
820fa3d789dSPierre van Houtryve     }
821fa3d789dSPierre van Houtryve   }
822fa3d789dSPierre van Houtryve 
823fa3d789dSPierre van Houtryve   return true;
824fa3d789dSPierre van Houtryve }
825fa3d789dSPierre van Houtryve 
826fa3d789dSPierre van Houtryve bool PatFragPattern::mapInputCodeExpansions(const CodeExpansions &ParentCEs,
827fa3d789dSPierre van Houtryve                                             CodeExpansions &PatFragCEs,
828fa3d789dSPierre van Houtryve                                             ArrayRef<SMLoc> DiagLoc) const {
829fa3d789dSPierre van Houtryve   for (const auto &[Idx, Op] : enumerate(operands())) {
830fa3d789dSPierre van Houtryve     StringRef ParamName = PF.getParam(Idx).Name;
831fa3d789dSPierre van Houtryve 
832fa3d789dSPierre van Houtryve     // Operands to a PFP can only be named, or be an immediate, but not a named
833fa3d789dSPierre van Houtryve     // immediate.
834fa3d789dSPierre van Houtryve     assert(!Op.isNamedImmediate());
835fa3d789dSPierre van Houtryve 
836fa3d789dSPierre van Houtryve     if (Op.isNamedOperand()) {
837fa3d789dSPierre van Houtryve       StringRef ArgName = Op.getOperandName();
838fa3d789dSPierre van Houtryve       // Map it only if it's been defined.
839fa3d789dSPierre van Houtryve       auto It = ParentCEs.find(ArgName);
840fa3d789dSPierre van Houtryve       if (It == ParentCEs.end()) {
841fa3d789dSPierre van Houtryve         if (!PF.handleUnboundInParam(ParamName, ArgName, DiagLoc))
842fa3d789dSPierre van Houtryve           return false;
843fa3d789dSPierre van Houtryve       } else
844fa3d789dSPierre van Houtryve         PatFragCEs.declare(ParamName, It->second);
845fa3d789dSPierre van Houtryve       continue;
846fa3d789dSPierre van Houtryve     }
847fa3d789dSPierre van Houtryve 
848fa3d789dSPierre van Houtryve     if (Op.hasImmValue()) {
849fa3d789dSPierre van Houtryve       PatFragCEs.declare(ParamName, std::to_string(Op.getImmValue()));
850fa3d789dSPierre van Houtryve       continue;
851fa3d789dSPierre van Houtryve     }
852fa3d789dSPierre van Houtryve 
853fa3d789dSPierre van Houtryve     llvm_unreachable("Unknown Operand Type!");
854fa3d789dSPierre van Houtryve   }
855fa3d789dSPierre van Houtryve 
856fa3d789dSPierre van Houtryve   return true;
857fa3d789dSPierre van Houtryve }
858fa3d789dSPierre van Houtryve 
859fa3d789dSPierre van Houtryve //===- BuiltinPattern -----------------------------------------------------===//
860fa3d789dSPierre van Houtryve 
861fa3d789dSPierre van Houtryve BuiltinPattern::BuiltinInfo BuiltinPattern::getBuiltinInfo(const Record &Def) {
862fa3d789dSPierre van Houtryve   assert(Def.isSubClassOf(ClassName));
863fa3d789dSPierre van Houtryve 
864fa3d789dSPierre van Houtryve   StringRef Name = Def.getName();
865fa3d789dSPierre van Houtryve   for (const auto &KBI : KnownBuiltins) {
866fa3d789dSPierre van Houtryve     if (KBI.DefName == Name)
867fa3d789dSPierre van Houtryve       return KBI;
868fa3d789dSPierre van Houtryve   }
869fa3d789dSPierre van Houtryve 
870fa3d789dSPierre van Houtryve   PrintFatalError(Def.getLoc(),
871fa3d789dSPierre van Houtryve                   "Unimplemented " + ClassName + " def '" + Name + "'");
872fa3d789dSPierre van Houtryve }
873fa3d789dSPierre van Houtryve 
874fa3d789dSPierre van Houtryve bool BuiltinPattern::checkSemantics(ArrayRef<SMLoc> Loc) {
875fa3d789dSPierre van Houtryve   if (!InstructionPattern::checkSemantics(Loc))
876fa3d789dSPierre van Houtryve     return false;
877fa3d789dSPierre van Houtryve 
878fa3d789dSPierre van Houtryve   // For now all builtins just take names, no immediates.
879fa3d789dSPierre van Houtryve   for (const auto &[Idx, Op] : enumerate(operands())) {
880fa3d789dSPierre van Houtryve     if (!Op.isNamedOperand() || Op.isNamedImmediate()) {
881fa3d789dSPierre van Houtryve       PrintError(Loc, "expected operand " + std::to_string(Idx) + " of '" +
882fa3d789dSPierre van Houtryve                           getInstName() + "' to be a name");
883fa3d789dSPierre van Houtryve       return false;
884fa3d789dSPierre van Houtryve     }
885fa3d789dSPierre van Houtryve   }
886fa3d789dSPierre van Houtryve 
887fa3d789dSPierre van Houtryve   return true;
888fa3d789dSPierre van Houtryve }
889fa3d789dSPierre van Houtryve 
890fa3d789dSPierre van Houtryve } // namespace gi
891fa3d789dSPierre van Houtryve } // namespace llvm
892