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