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