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