Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -62,6 +62,18 @@ }; enum { + /// Begin a try-block to attempt a match but and jump to OnFail if it is + /// unsuccessful. + /// - OnFail - The MatchTable entry at which to resume if the match fails. + /// + /// FIXME: This ought to take an argument indicating the number of try-blocks + /// to exit on failure. It's usually one but the last match attempt of + /// a block will need more. The (implemented) alternative is to tack a + /// GIM_Reject on the end of each try-block which is simpler but + /// requires an extra opcode and iteration in the interpreter on each + /// failed match. + GIM_Try, + /// Record the specified instruction /// - NewInsnID - Instruction ID to define /// - InsnID - Instruction ID @@ -102,7 +114,8 @@ /// - OpIdx - Operand index /// - Expected integer GIM_CheckConstantInt, - /// Check the operand is a specific literal integer (i.e. MO.isImm() or MO.isCImm() is true). + /// Check the operand is a specific literal integer (i.e. MO.isImm() or + /// MO.isCImm() is true). /// - InsnID - Instruction ID /// - OpIdx - Operand index /// - Expected integer @@ -122,6 +135,10 @@ /// - InsnID - Instruction ID GIM_CheckIsSafeToFold, + /// Fail the current try-block, or completely fail to match if there is no + /// current try-block. + GIM_Reject, + //=== Renderers === /// Mutate an instruction Index: include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -26,13 +26,34 @@ MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures) const { - const int64_t *Command = MatchTable; + uint64_t CurrentIdx = 0; + SmallVector OnFailResumeAt; + + enum RejectAction { RejectAndGiveUp, RejectAndResume }; + auto handleReject = [&]() -> enum RejectAction { + DEBUG(dbgs() << CurrentIdx << ": Rejected\n"); + if (OnFailResumeAt.empty()) + return RejectAndGiveUp; + CurrentIdx = OnFailResumeAt.back(); + OnFailResumeAt.pop_back(); + DEBUG(dbgs() << CurrentIdx << ": Resume at " << CurrentIdx << " (" + << OnFailResumeAt.size() << " try-blocks remain)\n"); + return RejectAndResume; + }; + while (true) { - switch (*Command++) { + assert(CurrentIdx != ~0u && "Invalid MatchTable index"); + switch (MatchTable[CurrentIdx++]) { + case GIM_Try: { + DEBUG(dbgs() << CurrentIdx << ": Begin try-block\n"); + OnFailResumeAt.push_back(MatchTable[CurrentIdx++]); + break; + } + case GIM_RecordInsn: { - int64_t NewInsnID = *Command++; - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; + int64_t NewInsnID = MatchTable[CurrentIdx++]; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; // As an optimisation we require that MIs[0] is always the root. Refuse // any attempt to modify it. @@ -41,88 +62,108 @@ MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx); if (!MO.isReg()) { - DEBUG(dbgs() << "Rejected (not a register)\n"); - return false; + DEBUG(dbgs() << CurrentIdx << ": Not a register\n"); + if (handleReject() == RejectAndGiveUp) + return false; + break; } if (TRI.isPhysicalRegister(MO.getReg())) { - DEBUG(dbgs() << "Rejected (is a physical register)\n"); - return false; + DEBUG(dbgs() << CurrentIdx << ": Is a physical register\n"); + if (handleReject() == RejectAndGiveUp) + return false; + break; } assert((size_t)NewInsnID == State.MIs.size() && "Expected to store MIs in order"); State.MIs.push_back(MRI.getVRegDef(MO.getReg())); - DEBUG(dbgs() << "MIs[" << NewInsnID << "] = GIM_RecordInsn(" << InsnID - << ", " << OpIdx << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": MIs[" << NewInsnID + << "] = GIM_RecordInsn(" << InsnID << ", " << OpIdx + << ")\n"); break; } case GIM_CheckFeatures: { - int64_t ExpectedBitsetID = *Command++; - DEBUG(dbgs() << "GIM_CheckFeatures(ExpectedBitsetID=" << ExpectedBitsetID - << ")\n"); + int64_t ExpectedBitsetID = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckFeatures(ExpectedBitsetID=" + << ExpectedBitsetID << ")\n"); if ((AvailableFeatures & MatcherInfo.FeatureBitsets[ExpectedBitsetID]) != MatcherInfo.FeatureBitsets[ExpectedBitsetID]) { - DEBUG(dbgs() << "Rejected\n"); - return false; + if (handleReject() == RejectAndGiveUp) + return false; + break; } break; } case GIM_CheckOpcode: { - int64_t InsnID = *Command++; - int64_t Expected = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Expected = MatchTable[CurrentIdx++]; unsigned Opcode = State.MIs[InsnID]->getOpcode(); - DEBUG(dbgs() << "GIM_CheckOpcode(MIs[" << InsnID << "], ExpectedOpcode=" - << Expected << ") // Got=" << Opcode << "\n"); + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID + << "], ExpectedOpcode=" << Expected << ") // Got=" << Opcode + << "\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - if (Opcode != Expected) - return false; + if (Opcode != Expected) { + if (handleReject() == RejectAndGiveUp) + return false; + } break; } case GIM_CheckNumOperands: { - int64_t InsnID = *Command++; - int64_t Expected = *Command++; - DEBUG(dbgs() << "GIM_CheckNumOperands(MIs[" << InsnID + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Expected = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckNumOperands(MIs[" << InsnID << "], Expected=" << Expected << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - if (State.MIs[InsnID]->getNumOperands() != Expected) - return false; + if (State.MIs[InsnID]->getNumOperands() != Expected) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckType: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t TypeID = *Command++; - DEBUG(dbgs() << "GIM_CheckType(MIs[" << InsnID << "]->getOperand(" - << OpIdx << "), TypeID=" << TypeID << ")\n"); + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t TypeID = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckType(MIs[" << InsnID + << "]->getOperand(" << OpIdx << "), TypeID=" << TypeID + << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); if (MRI.getType(State.MIs[InsnID]->getOperand(OpIdx).getReg()) != - MatcherInfo.TypeObjects[TypeID]) - return false; + MatcherInfo.TypeObjects[TypeID]) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckRegBankForClass: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t RCEnum = *Command++; - DEBUG(dbgs() << "GIM_CheckRegBankForClass(MIs[" << InsnID + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t RCEnum = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckRegBankForClass(MIs[" << InsnID << "]->getOperand(" << OpIdx << "), RCEnum=" << RCEnum << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); if (&RBI.getRegBankFromRegClass(*TRI.getRegClass(RCEnum)) != - RBI.getRegBank(State.MIs[InsnID]->getOperand(OpIdx).getReg(), MRI, TRI)) - return false; + RBI.getRegBank(State.MIs[InsnID]->getOperand(OpIdx).getReg(), MRI, + TRI)) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckComplexPattern: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t RendererID = *Command++; - int64_t ComplexPredicateID = *Command++; - DEBUG(dbgs() << "State.Renderers[" << RendererID + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t RendererID = MatchTable[CurrentIdx++]; + int64_t ComplexPredicateID = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": State.Renderers[" << RendererID << "] = GIM_CheckComplexPattern(MIs[" << InsnID << "]->getOperand(" << OpIdx << "), ComplexPredicateID=" << ComplexPredicateID << ")\n"); @@ -130,37 +171,49 @@ // FIXME: Use std::invoke() when it's available. if (!(State.Renderers[RendererID] = (ISel.*MatcherInfo.ComplexPredicates[ComplexPredicateID])( - State.MIs[InsnID]->getOperand(OpIdx)))) - return false; + State.MIs[InsnID]->getOperand(OpIdx)))) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckConstantInt: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t Value = *Command++; - DEBUG(dbgs() << "GIM_CheckConstantInt(MIs[" << InsnID << "]->getOperand(" - << OpIdx << "), Value=" << Value << ")\n"); + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t Value = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckConstantInt(MIs[" << InsnID + << "]->getOperand(" << OpIdx << "), Value=" << Value + << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - if (!isOperandImmEqual(State.MIs[InsnID]->getOperand(OpIdx), Value, MRI)) - return false; + if (!isOperandImmEqual(State.MIs[InsnID]->getOperand(OpIdx), Value, + MRI)) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckLiteralInt: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t Value = *Command++; - DEBUG(dbgs() << "GIM_CheckLiteralInt(MIs[" << InsnID << "]->getOperand(" << OpIdx - << "), Value=" << Value << ")\n"); + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t Value = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckLiteralInt(MIs[" << InsnID + << "]->getOperand(" << OpIdx << "), Value=" << Value + << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); MachineOperand &OM = State.MIs[InsnID]->getOperand(OpIdx); - if (!OM.isCImm() || !OM.getCImm()->equalsInt(Value)) - return false; + if (!OM.isCImm() || !OM.getCImm()->equalsInt(Value)) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } case GIM_CheckIntrinsicID: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t Value = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t Value = MatchTable[CurrentIdx++]; DEBUG(dbgs() << "GIM_CheckIntrinsicID(MIs[" << InsnID << "]->getOperand(" << OpIdx << "), Value=" << Value << ")\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); @@ -170,160 +223,175 @@ break; } case GIM_CheckIsMBB: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - DEBUG(dbgs() << "GIM_CheckIsMBB(MIs[" << InsnID << "]->getOperand(" - << OpIdx << "))\n"); + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckIsMBB(MIs[" << InsnID + << "]->getOperand(" << OpIdx << "))\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - if (!State.MIs[InsnID]->getOperand(OpIdx).isMBB()) - return false; + if (!State.MIs[InsnID]->getOperand(OpIdx).isMBB()) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } - case GIM_CheckIsSafeToFold: { - int64_t InsnID = *Command++; - DEBUG(dbgs() << "GIM_CheckIsSafeToFold(MIs[" << InsnID << "])\n"); + int64_t InsnID = MatchTable[CurrentIdx++]; + DEBUG(dbgs() << CurrentIdx << ": GIM_CheckIsSafeToFold(MIs[" << InsnID + << "])\n"); assert(State.MIs[InsnID] != nullptr && "Used insn before defined"); - if (!isObviouslySafeToFold(*State.MIs[InsnID])) - return false; + if (!isObviouslySafeToFold(*State.MIs[InsnID])) { + if (handleReject() == RejectAndGiveUp) + return false; + break; + } break; } + case GIM_Reject: + DEBUG(dbgs() << CurrentIdx << ": GIM_Reject"); + if (handleReject() == RejectAndGiveUp) + return false; + break; case GIR_MutateOpcode: { - int64_t OldInsnID = *Command++; - int64_t NewInsnID = *Command++; - int64_t NewOpcode = *Command++; + int64_t OldInsnID = MatchTable[CurrentIdx++]; + int64_t NewInsnID = MatchTable[CurrentIdx++]; + int64_t NewOpcode = MatchTable[CurrentIdx++]; assert((size_t)NewInsnID == OutMIs.size() && "Expected to store MIs in order"); OutMIs.push_back( MachineInstrBuilder(*State.MIs[OldInsnID]->getParent()->getParent(), State.MIs[OldInsnID])); OutMIs[NewInsnID]->setDesc(TII.get(NewOpcode)); - DEBUG(dbgs() << "GIR_MutateOpcode(OutMIs[" << NewInsnID << "], MIs[" - << OldInsnID << "], " << NewOpcode << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_MutateOpcode(OutMIs[" << NewInsnID + << "], MIs[" << OldInsnID << "], " << NewOpcode << ")\n"); break; } case GIR_BuildMI: { - int64_t InsnID = *Command++; - int64_t Opcode = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Opcode = MatchTable[CurrentIdx++]; assert((size_t)InsnID == OutMIs.size() && "Expected to store MIs in order"); (void)InsnID; OutMIs.push_back(BuildMI(*State.MIs[0]->getParent(), State.MIs[0], State.MIs[0]->getDebugLoc(), TII.get(Opcode))); - DEBUG(dbgs() << "GIR_BuildMI(OutMIs[" << InsnID << "], " << Opcode - << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_BuildMI(OutMIs[" << InsnID << "], " + << Opcode << ")\n"); break; } case GIR_Copy: { - int64_t NewInsnID = *Command++; - int64_t OldInsnID = *Command++; - int64_t OpIdx = *Command++; + int64_t NewInsnID = MatchTable[CurrentIdx++]; + int64_t OldInsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction"); OutMIs[NewInsnID].add(State.MIs[OldInsnID]->getOperand(OpIdx)); - DEBUG(dbgs() << "GIR_Copy(OutMIs[" << NewInsnID << "], MIs[" << OldInsnID - << "], " << OpIdx << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_Copy(OutMIs[" << NewInsnID + << "], MIs[" << OldInsnID << "], " << OpIdx << ")\n"); break; } case GIR_CopySubReg: { - int64_t NewInsnID = *Command++; - int64_t OldInsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t SubRegIdx = *Command++; + int64_t NewInsnID = MatchTable[CurrentIdx++]; + int64_t OldInsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t SubRegIdx = MatchTable[CurrentIdx++]; assert(OutMIs[NewInsnID] && "Attempted to add to undefined instruction"); OutMIs[NewInsnID].addReg(State.MIs[OldInsnID]->getOperand(OpIdx).getReg(), 0, SubRegIdx); - DEBUG(dbgs() << "GIR_CopySubReg(OutMIs[" << NewInsnID << "], MIs[" - << OldInsnID << "], " << OpIdx << ", " << SubRegIdx - << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_CopySubReg(OutMIs[" << NewInsnID + << "], MIs[" << OldInsnID << "], " << OpIdx << ", " + << SubRegIdx << ")\n"); break; } case GIR_AddImplicitDef: { - int64_t InsnID = *Command++; - int64_t RegNum = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t RegNum = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); OutMIs[InsnID].addDef(RegNum, RegState::Implicit); - DEBUG(dbgs() << "GIR_AddImplicitDef(OutMIs[" << InsnID << "], " << RegNum - << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_AddImplicitDef(OutMIs[" << InsnID + << "], " << RegNum << ")\n"); break; } case GIR_AddImplicitUse: { - int64_t InsnID = *Command++; - int64_t RegNum = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t RegNum = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); OutMIs[InsnID].addUse(RegNum, RegState::Implicit); - DEBUG(dbgs() << "GIR_AddImplicitUse(OutMIs[" << InsnID << "], " << RegNum - << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_AddImplicitUse(OutMIs[" << InsnID + << "], " << RegNum << ")\n"); break; } case GIR_AddRegister: { - int64_t InsnID = *Command++; - int64_t RegNum = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t RegNum = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); OutMIs[InsnID].addReg(RegNum); - DEBUG(dbgs() << "GIR_AddRegister(OutMIs[" << InsnID << "], " << RegNum - << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_AddRegister(OutMIs[" << InsnID + << "], " << RegNum << ")\n"); break; } case GIR_AddImm: { - int64_t InsnID = *Command++; - int64_t Imm = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t Imm = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); OutMIs[InsnID].addImm(Imm); - DEBUG(dbgs() << "GIR_AddImm(OutMIs[" << InsnID << "], " << Imm << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_AddImm(OutMIs[" << InsnID << "], " + << Imm << ")\n"); break; } case GIR_ComplexRenderer: { - int64_t InsnID = *Command++; - int64_t RendererID = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t RendererID = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); State.Renderers[RendererID](OutMIs[InsnID]); - DEBUG(dbgs() << "GIR_ComplexRenderer(OutMIs[" << InsnID << "], " - << RendererID << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_ComplexRenderer(OutMIs[" << InsnID + << "], " << RendererID << ")\n"); break; } case GIR_ConstrainOperandRC: { - int64_t InsnID = *Command++; - int64_t OpIdx = *Command++; - int64_t RCEnum = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; + int64_t OpIdx = MatchTable[CurrentIdx++]; + int64_t RCEnum = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); constrainOperandRegToRegClass(*OutMIs[InsnID].getInstr(), OpIdx, *TRI.getRegClass(RCEnum), TII, TRI, RBI); - DEBUG(dbgs() << "GIR_ConstrainOperandRC(OutMIs[" << InsnID << "], " - << OpIdx << ", " << RCEnum << ")\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_ConstrainOperandRC(OutMIs[" << InsnID + << "], " << OpIdx << ", " << RCEnum << ")\n"); break; } case GIR_ConstrainSelectedInstOperands: { - int64_t InsnID = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); constrainSelectedInstRegOperands(*OutMIs[InsnID].getInstr(), TII, TRI, RBI); - DEBUG(dbgs() << "GIR_ConstrainSelectedInstOperands(OutMIs[" << InsnID + DEBUG(dbgs() << CurrentIdx + << ": GIR_ConstrainSelectedInstOperands(OutMIs[" << InsnID << "])\n"); break; } case GIR_MergeMemOperands: { - int64_t InsnID = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; assert(OutMIs[InsnID] && "Attempted to add to undefined instruction"); for (const auto *FromMI : State.MIs) for (const auto &MMO : FromMI->memoperands()) OutMIs[InsnID].addMemOperand(MMO); - DEBUG(dbgs() << "GIR_MergeMemOperands(OutMIs[" << InsnID << "])\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_MergeMemOperands(OutMIs[" << InsnID + << "])\n"); break; } case GIR_EraseFromParent: { - int64_t InsnID = *Command++; + int64_t InsnID = MatchTable[CurrentIdx++]; assert(State.MIs[InsnID] && "Attempted to erase an undefined instruction"); State.MIs[InsnID]->eraseFromParent(); - DEBUG(dbgs() << "GIR_EraseFromParent(MIs[" << InsnID << "])\n"); + DEBUG(dbgs() << CurrentIdx << ": GIR_EraseFromParent(MIs[" << InsnID + << "])\n"); break; } case GIR_Done: - DEBUG(dbgs() << "GIR_Done"); + DEBUG(dbgs() << CurrentIdx << ": GIR_Done"); return true; default: Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -96,6 +96,7 @@ // // CHECK-LABEL: MatchTable0[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, // CHECK-NEXT: // MIs[0] dst @@ -120,6 +121,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable0\n"); @@ -136,6 +139,7 @@ // // CHECK-LABEL: MatchTable1[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/3, // MIs[1] // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/4, @@ -176,6 +180,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable1\n"); @@ -191,6 +197,7 @@ //===- Test a simple pattern with regclass operands. ----------------------===// // CHECK-LABEL: MatchTable2[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD, // CHECK-NEXT: // MIs[0] dst @@ -203,9 +210,11 @@ // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, // CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2) -// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/MyTarget::ADD, +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable2\n"); @@ -220,6 +229,7 @@ // // CHECK-LABEL: MatchTable3[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC, // CHECK-NEXT: // MIs[0] dst @@ -239,6 +249,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable3\n"); @@ -252,6 +264,7 @@ //===- Test a nested instruction match. -----------------------------------===// // CHECK-LABEL: MatchTable4[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] @@ -285,6 +298,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable4\n"); @@ -294,6 +309,7 @@ // We also get a second rule by commutativity. // CHECK-LABEL: MatchTable5[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2, @@ -327,6 +343,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable5\n"); @@ -342,6 +360,7 @@ //===- Test another simple pattern with regclass operands. ----------------===// // CHECK-LABEL: MatchTable6[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, @@ -363,6 +382,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable6\n"); @@ -377,6 +398,7 @@ //===- Test a more complex multi-instruction match. -----------------------===// // CHECK-LABEL: MatchTable7[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1] @@ -422,6 +444,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable7\n"); @@ -438,6 +462,7 @@ // // CHECK-LABEL: MatchTable8[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, // CHECK-NEXT: // MIs[0] dst @@ -458,6 +483,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable8\n"); @@ -472,6 +499,7 @@ // // CHECK-LABEL: MatchTable9[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, // CHECK-NEXT: // MIs[0] dst @@ -492,6 +520,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable9\n"); @@ -507,6 +537,7 @@ // // CHECK-LABEL: MatchTable10[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, // CHECK-NEXT: // MIs[0] dst @@ -527,6 +558,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable10\n"); @@ -542,6 +575,7 @@ // // CHECK-LABEL: MatchTable11[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, // CHECK-NEXT: // MIs[0] dst @@ -563,6 +597,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable11\n"); @@ -578,6 +614,7 @@ // // CHECK-LABEL: MatchTable12[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, // CHECK-NEXT: // MIs[0] dst @@ -600,6 +637,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable12\n"); @@ -617,6 +656,7 @@ // priority over register banks. // CHECK-LABEL: MatchTable13[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, // CHECK-NEXT: // MIs[0] dst @@ -637,6 +677,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable13\n"); @@ -651,6 +693,7 @@ // // CHECK-LABEL: MatchTable14[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST, // CHECK-NEXT: // MIs[0] dst @@ -660,9 +703,11 @@ // CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, // CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::FPR32RegClassID, // CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32) -// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/TargetOpcode::COPY, -// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/ 1, +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY, +// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable14\n"); @@ -676,6 +721,7 @@ //===- Test a simple pattern with just a leaf immediate. ------------------===// // CHECK-LABEL: MatchTable15[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT, // CHECK-NEXT: // MIs[0] dst @@ -690,6 +736,8 @@ // CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable15\n"); @@ -702,14 +750,17 @@ //===- Test a pattern with an MBB operand. --------------------------------===// // CHECK-LABEL: MatchTable16[] = { +// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ [[LABEL:[0-9]+]], // CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1, // CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR, // CHECK-NEXT: // MIs[0] target // CHECK-NEXT: GIM_CheckIsMBB, /*MI*/0, /*Op*/0, // CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target) -// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/ 0, /*Opcode*/MyTarget::BR, +// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR, // CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0, // CHECK-NEXT: GIR_Done, +// CHECK-NEXT: // Label 0: @[[LABEL]] +// CHECK-NEXT: GIM_Reject, // CHECK-NEXT: }; // CHECK-NEXT: MIs.resize(1); // CHECK-NEXT: DEBUG(dbgs() << "Processing MatchTable16\n"); Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -76,6 +76,14 @@ public: LLTCodeGen(const LLT &Ty) : Ty(Ty) {} + std::string getCxxEnumValue() const { + std::string Str; + raw_string_ostream OS(Str); + + emitCxxEnumValue(OS); + return OS.str(); + } + void emitCxxEnumValue(raw_ostream &OS) const { if (Ty.isScalar()) { OS << "GILLT_s" << Ty.getSizeInBits(); @@ -217,6 +225,214 @@ Name += ("_" + Feature->getName()).str(); return Name; } + +//===- MatchTable Helpers -------------------------------------------------===// + +class MatchTable; + +/// A record to be stored in a MatchTable. +/// This class supports all kinds of data that needs to be stored in the data. +struct MatchTableRecord { + enum RecordFlagsBits { + MTRF_None = 0x0, + /// Causes EmitStr to be formatted as comment when emitted. + MTRF_Comment = 0x1, + /// Causes the record value to be followed by a comma when emitted. + MTRF_CommaFollows = 0x2, + /// Causes the record value to be followed by a line break when emitted. + MTRF_LineBreakFollows = 0x4, + /// Indicates that the record defines a label and causes an additional + /// comment to be emitted containing the index of the label. + MTRF_Label = 0x8, + /// Causes the record to be emitted as the index of the label specified by + /// LabelID along with a comment indicating where that label is. + MTRF_JumpTarget = 0x10, + /// Causes the formatter to add a level of indentation before emitting the + /// record. + MTRF_Indent = 0x20, + /// Causes the formatter to remove a level of indentation after emitting the + /// record. + MTRF_Outdent = 0x40, + }; + + /// When MTRF_Label or MTRF_JumpTarget is used, indicates a label id to + /// reference or define. + unsigned LabelID; + /// The string to emit. Depending on the MTRF_* flags it may be a comment, a + /// value, a label name. + std::string EmitStr; + /// The number of MatchTable elements described by this record. Comments are 0 + /// while values are typically 1. Values >1 may occur when we need to emit + /// values that exceed the size of a MatchTable element. + unsigned NumElements; + /// A bitfield of RecordFlagsBits flags. + unsigned Flags; + + MatchTableRecord(Optional LabelID_, StringRef EmitStr, + unsigned NumElements, unsigned Flags) + : LabelID(LabelID_.hasValue() ? LabelID_.getValue() : ~0u), + EmitStr(EmitStr), NumElements(NumElements), Flags(Flags) { + assert((!LabelID_.hasValue() || LabelID != ~0u) && + "This value is reserved for non-labels"); + } + + void emit(raw_ostream &OS, bool LineBreakNextAfterThis, + const MatchTable &Table) const; + unsigned size() const { return NumElements; } +}; + +/// Holds the contents of a generated MatchTable to enable formatting and the +/// necessary index tracking needed to support GIM_Try. +class MatchTable { + /// An unique identifier for the table. The generated table will be named + /// MatchTable${ID}. + unsigned ID; + /// The records that make up the table. Also includes comments describing the + /// values being emitted and line breaks to format it. + std::vector Contents; + /// The currently defined labels. + DenseMap LabelMap; + /// Tracks the sum of MatchTableRecord::NumElements as the table is built. + unsigned CurrentSize; + +public: + static MatchTableRecord LineBreak; + static MatchTableRecord Comment(StringRef Comment) { + return MatchTableRecord(None, Comment, 0, MatchTableRecord::MTRF_Comment); + } + static MatchTableRecord Opcode(StringRef Opcode, int IndentAdjust = 0) { + unsigned ExtraFlags = 0; + if (IndentAdjust > 0) + ExtraFlags |= MatchTableRecord::MTRF_Indent; + if (IndentAdjust < 0) + ExtraFlags |= MatchTableRecord::MTRF_Outdent; + + return MatchTableRecord(None, Opcode, 1, + MatchTableRecord::MTRF_CommaFollows | ExtraFlags); + } + static MatchTableRecord NamedValue(StringRef NamedValue) { + return MatchTableRecord(None, NamedValue, 1, + MatchTableRecord::MTRF_CommaFollows); + } + static MatchTableRecord NamedValue(StringRef Namespace, + StringRef NamedValue) { + return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1, + MatchTableRecord::MTRF_CommaFollows); + } + static MatchTableRecord IntValue(int64_t IntValue) { + return MatchTableRecord(None, llvm::to_string(IntValue), 1, + MatchTableRecord::MTRF_CommaFollows); + } + static MatchTableRecord Label(unsigned LabelID) { + return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0, + MatchTableRecord::MTRF_Label | + MatchTableRecord::MTRF_Comment | + MatchTableRecord::MTRF_LineBreakFollows); + } + static MatchTableRecord JumpTarget(unsigned LabelID) { + return MatchTableRecord(LabelID, "Label " + llvm::to_string(LabelID), 0, + MatchTableRecord::MTRF_JumpTarget | + MatchTableRecord::MTRF_Comment | + MatchTableRecord::MTRF_CommaFollows); + } + + MatchTable(unsigned ID) : ID(ID), CurrentSize(0) {} + + void push_back(const MatchTableRecord &Value) { + if (Value.Flags & MatchTableRecord::MTRF_Label) + defineLabel(Value.LabelID); + Contents.push_back(Value); + CurrentSize += Value.NumElements; + } + + void defineLabel(unsigned LabelID) { + LabelMap.insert(std::make_pair(LabelID, CurrentSize + 1)); + } + + unsigned getLabelIndex(unsigned LabelID) const { + const auto I = LabelMap.find(LabelID); + assert(I != LabelMap.end() && "Use of undeclared label"); + return I->second; + } + + void emit(raw_ostream &OS) const { + unsigned Indentation = 4; + OS << " const static int64_t MatchTable" << ID << "[] = {"; + LineBreak.emit(OS, true, *this); + OS << std::string(Indentation, ' '); + + for (auto I = Contents.begin(), E = Contents.end(); I != E; + ++I) { + bool LineBreakIsNext = false; + const auto &NextI = std::next(I); + + if (NextI != E) { + if (NextI->EmitStr == "" && + NextI->Flags == MatchTableRecord::MTRF_LineBreakFollows) + LineBreakIsNext = true; + } + + if (I->Flags & MatchTableRecord::MTRF_Indent) + Indentation += 2; + + I->emit(OS, LineBreakIsNext, *this); + if (I->Flags & MatchTableRecord::MTRF_LineBreakFollows) + OS << std::string(Indentation, ' '); + + if (I->Flags & MatchTableRecord::MTRF_Outdent) + Indentation -= 2; + } + OS << "};\n"; + } +}; + +MatchTableRecord MatchTable::LineBreak = { + None, "" /* Emit String */, 0 /* Elements */, + MatchTableRecord::MTRF_LineBreakFollows}; + +void MatchTableRecord::emit(raw_ostream &OS, bool LineBreakIsNextAfterThis, + const MatchTable &Table) const { + bool UseLineComment = + LineBreakIsNextAfterThis | (Flags & MTRF_LineBreakFollows); + if (Flags & (MTRF_JumpTarget | MTRF_CommaFollows)) + UseLineComment = false; + + if (Flags & MTRF_Comment) + OS << (UseLineComment ? "// " : "/*"); + + OS << EmitStr; + if (Flags & MTRF_Label) + OS << ": @" << Table.getLabelIndex(LabelID); + + if (Flags & MTRF_Comment && !UseLineComment) + OS << "*/"; + + if (Flags & MTRF_JumpTarget) { + if (Flags & MTRF_Comment) + OS << " "; + OS << Table.getLabelIndex(LabelID); + } + + if (Flags & MTRF_CommaFollows) { + OS << ","; + if (!LineBreakIsNextAfterThis && !(Flags & MTRF_LineBreakFollows)) + OS << " "; + } + + if (Flags & MTRF_LineBreakFollows) + OS << "\n"; +} + +MatchTable &operator<<(MatchTable &Table, const MatchTableRecord &Value) { + Table.push_back(Value); + return Table; +} + +raw_ostream &operator<<(raw_ostream &OS, const MatchTable &Table) { + Table.emit(OS); + return OS; +} + //===- Matchers -----------------------------------------------------------===// class OperandMatcher; @@ -259,11 +475,11 @@ /// This is used for the root of the match. unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher); /// Define an instruction and emit corresponding state-machine opcodes. - unsigned defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher, + unsigned defineInsnVar(MatchTable &Table, const InstructionMatcher &Matcher, unsigned InsnVarID, unsigned OpIdx); unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; - void emitCaptureOpcodes(raw_ostream &OS); + void emitCaptureOpcodes(MatchTable &Table); void emit(raw_ostream &OS); @@ -309,14 +525,14 @@ /// Emit MatchTable opcodes that tests whether all the predicates are met. template - void emitPredicateListOpcodes(raw_ostream &OS, Args &&... args) const { + void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) const { if (Predicates.empty()) { - OS << "// No predicates\n"; + Table << MatchTable::Comment("No predicates") << MatchTable::LineBreak; return; } for (const auto &Predicate : predicates()) - Predicate->emitPredicateOpcodes(OS, std::forward(args)...); + Predicate->emitPredicateOpcodes(Table, std::forward(args)...); } }; @@ -370,11 +586,11 @@ /// /// Only InstructionOperandMatcher needs to do anything for this method the /// rest just walk the tree. - virtual void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + virtual void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const {} /// Emit MatchTable opcodes that check the predicate for the given operand. - virtual void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + virtual void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const = 0; @@ -403,12 +619,13 @@ return P->getKind() == OPM_LLT; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckType, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx - << ", /*Type*/"; - Ty.emitCxxEnumValue(OS); - OS << ", \n"; + Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI") + << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op") + << MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type") + << MatchTable::NamedValue(Ty.getCxxEnumValue()) + << MatchTable::LineBreak; } }; @@ -430,12 +647,15 @@ return P->getKind() == OPM_ComplexPattern; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { unsigned ID = getAllocatedTemporariesBaseID(); - OS << " GIM_CheckComplexPattern, /*MI*/" << InsnVarID << ", /*Op*/" - << OpIdx << ", /*Renderer*/" << ID << ", GICP_" - << TheDef.getName() << ",\n"; + Table << MatchTable::Opcode("GIM_CheckComplexPattern") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("Renderer") << MatchTable::IntValue(ID) + << MatchTable::NamedValue(("GICP_" + TheDef.getName()).str()) + << MatchTable::LineBreak; } unsigned countRendererFns() const override { @@ -456,10 +676,14 @@ return P->getKind() == OPM_RegBank; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckRegBankForClass, /*MI*/" << InsnVarID << ", /*Op*/" - << OpIdx << ", /*RC*/" << RC.getQualifiedName() << "RegClassID,\n"; + Table << MatchTable::Opcode("GIM_CheckRegBankForClass") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("RC") + << MatchTable::NamedValue(RC.getQualifiedName() + "RegClassID") + << MatchTable::LineBreak; } }; @@ -472,9 +696,11 @@ return P->getKind() == OPM_MBB; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckIsMBB, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ",\n"; + Table << MatchTable::Opcode("GIM_CheckIsMBB") << MatchTable::Comment("MI") + << MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op") + << MatchTable::IntValue(OpIdx) << MatchTable::LineBreak; } }; @@ -492,10 +718,12 @@ return P->getKind() == OPM_Int; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckConstantInt, /*MI*/" << InsnVarID << ", /*Op*/" - << OpIdx << ", " << Value << ",\n"; + Table << MatchTable::Opcode("GIM_CheckConstantInt") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::IntValue(Value) << MatchTable::LineBreak; } }; @@ -513,10 +741,12 @@ return P->getKind() == OPM_LiteralInt; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckLiteralInt, /*MI*/" << InsnVarID << ", /*Op*/" - << OpIdx << ", " << Value << ",\n"; + Table << MatchTable::Opcode("GIM_CheckLiteralInt") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::IntValue(Value) << MatchTable::LineBreak; } }; @@ -533,10 +763,13 @@ return P->getKind() == OPM_IntrinsicID; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID, unsigned OpIdx) const override { - OS << " GIM_CheckIntrinsicID, /*MI*/" << InsnVarID << ", /*Op*/" - << OpIdx << ", Intrinsic::" << II->EnumName << ",\n"; + Table << MatchTable::Opcode("GIM_CheckIntrinsicID") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::NamedValue("Intrinsic::" + II->EnumName) + << MatchTable::LineBreak; } }; @@ -589,23 +822,26 @@ InstructionMatcher &getInstructionMatcher() const { return Insn; } /// Emit MatchTable opcodes to capture instructions into the MIs table. - void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const { for (const auto &Predicate : predicates()) - Predicate->emitCaptureOpcodes(OS, Rule, InsnVarID, OpIdx); + Predicate->emitCaptureOpcodes(Table, Rule, InsnVarID, OpIdx); } /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarID matches all the predicates and all the operands. - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const { - OS << " // MIs[" << InsnVarID << "] "; + std::string Comment; + raw_string_ostream CommentOS(Comment); + CommentOS << "MIs[" << InsnVarID << "] "; if (SymbolicName.empty()) - OS << "Operand " << OpIdx; + CommentOS << "Operand " << OpIdx; else - OS << SymbolicName; - OS << "\n"; - emitPredicateListOpcodes(OS, Rule, InsnVarID, OpIdx); + CommentOS << SymbolicName; + Table << MatchTable::Comment(CommentOS.str()) << MatchTable::LineBreak; + + emitPredicateListOpcodes(Table, Rule, InsnVarID, OpIdx); } /// Compare the priority of this object and B. @@ -673,7 +909,7 @@ /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarID matches the predicate. - virtual void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + virtual void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const = 0; /// Compare the priority of this object and B. @@ -702,10 +938,12 @@ return P->getKind() == IPM_Opcode; } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const override { - OS << " GIM_CheckOpcode, /*MI*/" << InsnVarID << ", " << I->Namespace - << "::" << I->TheDef->getName() << ",\n"; + Table << MatchTable::Opcode("GIM_CheckOpcode") << MatchTable::Comment("MI") + << MatchTable::IntValue(InsnVarID) + << MatchTable::NamedValue(I->Namespace, I->TheDef->getName()) + << MatchTable::LineBreak; } /// Compare the priority of this object and B. @@ -795,21 +1033,23 @@ /// Emit MatchTable opcodes to check the shape of the match and capture /// instructions into the MIs table. - void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnID) { - OS << " GIM_CheckNumOperands, /*MI*/" << InsnID << ", /*Expected*/" - << getNumOperands() << ",\n"; + Table << MatchTable::Opcode("GIM_CheckNumOperands") + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("Expected") + << MatchTable::IntValue(getNumOperands()) << MatchTable::LineBreak; for (const auto &Operand : Operands) - Operand->emitCaptureOpcodes(OS, Rule, InsnID); + Operand->emitCaptureOpcodes(Table, Rule, InsnID); } /// Emit MatchTable opcodes that test whether the instruction named in /// InsnVarName matches all the predicates and all the operands. - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID) const { - emitPredicateListOpcodes(OS, Rule, InsnVarID); + emitPredicateListOpcodes(Table, Rule, InsnVarID); for (const auto &Operand : Operands) - Operand->emitPredicateOpcodes(OS, Rule, InsnVarID); + Operand->emitPredicateOpcodes(Table, Rule, InsnVarID); } /// Compare the priority of this object and B. @@ -886,17 +1126,17 @@ return InsnMatcher->getOptionalOperand(SymbolicName); } - void emitCaptureOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnID, unsigned OpIdx) const override { - unsigned InsnVarID = Rule.defineInsnVar(OS, *InsnMatcher, InsnID, OpIdx); - InsnMatcher->emitCaptureOpcodes(OS, Rule, InsnVarID); + unsigned InsnVarID = Rule.defineInsnVar(Table, *InsnMatcher, InsnID, OpIdx); + InsnMatcher->emitCaptureOpcodes(Table, Rule, InsnVarID); } - void emitPredicateOpcodes(raw_ostream &OS, RuleMatcher &Rule, + void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule, unsigned InsnVarID_, unsigned OpIdx_) const override { unsigned InsnVarID = Rule.getInsnVarID(*InsnMatcher); - InsnMatcher->emitPredicateOpcodes(OS, Rule, InsnVarID); + InsnMatcher->emitPredicateOpcodes(Table, Rule, InsnVarID); } }; @@ -920,7 +1160,8 @@ RendererKind getKind() const { return Kind; } - virtual void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const = 0; + virtual void emitRenderOpcodes(MatchTable &Table, + RuleMatcher &Rule) const = 0; }; /// A CopyRenderer emits code to copy a single operand from an existing @@ -947,12 +1188,14 @@ const StringRef getSymbolicName() const { return SymbolicName; } - void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); - OS << " GIR_Copy, /*NewInsnID*/" << NewInsnID << ", /*OldInsnID*/" - << OldInsnVarID << ", /*OpIdx*/" << Operand.getOperandIndex() << ", // " - << SymbolicName << "\n"; + Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID") + << MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID") + << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx") + << MatchTable::IntValue(Operand.getOperandIndex()) + << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; } }; @@ -983,13 +1226,17 @@ const StringRef getSymbolicName() const { return SymbolicName; } - void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); unsigned OldInsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); - OS << " GIR_CopySubReg, /*NewInsnID*/" << NewInsnID - << ", /*OldInsnID*/" << OldInsnVarID << ", /*OpIdx*/" - << Operand.getOperandIndex() << ", /*SubRegIdx*/" << SubReg->EnumValue - << ", // " << SymbolicName << "\n"; + Table << MatchTable::Opcode("GIR_CopySubReg") + << MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID) + << MatchTable::Comment("OldInsnID") + << MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx") + << MatchTable::IntValue(Operand.getOperandIndex()) + << MatchTable::Comment("SubRegIdx") + << MatchTable::IntValue(SubReg->EnumValue) + << MatchTable::Comment(SymbolicName) << MatchTable::LineBreak; } }; @@ -1009,12 +1256,15 @@ return R->getKind() == OR_Register; } - void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " GIR_AddRegister, /*InsnID*/" << InsnID << ", " - << (RegisterDef->getValue("Namespace") - ? RegisterDef->getValueAsString("Namespace") - : "") - << "::" << RegisterDef->getName() << ",\n"; + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIR_AddRegister") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::NamedValue( + (RegisterDef->getValue("Namespace") + ? RegisterDef->getValueAsString("Namespace") + : ""), + RegisterDef->getName()) + << MatchTable::LineBreak; } }; @@ -1032,9 +1282,10 @@ return R->getKind() == OR_Imm; } - void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " GIR_AddImm, /*InsnID*/" << InsnID << ", /*Imm*/" << Imm - << ",\n"; + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIR_AddImm") << MatchTable::Comment("InsnID") + << MatchTable::IntValue(InsnID) << MatchTable::Comment("Imm") + << MatchTable::IntValue(Imm) << MatchTable::LineBreak; } }; @@ -1064,9 +1315,11 @@ return R->getKind() == OR_ComplexPattern; } - void emitRenderOpcodes(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << " GIR_ComplexRenderer, /*InsnID*/" << InsnID << ", /*RendererID*/" - << RendererID << ",\n"; + void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override { + Table << MatchTable::Opcode("GIR_ComplexRenderer") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("RendererID") + << MatchTable::IntValue(RendererID) << MatchTable::LineBreak; } }; @@ -1079,13 +1332,13 @@ public: virtual ~MatchAction() {} - /// Emit the C++ statements to implement the action. + /// Emit the MatchTable opcodes to implement the action. /// /// \param RecycleInsnID If given, it's an instruction to recycle. The /// requirements on the instruction vary from action to /// action. - virtual void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - unsigned RecycleInsnID) const = 0; + virtual void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned RecycleInsnID) const = 0; }; /// Generates a comment describing the matched rule being acted upon. @@ -1096,10 +1349,11 @@ public: DebugCommentAction(const PatternToMatch &P) : P(P) {} - void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - unsigned RecycleInsnID) const override { - OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() - << "\n"; + void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned RecycleInsnID) const override { + Table << MatchTable::Comment(llvm::to_string(*P.getSrcPattern()) + " => " + + llvm::to_string(*P.getDstPattern())) + << MatchTable::LineBreak; } }; @@ -1142,27 +1396,35 @@ return *static_cast(OperandRenderers.back().get()); } - void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - unsigned RecycleInsnID) const override { + void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned RecycleInsnID) const override { if (canMutate()) { - OS << " GIR_MutateOpcode, /*InsnID*/" << InsnID - << ", /*RecycleInsnID*/ " << RecycleInsnID << ", /*Opcode*/" - << I->Namespace << "::" << I->TheDef->getName() << ",\n"; + Table << MatchTable::Opcode("GIR_MutateOpcode") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("RecycleInsnID") + << MatchTable::IntValue(RecycleInsnID) + << MatchTable::Comment("Opcode") + << MatchTable::NamedValue(I->Namespace, I->TheDef->getName()) + << MatchTable::LineBreak; if (!I->ImplicitDefs.empty() || !I->ImplicitUses.empty()) { for (auto Def : I->ImplicitDefs) { auto Namespace = Def->getValue("Namespace") ? Def->getValueAsString("Namespace") : ""; - OS << " GIR_AddImplicitDef, " << InsnID << ", " << Namespace - << "::" << Def->getName() << ",\n"; + Table << MatchTable::Opcode("GIR_AddImplicitDef") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::NamedValue(Namespace, Def->getName()) + << MatchTable::LineBreak; } for (auto Use : I->ImplicitUses) { auto Namespace = Use->getValue("Namespace") ? Use->getValueAsString("Namespace") : ""; - OS << " GIR_AddImplicitUse, " << InsnID << ", " << Namespace - << "::" << Use->getName() << ",\n"; + Table << MatchTable::Opcode("GIR_AddImplicitUse") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::NamedValue(Namespace, Use->getName()) + << MatchTable::LineBreak; } } return; @@ -1171,13 +1433,18 @@ // TODO: Simple permutation looks like it could be almost as common as // mutation due to commutative operations. - OS << " GIR_BuildMI, /*InsnID*/" << InsnID << ", /*Opcode*/" - << I->Namespace << "::" << I->TheDef->getName() << ",\n"; + Table << MatchTable::Opcode("GIR_BuildMI") << MatchTable::Comment("InsnID") + << MatchTable::IntValue(InsnID) << MatchTable::Comment("Opcode") + << MatchTable::NamedValue(I->Namespace, I->TheDef->getName()) + << MatchTable::LineBreak; for (const auto &Renderer : OperandRenderers) - Renderer->emitRenderOpcodes(OS, Rule); + Renderer->emitRenderOpcodes(Table, Rule); - OS << " GIR_MergeMemOperands, /*InsnID*/" << InsnID << ",\n" - << " GIR_EraseFromParent, /*InsnID*/" << RecycleInsnID << ",\n"; + Table << MatchTable::Opcode("GIR_MergeMemOperands") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::LineBreak << MatchTable::Opcode("GIR_EraseFromParent") + << MatchTable::Comment("InsnID") + << MatchTable::IntValue(RecycleInsnID) << MatchTable::LineBreak; } }; @@ -1189,9 +1456,11 @@ public: ConstrainOperandsToDefinitionAction(unsigned InsnID) : InsnID(InsnID) {} - void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - unsigned RecycleInsnID) const override { - OS << " GIR_ConstrainSelectedInstOperands, /*InsnID*/" << InsnID << ",\n"; + void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned RecycleInsnID) const override { + Table << MatchTable::Opcode("GIR_ConstrainSelectedInstOperands") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::LineBreak; } }; @@ -1207,10 +1476,13 @@ const CodeGenRegisterClass &RC) : InsnID(InsnID), OpIdx(OpIdx), RC(RC) {} - void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, - unsigned RecycleInsnID) const override { - OS << " GIR_ConstrainOperandRC, /*InsnID*/" << InsnID << ", /*Op*/" - << OpIdx << ", /*RC " << RC.getName() << "*/ " << RC.EnumValue << ",\n"; + void emitActionOpcodes(MatchTable &Table, RuleMatcher &Rule, + unsigned RecycleInsnID) const override { + Table << MatchTable::Opcode("GIR_ConstrainOperandRC") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("Op") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("RC " + RC.getName()) + << MatchTable::IntValue(RC.EnumValue) << MatchTable::LineBreak; } }; @@ -1240,13 +1512,16 @@ return NewInsnVarID; } -unsigned RuleMatcher::defineInsnVar(raw_ostream &OS, +unsigned RuleMatcher::defineInsnVar(MatchTable &Table, const InstructionMatcher &Matcher, unsigned InsnID, unsigned OpIdx) { unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher); - OS << " GIM_RecordInsn, /*DefineMI*/" << NewInsnVarID << ", /*MI*/" - << InsnID << ", /*OpIdx*/" << OpIdx << ", // MIs[" << NewInsnVarID - << "]\n"; + Table << MatchTable::Opcode("GIM_RecordInsn") + << MatchTable::Comment("DefineMI") << MatchTable::IntValue(NewInsnVarID) + << MatchTable::Comment("MI") << MatchTable::IntValue(InsnID) + << MatchTable::Comment("OpIdx") << MatchTable::IntValue(OpIdx) + << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]") + << MatchTable::LineBreak; return NewInsnVarID; } @@ -1259,10 +1534,10 @@ /// Emit MatchTable opcodes to check the shape of the match and capture /// instructions into local variables. -void RuleMatcher::emitCaptureOpcodes(raw_ostream &OS) { +void RuleMatcher::emitCaptureOpcodes(MatchTable &Table) { assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front()); - Matchers.front()->emitCaptureOpcodes(OS, *this, InsnVarID); + Matchers.front()->emitCaptureOpcodes(Table, *this, InsnVarID); } void RuleMatcher::emit(raw_ostream &OS) { @@ -1280,15 +1555,20 @@ // on some targets but we don't need to make use of that yet. assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - OS << " const static int64_t MatchTable" << CurrentMatchTableID << "[] = {\n"; + MatchTable Table(CurrentMatchTableID); + Table << MatchTable::Opcode("GIM_Try", +1) + << MatchTable::Comment("On fail goto") << MatchTable::JumpTarget(0) + << MatchTable::LineBreak; + if (!RequiredFeatures.empty()) { - OS << " GIM_CheckFeatures, " << getNameForFeatureBitset(RequiredFeatures) - << ",\n"; + Table << MatchTable::Opcode("GIM_CheckFeatures") + << MatchTable::NamedValue(getNameForFeatureBitset(RequiredFeatures)) + << MatchTable::LineBreak; } - emitCaptureOpcodes(OS); + emitCaptureOpcodes(Table); - Matchers.front()->emitPredicateOpcodes(OS, *this, + Matchers.front()->emitPredicateOpcodes(Table, *this, getInsnVarID(*Matchers.front())); // We must also check if it's safe to fold the matched instructions. @@ -1307,7 +1587,9 @@ for (const auto &InsnID : InsnIDs) { // Reject the difficult cases until we have a more accurate check. - OS << " GIM_CheckIsSafeToFold, /*InsnID*/" << InsnID << ",\n"; + Table << MatchTable::Opcode("GIM_CheckIsSafeToFold") + << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID) + << MatchTable::LineBreak; // FIXME: Emit checks to determine it's _actually_ safe to fold and/or // account for unsafe cases. @@ -1347,9 +1629,11 @@ } for (const auto &MA : Actions) - MA->emitCxxActionStmts(OS, *this, 0); - OS << " GIR_Done,\n" - << " };\n" + MA->emitActionOpcodes(Table, *this, 0); + Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak + << MatchTable::Label(0) << MatchTable::Opcode("GIM_Reject") + << MatchTable::LineBreak; + OS << Table << " State.MIs.resize(1);\n" << " DEBUG(dbgs() << \"Processing MatchTable" << CurrentMatchTableID << "\\n\");\n"