def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
[(set GPR32:$dst, (xor GPR32:$src1, -4))]>;
+//===- Test a simple pattern with multiple operands with defaults. --------===//
+//
+
+// CHECK-LABEL: if ([&]() {
+// CHECK-NEXT: MachineInstr &MI0 = I;
+// CHECK-NEXT: if (MI0.getNumOperands() < 3)
+// CHECK-NEXT: return false;
+// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) &&
+// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) &&
+// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) &&
+// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -5, MRI))))) {
+// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1)
+// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORManyDefaults));
+// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/);
+// CHECK-NEXT: MIB.addImm(-1);
+// CHECK-NEXT: MIB.addReg(MyTarget::R0);
+// CHECK-NEXT: MIB.addReg(MyTarget::R0);
+// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/);
+// CHECK-NEXT: for (const auto *FromMI : {&MI0, })
+// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands())
+// CHECK-NEXT: MIB.addMemOperand(MMO);
+// CHECK-NEXT: I.eraseFromParent();
+// CHECK-NEXT: MachineInstr &NewI = *MIB;
+// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI);
+// CHECK-NEXT: return true;
+// CHECK-NEXT: }
+// CHECK-NEXT: return false;
+// CHECK-NEXT: }()) { return true; }
+
+// The -5 is just to distinguish it from the other cases.
+def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1),
+ [(set GPR32:$dst, (xor GPR32:$src1, -5))]>;
+
//===- Test a simple pattern with constant immediate operands. ------------===//
//
// This must precede the 3-register variants because constant immediates have
Error importExplicitUseRenderer(BuildMIAction &DstMIBuilder,
TreePatternNode *DstChild,
const InstructionMatcher &InsnMatcher) const;
+ Error importDefaultOperandRenderers(BuildMIAction &DstMIBuilder,
+ DagInit *DefaultOps) const;
Error
importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
const std::vector<Record *> &ImplicitDefs) const;
DstMIBuilder.addRenderer<CopyRenderer>(InsnMatcher, DstIOperand.Name);
}
- // Figure out which operands need defaults inserted. Operands that subclass
- // OperandWithDefaultOps are considered from left to right until we have
- // enough operands to render the instruction.
- SmallSet<unsigned, 2> DefaultOperands;
- unsigned DstINumUses = DstI.Operands.size() - DstI.Operands.NumDefs;
- unsigned NumDefaultOperands = 0;
- for (unsigned I = 0; I < DstINumUses &&
- DstINumUses > Dst->getNumChildren() + NumDefaultOperands;
- ++I) {
- const auto &DstIOperand = DstI.Operands[DstI.Operands.NumDefs + I];
- if (DstIOperand.Rec->isSubClassOf("OperandWithDefaultOps")) {
- DefaultOperands.insert(I);
- NumDefaultOperands +=
- DstIOperand.Rec->getValueAsDag("DefaultOps")->getNumArgs();
- }
- }
- if (DstINumUses > Dst->getNumChildren() + DefaultOperands.size())
- return failedImport("Insufficient operands supplied and default ops "
- "couldn't make up the shortfall");
- if (DstINumUses < Dst->getNumChildren() + DefaultOperands.size())
- return failedImport("Too many operands supplied");
-
// Render the explicit uses.
unsigned Child = 0;
+ unsigned DstINumUses = DstI.Operands.size() - DstI.Operands.NumDefs;
+ unsigned NumDefaultOps = 0;
for (unsigned I = 0; I != DstINumUses; ++I) {
- // If we need to insert default ops here, then do so.
- if (DefaultOperands.count(I)) {
- const auto &DstIOperand = DstI.Operands[DstI.Operands.NumDefs + I];
+ const auto &DstIOperand = DstI.Operands[DstI.Operands.NumDefs + I];
+ // If the operand has default values, introduce them now.
+ // FIXME: Until we have a decent test case that dictates we should do
+ // otherwise, we're going to assume that operands with default values cannot
+ // be specified in the patterns. Therefore, adding them will not cause us to
+ // end up with too many rendered operands.
+ if (DstIOperand.Rec->isSubClassOf("OperandWithDefaultOps")) {
DagInit *DefaultOps = DstIOperand.Rec->getValueAsDag("DefaultOps");
- for (const auto *DefaultOp : DefaultOps->args()) {
- // Look through ValueType operators.
- if (const DagInit *DefaultDagOp = dyn_cast<DagInit>(DefaultOp)) {
- if (const DefInit *DefaultDagOperator =
- dyn_cast<DefInit>(DefaultDagOp->getOperator())) {
- if (DefaultDagOperator->getDef()->isSubClassOf("ValueType"))
- DefaultOp = DefaultDagOp->getArg(0);
- }
- }
-
- if (const DefInit *DefaultDefOp = dyn_cast<DefInit>(DefaultOp)) {
- DstMIBuilder.addRenderer<AddRegisterRenderer>(DefaultDefOp->getDef());
- continue;
- }
-
- if (const IntInit *DefaultIntOp = dyn_cast<IntInit>(DefaultOp)) {
- DstMIBuilder.addRenderer<ImmRenderer>(DefaultIntOp->getValue());
- continue;
- }
-
- return failedImport("Could not add default op");
- }
-
+ if (auto Error = importDefaultOperandRenderers(DstMIBuilder, DefaultOps))
+ return std::move(Error);
+ ++NumDefaultOps;
continue;
}
++Child;
}
+ if (NumDefaultOps + Dst->getNumChildren() != DstINumUses)
+ return failedImport("Expected " + std::to_string(DstINumUses) +
+ " used operands but found " +
+ std::to_string(Dst->getNumChildren()) +
+ " explicit ones and " + std::to_string(NumDefaultOps) +
+ " default ones");
+
return DstMIBuilder;
}
+Error GlobalISelEmitter::importDefaultOperandRenderers(
+ BuildMIAction &DstMIBuilder, DagInit *DefaultOps) const {
+ for (const auto *DefaultOp : DefaultOps->args()) {
+ // Look through ValueType operators.
+ if (const DagInit *DefaultDagOp = dyn_cast<DagInit>(DefaultOp)) {
+ if (const DefInit *DefaultDagOperator =
+ dyn_cast<DefInit>(DefaultDagOp->getOperator())) {
+ if (DefaultDagOperator->getDef()->isSubClassOf("ValueType"))
+ DefaultOp = DefaultDagOp->getArg(0);
+ }
+ }
+
+ if (const DefInit *DefaultDefOp = dyn_cast<DefInit>(DefaultOp)) {
+ DstMIBuilder.addRenderer<AddRegisterRenderer>(DefaultDefOp->getDef());
+ continue;
+ }
+
+ if (const IntInit *DefaultIntOp = dyn_cast<IntInit>(DefaultOp)) {
+ DstMIBuilder.addRenderer<ImmRenderer>(DefaultIntOp->getValue());
+ continue;
+ }
+
+ return failedImport("Could not add default op");
+ }
+
+ return Error::success();
+}
+
Error GlobalISelEmitter::importImplicitDefRenderers(
BuildMIAction &DstMIBuilder,
const std::vector<Record *> &ImplicitDefs) const {