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