Index: llvm/trunk/test/TableGen/GlobalISelEmitter.td =================================================================== --- llvm/trunk/test/TableGen/GlobalISelEmitter.td +++ llvm/trunk/test/TableGen/GlobalISelEmitter.td @@ -387,6 +387,42 @@ 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 Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -1242,6 +1242,8 @@ Error importExplicitUseRenderer(BuildMIAction &DstMIBuilder, TreePatternNode *DstChild, const InstructionMatcher &InsnMatcher) const; + Error importDefaultOperandRenderers(BuildMIAction &DstMIBuilder, + DagInit *DefaultOps) const; Error importImplicitDefRenderers(BuildMIAction &DstMIBuilder, const std::vector &ImplicitDefs) const; @@ -1509,59 +1511,23 @@ DstMIBuilder.addRenderer(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 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(DefaultOp)) { - if (const DefInit *DefaultDagOperator = - dyn_cast(DefaultDagOp->getOperator())) { - if (DefaultDagOperator->getDef()->isSubClassOf("ValueType")) - DefaultOp = DefaultDagOp->getArg(0); - } - } - - if (const DefInit *DefaultDefOp = dyn_cast(DefaultOp)) { - DstMIBuilder.addRenderer(DefaultDefOp->getDef()); - continue; - } - - if (const IntInit *DefaultIntOp = dyn_cast(DefaultOp)) { - DstMIBuilder.addRenderer(DefaultIntOp->getValue()); - continue; - } - - return failedImport("Could not add default op"); - } - + if (auto Error = importDefaultOperandRenderers(DstMIBuilder, DefaultOps)) + return std::move(Error); + ++NumDefaultOps; continue; } @@ -1571,9 +1537,44 @@ ++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(DefaultOp)) { + if (const DefInit *DefaultDagOperator = + dyn_cast(DefaultDagOp->getOperator())) { + if (DefaultDagOperator->getDef()->isSubClassOf("ValueType")) + DefaultOp = DefaultDagOp->getArg(0); + } + } + + if (const DefInit *DefaultDefOp = dyn_cast(DefaultOp)) { + DstMIBuilder.addRenderer(DefaultDefOp->getDef()); + continue; + } + + if (const IntInit *DefaultIntOp = dyn_cast(DefaultOp)) { + DstMIBuilder.addRenderer(DefaultIntOp->getValue()); + continue; + } + + return failedImport("Could not add default op"); + } + + return Error::success(); +} + Error GlobalISelEmitter::importImplicitDefRenderers( BuildMIAction &DstMIBuilder, const std::vector &ImplicitDefs) const {