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