llvm.org GIT mirror llvm / cc3830e
[globalisel][tablegen] Revise API for ComplexPattern operands to improve flexibility. Summary: Some targets need to be able to do more complex rendering than just adding an operand or two to an instruction. For example, it may need to insert an instruction to extract a subreg first, or it may need to perform an operation on the operand. In SelectionDAG, targets would create SDNode's to achieve the desired effect during the complex pattern predicate. This worked because SelectionDAG had a form of garbage collection that would take care of SDNode's that were created but not used due to a later predicate rejecting a match. This doesn't translate well to GlobalISel and the churn was wasteful. The API changes in this patch enable GlobalISel to accomplish the same thing without the waste. The API is now: InstructionSelector::OptionalComplexRendererFn selectArithImmed(MachineOperand &Root) const; where Root is the root of the match. The return value can be omitted to indicate that the predicate failed to match, or a function with the signature ComplexRendererFn can be returned. For example: return OptionalComplexRendererFn( [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed).addImm(ShVal); }); adds two immediate operands to the rendered instruction. Immed and ShVal are captured from the predicate function. As an added bonus, this also reduces the amount of information we need to provide to GIComplexOperandMatcher. Depends on D31418 Reviewers: aditya_nandakumar, t.p.northover, qcolombet, rovka, ab, javed.absar Reviewed By: ab Subscribers: dberris, kristof.beyls, igorb, llvm-commits Differential Revision: https://reviews.llvm.org/D31761 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301079 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 3 years ago
10 changed file(s) with 63 addition(s) and 157 deletion(s). Raw diff Collapse all Expand all
1818 #include "llvm/ADT/Optional.h"
1919 #include
2020 #include
21 #include
2122
2223 namespace llvm {
2324 class MachineInstr;
25 class MachineInstrBuilder;
2426 class MachineFunction;
2527 class MachineOperand;
2628 class MachineRegisterInfo;
7577 virtual bool select(MachineInstr &I) const = 0;
7678
7779 protected:
80 typedef std::function ComplexRendererFn;
81
7882 InstructionSelector();
7983
8084 /// Mutate the newly-selected instruction \p I to constrain its (possibly
6464 MO_CFIIndex, ///< MCCFIInstruction index.
6565 MO_IntrinsicID, ///< Intrinsic ID for ISel
6666 MO_Predicate, ///< Generic predicate for ISel
67 MO_Placeholder, ///< Placeholder for GlobalISel ComplexPattern result.
6867 };
6968
7069 private:
767766 return Op;
768767 }
769768
770 static MachineOperand CreatePlaceholder() {
771 MachineOperand Op(MachineOperand::MO_Placeholder);
772 return Op;
773 }
774
775769 friend class MachineInstr;
776770 friend class MachineRegisterInfo;
777771 private:
2929 // Definitions that inherit from this may also inherit from
3030 // GIComplexPatternEquiv to enable the import of SelectionDAG patterns involving
3131 // those ComplexPatterns.
32 class GIComplexOperandMatcherdag operands, string matcherfn> {
32 class GIComplexOperandMatcherstring matcherfn> {
3333 // The expected type of the root of the match.
3434 //
3535 // TODO: We should probably support, any-type, any-scalar, and multiple types
3636 // in the future.
3737 LLT Type = type;
38
39 // The operands that result from a successful match
40 // Should be of the form '(ops ty1, ty2, ...)' where ty1/ty2 are definitions
41 // that inherit from Operand.
42 //
43 // FIXME: Which definition is used for ty1/ty2 doesn't actually matter at the
44 // moment. Only the number of operands is used.
45 dag Operands = operands;
4638
4739 // The function that determines whether the operand matches. It should be of
4840 // the form:
924924 << CmpInst::getPredicateName(Pred) << ')';
925925 break;
926926 }
927 case MachineOperand::MO_Placeholder:
928 OS << "";
929 break;
930927 }
931928 }
932929
286286 return getIntrinsicID() == Other.getIntrinsicID();
287287 case MachineOperand::MO_Predicate:
288288 return getPredicate() == Other.getPredicate();
289 case MachineOperand::MO_Placeholder:
290 return true;
291289 }
292290 llvm_unreachable("Invalid machine operand type");
293291 }
336334 return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getIntrinsicID());
337335 case MachineOperand::MO_Predicate:
338336 return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getPredicate());
339 case MachineOperand::MO_Placeholder:
340 return hash_combine();
341337 }
342338 llvm_unreachable("Invalid machine operand type");
343339 }
514510 << CmpInst::getPredicateName(Pred) << '>';
515511 break;
516512 }
517 case MachineOperand::MO_Placeholder:
518 OS << "";
519 break;
520513 }
521514 if (unsigned TF = getTargetFlags())
522515 OS << "[TF=" << TF << ']';
692692 def addsub_shifted_imm64_neg : addsub_shifted_imm_neg;
693693
694694 def gi_addsub_shifted_imm32 :
695 GIComplexOperandMatcher(ops i32imm, i32imm), "selectArithImmed">,
695 GIComplexOperandMatcher"selectArithImmed">,
696696 GIComplexPatternEquiv;
697697
698698 def gi_addsub_shifted_imm64 :
699 GIComplexOperandMatcher(ops i32imm, i32imm), "selectArithImmed">,
699 GIComplexOperandMatcher"selectArithImmed">,
700700 GIComplexPatternEquiv;
701701
702702 class neg_addsub_shifted_imm
6666 bool selectCompareBranch(MachineInstr &I, MachineFunction &MF,
6767 MachineRegisterInfo &MRI) const;
6868
69 bool selectArithImmed(MachineOperand &Root, MachineOperand &Result1,
70 MachineOperand &Result2) const;
69 ComplexRendererFn selectArithImmed(MachineOperand &Root) const;
7170
7271 const AArch64TargetMachine &TM;
7372 const AArch64Subtarget &STI;
13281327 /// SelectArithImmed - Select an immediate value that can be represented as
13291328 /// a 12-bit value shifted left by either 0 or 12. If so, return true with
13301329 /// Val set to the 12-bit value and Shift set to the shifter operand.
1331 bool AArch64InstructionSelector::selectArithImmed(
1332 MachineOperand &Root, MachineOperand &Result1,
1333 MachineOperand &Result2) const {
1330 InstructionSelector::ComplexRendererFn
1331 AArch64InstructionSelector::selectArithImmed(MachineOperand &Root) const {
13341332 MachineInstr &MI = *Root.getParent();
13351333 MachineBasicBlock &MBB = *MI.getParent();
13361334 MachineFunction &MF = *MBB.getParent();
13491347 else if (Root.isReg()) {
13501348 MachineInstr *Def = MRI.getVRegDef(Root.getReg());
13511349 if (Def->getOpcode() != TargetOpcode::G_CONSTANT)
1352 return false;
1350 return nullptr;
13531351 MachineOperand &Op1 = Def->getOperand(1);
13541352 if (!Op1.isCImm() || Op1.getCImm()->getBitWidth() > 64)
1355 return false;
1353 return nullptr;
13561354 Immed = Op1.getCImm()->getZExtValue();
13571355 } else
1358 return false;
1356 return nullptr;
13591357
13601358 unsigned ShiftAmt;
13611359
13651363 ShiftAmt = 12;
13661364 Immed = Immed >> 12;
13671365 } else
1368 return false;
1366 return nullptr;
13691367
13701368 unsigned ShVal = AArch64_AM::getShifterImm(AArch64_AM::LSL, ShiftAmt);
1371 Result1.ChangeToImmediate(Immed);
1372 Result1.clearParent();
1373 Result2.ChangeToImmediate(ShVal);
1374 Result2.clearParent();
1375 return true;
1369 return [=](MachineInstrBuilder &MIB) { MIB.addImm(Immed).addImm(ShVal); };
13761370 }
13771371
13781372 namespace llvm {
660660 return false;
661661 case MachineOperand::MO_IntrinsicID:
662662 case MachineOperand::MO_Predicate:
663 case MachineOperand::MO_Placeholder:
664663 llvm_unreachable("should not exist post-isel");
665664 }
666665 llvm_unreachable("unhandled machine operand type");
2121 let MIOperandInfo = (ops i32imm, i32imm);
2222 }
2323 def gi_complex :
24 GIComplexOperandMatcher(ops i32imm, i32imm), "selectComplexPattern">,
24 GIComplexOperandMatcher"selectComplexPattern">,
2525 GIComplexPatternEquiv;
2626
2727 def m1 : OperandWithDefaultOps ;
7171 // CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
7272 // CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
7373 // CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
74 // CHECK-NEXT: (selectComplexPattern(MI0.getOperand(2), TempOp0, TempOp1)))) &&
74 // CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2)))))) &&
7575 // CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(3).getReg()) == (LLT::scalar(32))) &&
76 // CHECK-NEXT: (selectComplexPattern(MI0.getOperand(3), TempOp2, TempOp3))))) {
76 // CHECK-NEXT: ((Renderer1 = selectComplexPattern(MI0.getOperand(3))))))) {
7777 // CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, complex:i32:$src3) => (INSN2:i32 GPR32:i32:$src1, complex:i32:$src3, complex:i32:$src2)
7878 // CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN2));
7979 // CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
8080 // CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
81 // CHECK-NEXT: MIB.add(TempOp2);
82 // CHECK-NEXT: MIB.add(TempOp3);
83 // CHECK-NEXT: MIB.add(TempOp0);
84 // CHECK-NEXT: MIB.add(TempOp1);
81 // CHECK-NEXT: Renderer1(MIB);
82 // CHECK-NEXT: Renderer0(MIB);
8583 // CHECK-NEXT: for (const auto *FromMI : {&MI0, })
8684 // CHECK-NEXT: for (const auto &MMO : FromMI->memoperands())
8785 // CHECK-NEXT: MIB.addMemOperand(MMO);
262260 // CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
263261 // CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
264262 // CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
265 // CHECK-NEXT: (selectComplexPattern(MI0.getOperand(2), TempOp0, TempOp1))))) {
263 // CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2))))))) {
266264 // CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2)
267265 // CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN1));
268266 // CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
269267 // CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
270 // CHECK-NEXT: MIB.add(TempOp0);
271 // CHECK-NEXT: MIB.add(TempOp1);
268 // CHECK-NEXT: Renderer0(MIB);
272269 // CHECK-NEXT: for (const auto *FromMI : {&MI0, })
273270 // CHECK-NEXT: for (const auto &MMO : FromMI->memoperands())
274271 // CHECK-NEXT: MIB.addMemOperand(MMO);
9090 };
9191
9292 class InstructionMatcher;
93 class OperandPlaceholder {
94 private:
95 enum PlaceholderKind {
96 OP_MatchReference,
97 OP_Temporary,
98 } Kind;
99
100 struct MatchReferenceData {
101 InstructionMatcher *InsnMatcher;
102 StringRef InsnVarName;
103 StringRef SymbolicName;
104 };
105
106 struct TemporaryData {
107 unsigned OpIdx;
108 };
109
110 union {
111 struct MatchReferenceData MatchReference;
112 struct TemporaryData Temporary;
113 };
114
115 OperandPlaceholder(PlaceholderKind Kind) : Kind(Kind) {}
116
117 public:
118 ~OperandPlaceholder() {}
119
120 static OperandPlaceholder
121 CreateMatchReference(InstructionMatcher *InsnMatcher,
122 StringRef InsnVarName, StringRef SymbolicName) {
123 OperandPlaceholder Result(OP_MatchReference);
124 Result.MatchReference.InsnMatcher = InsnMatcher;
125 Result.MatchReference.InsnVarName = InsnVarName;
126 Result.MatchReference.SymbolicName = SymbolicName;
127 return Result;
128 }
129
130 static OperandPlaceholder CreateTemporary(unsigned OpIdx) {
131 OperandPlaceholder Result(OP_Temporary);
132 Result.Temporary.OpIdx = OpIdx;
133 return Result;
134 }
135
136 void emitCxxValueExpr(raw_ostream &OS) const;
137 };
138
13993 /// Convert an MVT to an equivalent LLT if possible, or the invalid LLT() for
14094 /// MVTs that don't map cleanly to an LLT (e.g., iPTR, *any, ...).
14195 static Optional MVTToLLT(MVT::SimpleValueType SVT) {
255209
256210 /// Report the maximum number of temporary operands needed by the rule
257211 /// matcher.
258 unsigned countTemporaryOperands() const;
212 unsigned countRendererFns() const;
213
214 // FIXME: Remove this as soon as possible
215 InstructionMatcher &insnmatcher_front() const { return *Matchers.front(); }
259216 };
260217
261218 template class PredicateListMatcher {
360317
361318 /// Report the maximum number of temporary operands needed by the predicate
362319 /// matcher.
363 virtual unsigned countTemporaryOperands() const { return 0; }
320 virtual unsigned countRendererFns() const { return 0; }
364321 };
365322
366323 /// Generates code to check that an operand is a particular LLT.
390347 const OperandMatcher &Operand;
391348 const Record &TheDef;
392349
393 unsigned getNumOperands() const {
394 return TheDef.getValueAsDag("Operands")->getNumArgs();
395 }
396
397350 unsigned getAllocatedTemporariesBaseID() const;
398351
399352 public:
408361
409362 void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule,
410363 StringRef OperandExpr) const override {
411 OS << TheDef.getValueAsString("MatcherFn") << "(" << OperandExpr;
412 for (unsigned I = 0; I < getNumOperands(); ++I) {
413 OS << ", ";
414 OperandPlaceholder::CreateTemporary(getAllocatedTemporariesBaseID() + I)
415 .emitCxxValueExpr(OS);
416 }
417 OS << ")";
418 }
419
420 unsigned countTemporaryOperands() const override {
421 return getNumOperands();
364 unsigned ID = getAllocatedTemporariesBaseID();
365 OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn")
366 << "(" << OperandExpr << "))";
367 }
368
369 unsigned countRendererFns() const override {
370 return 1;
422371 }
423372 };
424373
487436
488437 /// The index of the first temporary variable allocated to this operand. The
489438 /// number of allocated temporaries can be found with
490 /// countTemporaryOperands().
439 /// countRendererFns().
491440 unsigned AllocatedTemporariesBaseID;
492441
493442 public:
568517
569518 /// Report the maximum number of temporary operands needed by the operand
570519 /// matcher.
571 unsigned countTemporaryOperands() const {
520 unsigned countRendererFns() const {
572521 return std::accumulate(
573522 predicates().begin(), predicates().end(), 0,
574523 [](unsigned A,
575524 const std::unique_ptr &Predicate) {
576 return A + Predicate->countTemporaryOperands();
525 return A + Predicate->countRendererFns();
577526 });
578527 }
579528
622571
623572 /// Report the maximum number of temporary operands needed by the predicate
624573 /// matcher.
625 virtual unsigned countTemporaryOperands() const { return 0; }
574 virtual unsigned countRendererFns() const { return 0; }
626575 };
627576
628577 /// Generates code to check the opcode of an instruction.
779728
780729 /// Report the maximum number of temporary operands needed by the instruction
781730 /// matcher.
782 unsigned countTemporaryOperands() const {
731 unsigned countRendererFns() const {
783732 return std::accumulate(predicates().begin(), predicates().end(), 0,
784733 [](unsigned A,
785734 const std::unique_ptr
786735 &Predicate) {
787 return A + Predicate->countTemporaryOperands();
736 return A + Predicate->countRendererFns();
788737 }) +
789738 std::accumulate(
790739 Operands.begin(), Operands.end(), 0,
791740 [](unsigned A, const std::unique_ptr &Operand) {
792 return A + Operand->countTemporaryOperands();
741 return A + Operand->countRendererFns();
793742 });
794743 }
795744 };
844793 };
845794
846795 //===- Actions ------------------------------------------------------------===//
847 void OperandPlaceholder::emitCxxValueExpr(raw_ostream &OS) const {
848 switch (Kind) {
849 case OP_MatchReference:
850 OS << MatchReference.InsnMatcher->getOperand(MatchReference.SymbolicName)
851 .getOperandExpr(MatchReference.InsnVarName);
852 break;
853 case OP_Temporary:
854 OS << "TempOp" << Temporary.OpIdx;
855 break;
856 }
857 }
858
859796 class OperandRenderer {
860797 public:
861798 enum RendererKind { OR_Copy, OR_Imm, OR_Register, OR_ComplexPattern };
941878 }
942879 };
943880
881 /// Adds operands by calling a renderer function supplied by the ComplexPattern
882 /// matcher function.
944883 class RenderComplexPatternOperand : public OperandRenderer {
945884 private:
946885 const Record &TheDef;
947 std::vector Sources;
886 /// The name of the operand.
887 const StringRef SymbolicName;
888 /// The renderer number. This must be unique within a rule since it's used to
889 /// identify a temporary variable to hold the renderer function.
890 unsigned RendererID;
948891
949892 unsigned getNumOperands() const {
950893 return TheDef.getValueAsDag("Operands")->getNumArgs();
951894 }
952895
953896 public:
954 RenderComplexPatternOperand(const Record &TheDef,
955 const ArrayRef Sources)
956 : OperandRenderer(OR_ComplexPattern), TheDef(TheDef), Sources(Sources) {}
897 RenderComplexPatternOperand(const Record &TheDef, StringRef SymbolicName,
898 unsigned RendererID)
899 : OperandRenderer(OR_ComplexPattern), TheDef(TheDef),
900 SymbolicName(SymbolicName), RendererID(RendererID) {}
957901
958902 static bool classof(const OperandRenderer *R) {
959903 return R->getKind() == OR_ComplexPattern;
960904 }
961905
962906 void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override {
963 assert(Sources.size() == getNumOperands() && "Inconsistent number of operands");
964 for (const auto &Source : Sources) {
965 OS << "MIB.add(";
966 Source.emitCxxValueExpr(OS);
967 OS << ");\n";
968 }
907 OS << "Renderer" << RendererID << "(MIB);\n";
969908 }
970909 };
971910
12481187 return false;
12491188 }
12501189
1251 unsigned RuleMatcher::countTemporaryOperands() const {
1190 unsigned RuleMatcher::countRendererFns() const {
12521191 return std::accumulate(
12531192 Matchers.begin(), Matchers.end(), 0,
12541193 [](unsigned A, const std::unique_ptr &Matcher) {
1255 return A + Matcher->countTemporaryOperands();
1194 return A + Matcher->countRendererFns();
12561195 });
12571196 }
12581197
14511390 return failedImport("SelectionDAG ComplexPattern (" +
14521391 ChildRec->getName() + ") not mapped to GlobalISel");
14531392
1454 const auto &Predicate = OM.addPredicate(
1455 OM, *ComplexPattern->second);
1456 TempOpIdx += Predicate.countTemporaryOperands();
1393 OM.addPredicate(OM,
1394 *ComplexPattern->second);
1395 TempOpIdx++;
14571396 return Error::success();
14581397 }
14591398
15181457 return failedImport(
15191458 "SelectionDAG ComplexPattern not mapped to GlobalISel");
15201459
1521 SmallVector RenderedOperands;
15221460 const OperandMatcher &OM = InsnMatcher.getOperand(DstChild->getName());
1523 for (unsigned I = 0; I < OM.countTemporaryOperands(); ++I)
1524 RenderedOperands.push_back(OperandPlaceholder::CreateTemporary(
1525 OM.getAllocatedTemporariesBaseID() + I));
15261461 DstMIBuilder.addRenderer(
1527 *ComplexPattern->second, RenderedOperands);
1462 *ComplexPattern->second, DstChild->getName(),
1463 OM.getAllocatedTemporariesBaseID());
15281464 return Error::success();
15291465 }
15301466
17441680
17451681 unsigned MaxTemporaries = 0;
17461682 for (const auto &Rule : Rules)
1747 MaxTemporaries = std::max(MaxTemporaries, Rule.countTemporaryOperands());
1683 MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns());
17481684
17491685 OS << "#ifdef GET_GLOBALISEL_PREDICATE_BITSET\n"
17501686 << "const unsigned MAX_SUBTARGET_PREDICATES = " << SubtargetFeatures.size()
17551691
17561692 OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n";
17571693 for (unsigned I = 0; I < MaxTemporaries; ++I)
1758 OS << " mutable MachineOperand TempOp" << I << ";\n";
1694 OS << " mutable ComplexRendererFn Renderer" << I << ";\n";
17591695 OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n";
17601696
17611697 OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n";
17621698 for (unsigned I = 0; I < MaxTemporaries; ++I)
1763 OS << ", TempOp" << I << "(MachineOperand::CreatePlaceholder())\n";
1699 OS << ", Renderer" << I << "(nullptr)\n";
17641700 OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
17651701
17661702 OS << "#ifdef GET_GLOBALISEL_IMPL\n";