Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Common/GlobalISel/Patterns.cpp
35315 views
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
PrintError(DiagLoc, DiagCtx + ": unknown type '" + R->getName() + "'");
50
return std::nullopt;
51
}
52
53
PatternType PatternType::getTypeOf(StringRef OpName) {
54
PatternType PT(PT_TypeOf);
55
PT.Data.Str = OpName;
56
return PT;
57
}
58
59
StringRef PatternType::getTypeOfOpName() const {
60
assert(isTypeOf());
61
return Data.Str;
62
}
63
64
const Record *PatternType::getLLTRecord() const {
65
assert(isLLT());
66
return Data.Def;
67
}
68
69
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
85
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
100
void Pattern::dump() const { return print(dbgs()); }
101
102
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
119
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
130
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
142
CXXPattern::CXXPattern(const StringInit &Code, StringRef Name)
143
: CXXPattern(Code.getAsUnquotedString(), Name) {}
144
145
const CXXPredicateCode &
146
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
161
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
171
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
180
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
199
void InstructionOperand::dump() const { return print(dbgs()); }
200
201
//===- InstructionPattern -------------------------------------------------===//
202
203
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
217
void InstructionPattern::reportUnreachable(ArrayRef<SMLoc> Locs) const {
218
PrintError(Locs, "pattern '" + getName() + "' ('" + getInstName() +
219
"') is unreachable from the pattern root!");
220
}
221
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
247
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
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
292
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
314
void OperandTable::dump() const { print(dbgs()); }
315
316
//===- MIFlagsInfo --------------------------------------------------------===//
317
318
void MIFlagsInfo::addSetFlag(const Record *R) {
319
SetF.insert(R->getValueAsString("EnumName"));
320
}
321
322
void MIFlagsInfo::addUnsetFlag(const Record *R) {
323
UnsetF.insert(R->getValueAsString("EnumName"));
324
}
325
326
void MIFlagsInfo::addCopyFlag(StringRef InstName) { CopyF.insert(InstName); }
327
328
//===- CodeGenInstructionPattern ------------------------------------------===//
329
330
bool CodeGenInstructionPattern::is(StringRef OpcodeName) const {
331
return I.TheDef->getName() == OpcodeName;
332
}
333
334
bool CodeGenInstructionPattern::isVariadic() const {
335
return !isIntrinsic() && I.Operands.isVariadic;
336
}
337
338
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
355
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
366
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
375
MIFlagsInfo &CodeGenInstructionPattern::getOrCreateMIFlagsInfo() {
376
if (!FI)
377
FI = std::make_unique<MIFlagsInfo>();
378
return *FI;
379
}
380
381
StringRef CodeGenInstructionPattern::getInstName() const {
382
return I.TheDef->getName();
383
}
384
385
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
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
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
452
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
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
474
PatFrag::PatFrag(const Record &Def) : Def(Def) {
475
assert(Def.isSubClassOf(ClassName));
476
}
477
478
StringRef PatFrag::getName() const { return Def.getName(); }
479
480
ArrayRef<SMLoc> PatFrag::getLoc() const { return Def.getLoc(); }
481
482
void PatFrag::addInParam(StringRef Name, ParamKind Kind) {
483
Params.emplace_back(Param{Name, Kind});
484
}
485
486
iterator_range<PatFrag::ParamIt> PatFrag::in_params() const {
487
return {Params.begin() + NumOutParams, Params.end()};
488
}
489
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
497
iterator_range<PatFrag::ParamIt> PatFrag::out_params() const {
498
return {Params.begin(), Params.begin() + NumOutParams};
499
}
500
501
unsigned PatFrag::num_roots() const {
502
return count_if(out_params(),
503
[&](const auto &P) { return P.Kind == PK_Root; });
504
}
505
506
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
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
634
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
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
695
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
725
void PatFrag::dump() const { print(dbgs()); }
726
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
737
void PatFrag::PrintError(Twine Msg) const { llvm::PrintError(&Def, Msg); }
738
739
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
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
787
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
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
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
854