};
enum {
+ /// Begin a try-block to attempt a match 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
/// - 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
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI,
const PredicateBitset &AvailableFeatures) const {
- const int64_t *Command = MatchTable;
+ uint64_t CurrentIdx = 0;
+ SmallVector<uint64_t, 8> 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.
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;
}
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;
}
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;
}
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;
}
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");
// 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;
}
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;
}
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;
}
case GIM_CheckIntrinsicID: {
- int64_t InsnID = *Command++;
- int64_t OpIdx = *Command++;
- int64_t Value = *Command++;
- DEBUG(dbgs() << "GIM_CheckIntrinsicID(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_CheckIntrinsicID(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.isIntrinsicID() || OM.getIntrinsicID() != Value)
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;
}
-
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;
}
+ case GIM_Reject:
+ DEBUG(dbgs() << CurrentIdx << ": GIM_Reject");
+ if (handleReject() == RejectAndGiveUp)
+ return false;
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:
//
// 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
// 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");
//
// 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,
// 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");
//===- 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
// 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");
//
// 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
// 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");
//===- 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]
// 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");
// 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,
// 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");
//===- 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,
// 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");
//===- 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]
// 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");
//
// 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
// 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");
//
// 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
// 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");
//
// 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
// 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");
//
// 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
// 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");
//
// 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
// 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");
// 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
// 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");
//
// 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
// 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");
//===- 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
// 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");
//===- 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");
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();
Name += ("_" + Feature->getName()).str();
return Name;
}
+
+//===- MatchTable Helpers -------------------------------------------------===//
+
+class MatchTable;
+
+/// A record to be stored in a MatchTable.
+///
+/// This class represents any and all output that may be required to emit the
+/// MatchTable. Instances are most often configured to represent an opcode or
+/// value that will be emitted to the table with some formatting but it can also
+/// represent commas, comments, and other formatting instructions.
+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;
+
+private:
+ /// 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;
+
+public:
+ /// A bitfield of RecordFlagsBits flags.
+ unsigned Flags;
+
+ MatchTableRecord(Optional<unsigned> 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<MatchTableRecord> Contents;
+ /// The currently defined labels.
+ DenseMap<unsigned, unsigned> 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.size();
+ }
+
+ 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;
/// 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);
/// Emit MatchTable opcodes that tests whether all the predicates are met.
template <class... Args>
- 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>(args)...);
+ Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
}
};
///
/// 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;
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;
}
};
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 {
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;
}
};
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;
}
};
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;
}
};
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;
}
};
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;
}
};
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.
/// 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.
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.
/// 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.
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);
}
};
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
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;
}
};
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;
}
};
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;
}
};
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;
}
};
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;
}
};
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.
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;
}
};
return *static_cast<Kind *>(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;
// 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;
}
};
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;
}
};
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;
}
};
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;
}
/// 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) {
// 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.
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.
}
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"