Index: include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -17,11 +17,13 @@ #define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" #include #include #include namespace llvm { +class LLT; class MachineInstr; class MachineInstrBuilder; class MachineFunction; @@ -57,6 +59,60 @@ } }; +enum { + /// Record the specified instruction + /// - NewInsnID - Instruction ID to define + GIM_RecordInsn, + /// Follow the specified operand to the def and push it onto the stack + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + GIM_PushInsnOpDef, + /// Pop the current instruction from the stack + GIM_PopInsn, + + /// Check the feature bits + /// - Expected features + GIM_CheckFeatures, + + /// Check the opcode on the specified instruction + /// - InsnID - Instruction ID + /// - Expected opcode + GIM_CheckOpcode, + /// Check the instruction has the right number of operands + /// - InsnID - Instruction ID + /// - Expected number of operands + GIM_CheckNumOperands, + + /// Check the type for the specified operand + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - Expected type + GIM_CheckType, + /// Check the register bank for the specified operand + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - Expected register bank (specified as a register class) + GIM_CheckRegBankForClass, + /// Check the operand matches a complex predicate + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - RendererID - The renderer to hold the result + /// - Complex predicate ID + GIM_CheckComplexPattern, + /// Check the operand is a specific integer + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + /// - Expected integer + GIM_CheckInt, + /// Check the specified operand is an MBB + /// - InsnID - Instruction ID + /// - OpIdx - Operand index + GIM_CheckIsMBB, + + /// A successful match + GIM_Accept, +}; + /// Provides the logic to select generic machine instructions. class InstructionSelector { public: @@ -77,9 +133,21 @@ protected: typedef std::function ComplexRendererFn; + typedef SmallVector RecordedMIVector; InstructionSelector(); + template + bool executeMatchTable( + TgtInstructionSelector &ISel, RecordedMIVector &MIs, + RecordedMIVector &MIStack, std::vector &Renderers, + const LLT TypeObjects[], const PredicateBitset FeatureBitsets[], + const std::vector &ComplexPredicates, + const int64_t *MatchTable, MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI, + const PredicateBitset &AvailableFeatures) const; + bool constrainOperandRegToRegClass(MachineInstr &I, unsigned OpIdx, const TargetRegisterClass *RC, const TargetInstrInfo &TII, Index: include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- /dev/null +++ include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -0,0 +1,169 @@ +//==-- llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h ---------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file This file declares the API for the instruction selector. +/// This class is responsible for selecting machine instructions. +/// It's implemented by the target. It's used by the InstructionSelect pass. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H +#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H + +namespace llvm { +template +bool InstructionSelector::executeMatchTable( + TgtInstructionSelector &ISel, RecordedMIVector &MIs, + RecordedMIVector &MIStack, std::vector &Renderers, + const LLT TypeObjects[], const PredicateBitset FeatureBitsets[], + const std::vector &ComplexPredicates, + const int64_t *MatchTable, MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI, + const PredicateBitset &AvailableFeatures) const { + const int64_t *Command = MatchTable; + while (true) { + switch (*Command++) { + case GIM_RecordInsn: { + int64_t NewInsnID = *Command++; + assert((size_t)NewInsnID == MIs.size() && "Expected to store MIs in order"); + MIs.push_back(MIStack.back()); + DEBUG(dbgs() << "MIs[" << NewInsnID << "] = GIM_RecordInsn()\n"); + break; + } + case GIM_PushInsnOpDef: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + DEBUG(dbgs() << "GIM_PushInsnOpDef(" << InsnID << ", " << OpIdx << ")\n"); + if (!MIs[InsnID]->getOperand(OpIdx).isReg()) { + DEBUG(dbgs() << "Rejected (not a register)\n"); + return false; + } + if (TRI.isPhysicalRegister(MIs[InsnID]->getOperand(OpIdx).getReg())) { + DEBUG(dbgs() << "Rejected (is a physical register)\n"); + return false; + } + MIStack.push_back( + MRI.getVRegDef(MIs[InsnID]->getOperand(OpIdx).getReg())); + break; + } + case GIM_PopInsn: { + DEBUG(dbgs() << "GIM_PopInsn()\n"); + MIStack.pop_back(); + break; + } + + case GIM_CheckFeatures: { + int64_t ExpectedBitsetID = *Command++; + DEBUG(dbgs() << "GIM_CheckFeatures(ExpectedBitsetID=" << ExpectedBitsetID + << ")\n"); + if ((AvailableFeatures & FeatureBitsets[ExpectedBitsetID]) != + FeatureBitsets[ExpectedBitsetID]) { + DEBUG(dbgs() << "Rejected\n"); + return false; + } + break; + } + + case GIM_CheckOpcode: { + int64_t InsnID = *Command++; + int64_t Expected = *Command++; + DEBUG(dbgs() << "GIM_CheckOpcode(MIs[" << InsnID + << "], ExpectedOpcode=" << Expected << ")\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (MIs[InsnID]->getOpcode() != Expected) + return false; + break; + } + case GIM_CheckNumOperands: { + int64_t InsnID = *Command++; + int64_t Expected = *Command++; + DEBUG(dbgs() << "GIM_CheckNumOperands(MIs[" << InsnID + << "], Expected=" << Expected << ")\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (MIs[InsnID]->getNumOperands() != Expected) + 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"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (MRI.getType(MIs[InsnID]->getOperand(OpIdx).getReg()) != + TypeObjects[TypeID]) + return false; + break; + } + case GIM_CheckRegBankForClass: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + int64_t RCEnum = *Command++; + DEBUG(dbgs() << "GIM_CheckRegBankForClass(MIs[" << InsnID + << "]->getOperand(" << OpIdx << "), RCEnum=" << RCEnum + << ")\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (&RBI.getRegBankFromRegClass(*TRI.getRegClass(RCEnum)) != + RBI.getRegBank(MIs[InsnID]->getOperand(OpIdx).getReg(), MRI, TRI)) + return false; + break; + } + case GIM_CheckComplexPattern: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + int64_t RendererID = *Command++; + int64_t ComplexPredicateID = *Command++; + DEBUG(dbgs() << "Renderers[" << RendererID + << "] = GIM_CheckComplexPattern(MIs[" << InsnID + << "]->getOperand(" << OpIdx + << "), ComplexPredicateID=" << ComplexPredicateID << ")\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + // FIXME: Use std::invoke() when it's available. + if (!(Renderers[RendererID] = + (ISel.*ComplexPredicates[ComplexPredicateID])( + MIs[InsnID]->getOperand(OpIdx)))) + return false; + break; + } + case GIM_CheckInt: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + int64_t Value = *Command++; + DEBUG(dbgs() << "GIM_CheckInt(MIs[" << InsnID << "]->getOperand(" << OpIdx + << "), Value=" << Value << ")\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (!isOperandImmEqual(MIs[InsnID]->getOperand(OpIdx), Value, MRI)) + return false; + break; + } + case GIM_CheckIsMBB: { + int64_t InsnID = *Command++; + int64_t OpIdx = *Command++; + DEBUG(dbgs() << "GIM_CheckIsMBB(MIs[" << InsnID << "]->getOperand(" + << OpIdx << "))\n"); + assert(MIs[InsnID] != nullptr && "Used insn before defined"); + if (!MIs[InsnID]->getOperand(OpIdx).isMBB()) + return false; + break; + } + + case GIM_Accept: + DEBUG(dbgs() << "GIM_Accept"); + return true; + default: + llvm_unreachable("Unexpected command"); + } + } +} +} // end namespace llvm + +#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTORIMPL_H Index: lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- lib/Target/AArch64/AArch64InstructionSelector.cpp +++ lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -33,6 +33,8 @@ #define DEBUG_TYPE "aarch64-isel" +#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" + using namespace llvm; #ifndef LLVM_BUILD_GLOBAL_ISEL Index: lib/Target/ARM/ARMInstructionSelector.cpp =================================================================== --- lib/Target/ARM/ARMInstructionSelector.cpp +++ lib/Target/ARM/ARMInstructionSelector.cpp @@ -20,6 +20,8 @@ #define DEBUG_TYPE "arm-isel" +#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" + using namespace llvm; #ifndef LLVM_BUILD_GLOBAL_ISEL Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -32,6 +32,8 @@ #define DEBUG_TYPE "X86-isel" +#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" + using namespace llvm; #ifndef LLVM_BUILD_GLOBAL_ISEL Index: test/TableGen/GlobalISelEmitter.td =================================================================== --- test/TableGen/GlobalISelEmitter.td +++ test/TableGen/GlobalISelEmitter.td @@ -64,38 +64,49 @@ // CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I) const { // CHECK: MachineFunction &MF = *I.getParent()->getParent(); -// CHECK: const MachineRegisterInfo &MRI = MF.getRegInfo(); +// CHECK: MachineRegisterInfo &MRI = MF.getRegInfo(); +// CHECK: AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF); +// CHECK: const PredicateBitset AvailableFeatures = getAvailableFeatures(); +// CHECK: RecordedMIVector MIs; +// CHECK: RecordedMIVector MIStack; //===- Test a pattern with multiple ComplexPattern operands. --------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 4) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_SELECT) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2)))))) && -// CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(3).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((Renderer1 = selectComplexPattern(MI0.getOperand(3))))))) { -// CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, complex:i32:$src3) => (INSN2:i32 GPR32:i32:$src1, complex:i32:$src3, complex:i32:$src2) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN2)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: Renderer1(MIB); -// CHECK-NEXT: Renderer0(MIB); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } +// CHECK-LABEL: MatchTable0[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex, +// CHECK-NEXT: // MIs[0] src3 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable0, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (select:i32 GPR32:i32:$src1, complex:i32:$src2, complex:i32:$src3) => (INSN2:i32 GPR32:i32:$src1, complex:i32:$src3, complex:i32:$src2) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN2)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: Renderers[1](MIB); +// CHECK-NEXT: Renderers[0](MIB); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def : GINodeEquiv; def INSN2 : I<(outs GPR32:$dst), (ins GPR32Op:$src1, complex:$src2, complex:$src3), []>; @@ -104,112 +115,122 @@ //===- Test a simple pattern with regclass operands. ----------------------===// -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_ADD) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(2).getReg(), MRI, TRI)))))) { - -// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2) -// CHECK-NEXT: I.setDesc(TII.get(MyTarget::ADD)); -// CHECK-NEXT: MachineInstr &NewI = I; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } - +// CHECK-LABEL: MatchTable1[] = { +// 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*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClass +// CHECK-NEXT: // MIs[0] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable1, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (add:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (ADD:i32 GPR32:i32:$src1, GPR32:i32:$src2) +// CHECK-NEXT: I.setDesc(TII.get(MyTarget::ADD)); +// CHECK-NEXT: MachineInstr &NewI = I; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), [(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>; //===- Test a nested instruction match. -----------------------------------===// -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; -// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) -// CHECK-NEXT: return false; -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if (!MI0.getOperand(1).isReg()) -// CHECK-NEXT: return false; -// CHECK-NEXT: if (TRI.isPhysicalRegister(MI0.getOperand(1).getReg())) -// CHECK-NEXT: return false; -// CHECK-NEXT: MachineInstr &MI1 = *MRI.getVRegDef(MI0.getOperand(1).getReg()); -// CHECK-NEXT: if (MI1.getNumOperands() < 3) +// CHECK-LABEL: MatchTable2[] = { +// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_PushInsnOpDef, /*MI*/0, /*OpIdx*/1, +// CHECK-NEXT: GIM_RecordInsn, 1, // MIs[1] +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3, +// CHECK-NEXT: GIM_PopInsn, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD, +// CHECK-NEXT: // MIs[1] Operand 0 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: // MIs[1] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[1] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src3 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable2, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: if (!isObviouslySafeToFold(*MIs[1])) // CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_MUL) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (((MI1.getOpcode() == TargetOpcode::G_ADD) && -// CHECK-NEXT: ((/* Operand 0 */ (MRI.getType(MI1.getOperand(0).getReg()) == (LLT::scalar(32))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI1.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI1.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(2).getReg(), MRI, TRI)))))) -// CHECK-NEXT: ))) && -// CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(2).getReg(), MRI, TRI)))))) { -// CHECK-NEXT: if (!isObviouslySafeToFold(MI1)) return false; -// CHECK-NEXT: // (mul:i32 (add:i32 GPR32:i32:$src1, GPR32:i32:$src2), GPR32:i32:$src3) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MULADD)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(MI1.getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(MI1.getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(2)/*src3*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, &MI1, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } +// CHECK-NEXT: // (mul:i32 (add:i32 GPR32:i32:$src1, GPR32:i32:$src2), GPR32:i32:$src3) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MULADD)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MIs[1]->getOperand(1)/*src1*/); +// CHECK-NEXT: MIB.add(MIs[1]->getOperand(2)/*src2*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(2)/*src3*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], MIs[1], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // We also get a second rule by commutativity. -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit}; -// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) -// CHECK-NEXT: return false; -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if (!MI0.getOperand(2).isReg()) -// CHECK-NEXT: return false; -// CHECK-NEXT: if (TRI.isPhysicalRegister(MI0.getOperand(2).getReg())) -// CHECK-NEXT: return false; -// CHECK-NEXT: MachineInstr &MI1 = *MRI.getVRegDef(MI0.getOperand(2).getReg()); -// CHECK-NEXT: if (MI1.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_MUL) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src3 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (((MI1.getOpcode() == TargetOpcode::G_ADD) && -// CHECK-NEXT: ((/* Operand 0 */ (MRI.getType(MI1.getOperand(0).getReg()) == (LLT::scalar(32))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI1.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI1.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI1.getOperand(2).getReg(), MRI, TRI)))))) -// CHECK-NEXT: )))) { -// CHECK-NEXT: if (!isObviouslySafeToFold(MI1)) return false; -// CHECK-NEXT: // (mul:i32 GPR32:i32:$src3, (add:i32 GPR32:i32:$src1, GPR32:i32:$src2)) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) +// CHECK-LABEL: MatchTable3[] = { +// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA, +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_PushInsnOpDef, /*MI*/0, /*OpIdx*/2, +// CHECK-NEXT: GIM_RecordInsn, 1, // MIs[1] +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3, +// CHECK-NEXT: GIM_PopInsn, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src3 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD, +// CHECK-NEXT: // MIs[1] Operand 0 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: // MIs[1] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[1] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable3, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: if (!isObviouslySafeToFold(*MIs[1])) +// CHECK-NEXT: return false; +// CHECK-NEXT: // (mul:i32 GPR32:i32:$src3, (add:i32 GPR32:i32:$src1, GPR32:i32:$src2)) => (MULADD:i32 GPR32:i32:$src1, GPR32:i32:$src2, GPR32:i32:$src3) // CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MULADD)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(MI1.getOperand(1)/*src1*/); -// CHECK-NEXT: MIB.add(MI1.getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src3*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, &MI1, }) +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MIs[1]->getOperand(1)/*src1*/); +// CHECK-NEXT: MIB.add(MIs[1]->getOperand(2)/*src2*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src3*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], MIs[1], }) // CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) // CHECK-NEXT: MIB.addMemOperand(MMO); // CHECK-NEXT: I.eraseFromParent(); @@ -225,35 +246,37 @@ //===- Test another simple pattern with regclass operands. ----------------===// -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: PredicateBitset ExpectedFeatures = {Feature_HasABit, Feature_HasBBit, Feature_HasCBit}; -// CHECK-NEXT: if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures) -// CHECK-NEXT: return false; -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_MUL) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(2).getReg(), MRI, TRI)))))) { -// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MUL)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(2)/*src2*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable4[] = { +// 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: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable4, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (mul:i32 GPR32:i32:$src1, GPR32:i32:$src2) => (MUL:i32 GPR32:i32:$src2, GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::MUL)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(2)/*src2*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1), [(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>, @@ -262,30 +285,36 @@ //===- Test a pattern with ComplexPattern operands. -----------------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_SUB) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((Renderer0 = selectComplexPattern(MI0.getOperand(2))))))) { -// CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN1)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: Renderer0(MIB); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } +// CHECK-LABEL: MatchTable5[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable5, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (sub:i32 GPR32:i32:$src1, complex:i32:$src2) => (INSN1:i32 GPR32:i32:$src1, complex:i32:$src2) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::INSN1)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: Renderers[0](MIB); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def INSN1 : I<(outs GPR32:$dst), (ins GPR32:$src1, complex:$src2), []>; def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>; @@ -293,32 +322,36 @@ //===- Test a simple pattern with a default operand. ----------------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -2, MRI))))) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -2:i32) => (XORI:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORI)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable6[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckInt, /*MI*/0, /*Op*/2, -2 +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable6, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -2:i32) => (XORI:i32 GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORI)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.addImm(-1); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // The -2 is just to distinguish it from the 'not' case below. def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1), @@ -327,32 +360,36 @@ //===- Test a simple pattern with a default register operand. -------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -3, MRI))))) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -3:i32) => (XOR:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XOR)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable7[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckInt, /*MI*/0, /*Op*/2, -3 +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable7, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -3:i32) => (XOR:i32 GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XOR)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.addReg(MyTarget::R0); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // The -3 is just to distinguish it from the 'not' case below and the other default op case above. def XOR : I<(outs GPR32:$dst), (ins Z:$src2, GPR32:$src1), @@ -361,33 +398,37 @@ //===- Test a simple pattern with a multiple default operands. ------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -4, MRI))))) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -4:i32) => (XORlike:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORlike)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable8[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckInt, /*MI*/0, /*Op*/2, -4 +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable8, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -4:i32) => (XORlike:i32 GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORlike)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.addImm(-1); +// CHECK-NEXT: MIB.addReg(MyTarget::R0); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // The -4 is just to distinguish it from the other 'not' cases. def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1), @@ -396,34 +437,38 @@ //===- Test a simple pattern with multiple operands with defaults. --------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -5, MRI))))) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORManyDefaults)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addImm(-1); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*src1*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable9[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckInt, /*MI*/0, /*Op*/2, -5, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable9, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$src1, -5:i32) => (XORManyDefaults:i32 GPR32:i32:$src1) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::XORManyDefaults)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.addImm(-1); +// CHECK-NEXT: MIB.addReg(MyTarget::R0); +// CHECK-NEXT: MIB.addReg(MyTarget::R0); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*src1*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // The -5 is just to distinguish it from the other cases. def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1), @@ -434,32 +479,36 @@ // This must precede the 3-register variants because constant immediates have // priority over register banks. -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 3) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_XOR) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Wm */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* Operand 2 */ (MRI.getType(MI0.getOperand(2).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: (isOperandImmEqual(MI0.getOperand(2), -1, MRI))))) { -// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm) -// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::ORN)); -// CHECK-NEXT: MIB.add(MI0.getOperand(0)/*dst*/); -// CHECK-NEXT: MIB.addReg(MyTarget::R0); -// CHECK-NEXT: MIB.add(MI0.getOperand(1)/*Wm*/); -// CHECK-NEXT: for (const auto *FromMI : {&MI0, }) -// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) -// CHECK-NEXT: MIB.addMemOperand(MMO); -// CHECK-NEXT: I.eraseFromParent(); -// CHECK-NEXT: MachineInstr &NewI = *MIB; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable10[] = { +// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3, +// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR, +// CHECK-NEXT: // MIs[0] dst +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Wm +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] Operand 2 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckInt, /*MI*/0, /*Op*/2, -1, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable10, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (xor:i32 GPR32:i32:$Wm, -1:i32) => (ORN:i32 R0:i32, GPR32:i32:$Wm) +// CHECK-NEXT: MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(MyTarget::ORN)); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(0)/*dst*/); +// CHECK-NEXT: MIB.addReg(MyTarget::R0); +// CHECK-NEXT: MIB.add(MIs[0]->getOperand(1)/*Wm*/); +// CHECK-NEXT: for (const auto *FromMI : {MIs[0], }) +// CHECK-NEXT: for (const auto &MMO : FromMI->memoperands()) +// CHECK-NEXT: MIB.addMemOperand(MMO); +// CHECK-NEXT: I.eraseFromParent(); +// CHECK-NEXT: MachineInstr &NewI = *MIB; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>; def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>; @@ -467,23 +516,26 @@ //===- Test a COPY_TO_REGCLASS --------------------------------------------===// // -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 2) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_BITCAST) && -// CHECK-NEXT: ((/* dst */ (MRI.getType(MI0.getOperand(0).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::GPR32RegClass) == RBI.getRegBank(MI0.getOperand(0).getReg(), MRI, TRI))))) && -// CHECK-NEXT: ((/* src1 */ (MRI.getType(MI0.getOperand(1).getReg()) == (LLT::scalar(32))) && -// CHECK-NEXT: ((&RBI.getRegBankFromRegClass(MyTarget::FPR32RegClass) == RBI.getRegBank(MI0.getOperand(1).getReg(), MRI, TRI)))))) -// CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32) -// CHECK-NEXT: I.setDesc(TII.get(TargetOpcode::COPY)); -// CHECK-NEXT: MachineInstr &NewI = I; -// CHECK-NEXT: constrainOperandRegToRegClass(NewI, 0, &MyTarget::GPR32RegClass, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable11[] = { +// 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*/0, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID, +// CHECK-NEXT: // MIs[0] src1 +// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32, +// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::FPR32RegClassID, +// CHECK-NEXT: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable11, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (bitconvert:i32 FPR32:f32:$src1) => (COPY_TO_REGCLASS:i32 FPR32:f32:$src1, GPR32:i32) +// CHECK-NEXT: I.setDesc(TII.get(TargetOpcode::COPY)); +// CHECK-NEXT: MachineInstr &NewI = I; +// CHECK-NEXT: constrainOperandRegToRegClass(NewI, 0, &MyTarget::GPR32RegClass, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } // The -6 is just to distinguish it from the other 'not' cases. def : Pat<(i32 (bitconvert FPR32:$src1)), @@ -491,21 +543,22 @@ //===- Test a pattern with an MBB operand. --------------------------------===// -// CHECK-LABEL: if ([&]() { -// CHECK-NEXT: MachineInstr &MI0 = I; -// CHECK-NEXT: if (MI0.getNumOperands() < 1) -// CHECK-NEXT: return false; -// CHECK-NEXT: if ((MI0.getOpcode() == TargetOpcode::G_BR) && -// CHECK-NEXT: ((/* target */ (MI0.getOperand(0).isMBB())))) { - -// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target) -// CHECK-NEXT: I.setDesc(TII.get(MyTarget::BR)); -// CHECK-NEXT: MachineInstr &NewI = I; -// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); -// CHECK-NEXT: return true; -// CHECK-NEXT: } -// CHECK-NEXT: return false; -// CHECK-NEXT: }()) { return true; } +// CHECK-LABEL: MatchTable12[] = { +// 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: GIM_Accept, +// CHECK-NEXT: }; +// CHECK-NEXT: MIs.clear(); +// CHECK-NEXT: MIs.push_back(&I); +// CHECK-NEXT: if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, FeatureBitsets, ComplexPredicates, MatchTable12, MRI, TRI, RBI, AvailableFeatures)) { +// CHECK-NEXT: // (br (bb:Other):$target) => (BR (bb:Other):$target) +// CHECK-NEXT: I.setDesc(TII.get(MyTarget::BR)); +// CHECK-NEXT: MachineInstr &NewI = I; +// CHECK-NEXT: constrainSelectedInstRegOperands(NewI, TII, TRI, RBI); +// CHECK-NEXT: return true; +// CHECK-NEXT: } def BR : I<(outs), (ins unknown:$target), [(br bb:$target)]>; Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -74,6 +74,18 @@ public: LLTCodeGen(const LLT &Ty) : Ty(Ty) {} + void emitCxxEnumValue(raw_ostream &OS) const { + if (Ty.isScalar()) { + OS << "GILLT_s" << Ty.getSizeInBits(); + return; + } + if (Ty.isVector()) { + OS << "GILLT_v" << Ty.getNumElements() << "s" << Ty.getScalarSizeInBits(); + return; + } + llvm_unreachable("Unhandled LLT"); + } + void emitCxxConstructorCall(raw_ostream &OS) const { if (Ty.isScalar()) { OS << "LLT::scalar(" << Ty.getSizeInBits() << ")"; @@ -88,6 +100,33 @@ } const LLT &get() const { return Ty; } + + /// This ordering is used for std::unique() and std::sort(). There's no + /// particular logic behind the order. + bool operator<(const LLTCodeGen &Other) const { + if (!Ty.isValid()) + return Other.Ty.isValid(); + if (Ty.isScalar()) { + if (!Other.Ty.isValid()) + return false; + if (Other.Ty.isScalar()) + return Ty.getSizeInBits() < Other.Ty.getSizeInBits(); + return false; + } + if (Ty.isVector()) { + if (!Other.Ty.isValid() || Other.Ty.isScalar()) + return false; + if (Other.Ty.isVector()) { + if (Ty.getNumElements() < Other.Ty.getNumElements()) + return true; + if (Ty.getNumElements() > Other.Ty.getNumElements()) + return false; + return Ty.getSizeInBits() < Other.Ty.getSizeInBits(); + } + return false; + } + llvm_unreachable("Unhandled LLT"); + } }; class InstructionMatcher; @@ -184,7 +223,7 @@ /// A map of instruction matchers to the local variables created by /// emitCxxCaptureStmts(). - std::map InsnVariableNames; + std::map InsnVariableNames; /// ID for the next instruction variable defined with defineInsnVar() unsigned NextInsnVarID; @@ -199,17 +238,20 @@ InstructionMatcher &addInstructionMatcher(); void addRequiredFeature(Record *Feature); + const std::vector &getRequiredFeatures() const; template Kind &addAction(Args &&... args); - std::string defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher, - StringRef Value); - StringRef getInsnVarName(const InstructionMatcher &InsnMatcher) const; + unsigned implicitlyDefineInsnVar(raw_ostream &OS, + const InstructionMatcher &Matcher); + unsigned defineInsnVar(raw_ostream &OS, const InstructionMatcher &Matcher, + unsigned InsnVarID, unsigned OpIdx); + unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const; void emitCxxCapturedInsnList(raw_ostream &OS); - void emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr); + void emitCxxCaptureStmts(raw_ostream &OS); -void emit(raw_ostream &OS, SubtargetFeatureInfoMap SubtargetFeatures); +void emit(raw_ostream &OS); /// Compare the priority of this object and B. /// @@ -249,17 +291,12 @@ template void emitCxxPredicateListExpr(raw_ostream &OS, Args &&... args) const { if (Predicates.empty()) { - OS << "true"; + OS << "// No predicates\n"; return; } - StringRef Separator = ""; - for (const auto &Predicate : predicates()) { - OS << Separator << "("; + for (const auto &Predicate : predicates()) Predicate->emitCxxPredicateExpr(OS, std::forward(args)...); - OS << ")"; - Separator = " &&\n"; - } } }; @@ -311,11 +348,12 @@ /// /// Only InstructionOperandMatcher needs to do anything for this method. virtual void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef Expr) const {} + unsigned InsnVarID, unsigned OpIdx) const {} /// Emit a C++ expression that checks the predicate for the given operand. virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const = 0; + unsigned InsnVarID, + unsigned OpIdx) const = 0; /// Compare the priority of this object and B. /// @@ -343,10 +381,11 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "MRI.getType(" << OperandExpr << ".getReg()) == ("; - Ty.emitCxxConstructorCall(OS); - OS << ")"; + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckType, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx + << ", /*Type*/"; + Ty.emitCxxEnumValue(OS); + OS << ", \n"; } }; @@ -369,10 +408,11 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { + unsigned InsnVarID, unsigned OpIdx) const override { unsigned ID = getAllocatedTemporariesBaseID(); - OS << "(Renderer" << ID << " = " << TheDef.getValueAsString("MatcherFn") - << "(" << OperandExpr << "))"; + OS << " GIM_CheckComplexPattern, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", /*Renderer*/" << ID << ", GICP_" + << TheDef.getName() << ",\n"; } unsigned countRendererFns() const override { @@ -394,10 +434,9 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "(&RBI.getRegBankFromRegClass(" << RC.getQualifiedName() - << "RegClass) == RBI.getRegBank(" << OperandExpr - << ".getReg(), MRI, TRI))"; + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckRegBankForClass, /*MI*/" << InsnVarID << ", /*Op*/" + << OpIdx << ", /*RC*/" << RC.getQualifiedName() << "RegClassID,\n"; } }; @@ -411,8 +450,8 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << OperandExpr << ".isMBB()"; + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckIsMBB, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ",\n"; } }; @@ -430,8 +469,9 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "isOperandImmEqual(" << OperandExpr << ", " << Value << ", MRI)"; + unsigned InsnVarID, unsigned OpIdx) const override { + OS << " GIM_CheckInt, /*MI*/" << InsnVarID << ", /*Op*/" << OpIdx << ", " << Value + << ",\n"; } }; @@ -463,8 +503,9 @@ } unsigned getOperandIndex() const { return OpIdx; } - std::string getOperandExpr(StringRef InsnVarName) const { - return (InsnVarName + ".getOperand(" + llvm::to_string(OpIdx) + ")").str(); + std::string getOperandExpr(unsigned InsnVarID) const { + return "MIs[" + llvm::to_string(InsnVarID) + "]->getOperand(" + + llvm::to_string(OpIdx) + ")"; } Optional @@ -484,23 +525,22 @@ /// Emit C++ statements to capture instructions into local variables. void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const { + unsigned InsnVarID) const { for (const auto &Predicate : predicates()) - Predicate->emitCxxCaptureStmts(OS, Rule, OperandExpr); + Predicate->emitCxxCaptureStmts(OS, Rule, InsnVarID, OpIdx); } /// Emit a C++ expression that tests whether the instruction named in - /// InsnVarName matches all the predicate and all the operands. + /// InsnVarID matches all the predicates and all the operands. void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const { - OS << "(/* "; + unsigned InsnVarID) const { + OS << " // MIs[" << InsnVarID << "] "; if (SymbolicName.empty()) OS << "Operand " << OpIdx; else OS << SymbolicName; - OS << " */ "; - emitCxxPredicateListExpr(OS, Rule, getOperandExpr(InsnVarName)); - OS << ")"; + OS << "\n"; + emitCxxPredicateListExpr(OS, Rule, InsnVarID, OpIdx); } /// Compare the priority of this object and B. @@ -567,9 +607,9 @@ PredicateKind getKind() const { return Kind; } /// Emit a C++ expression that tests whether the instruction named in - /// InsnVarName matches the predicate. + /// InsnVarID matches the predicate. virtual void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const = 0; + unsigned InsnVarID) const = 0; /// Compare the priority of this object and B. /// @@ -597,9 +637,9 @@ } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const override { - OS << InsnVarName << ".getOpcode() == " << I->Namespace - << "::" << I->TheDef->getName(); + unsigned InsnVarID) const override { + OS << " GIM_CheckOpcode, /*MI*/" << InsnVarID << ", " << I->Namespace + << "::" << I->TheDef->getName() << ",\n"; } /// Compare the priority of this object and B. @@ -688,24 +728,21 @@ /// Emit C++ statements to check the shape of the match and capture /// instructions into local variables. - void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef Expr) { - OS << "if (" << Expr << ".getNumOperands() < " << getNumOperands() << ")\n" - << " return false;\n"; - for (const auto &Operand : Operands) { - Operand->emitCxxCaptureStmts(OS, Rule, Operand->getOperandExpr(Expr)); - } + void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, + unsigned InsnID) { + OS << " GIM_CheckNumOperands, /*MI*/" << InsnID << ", /*Expected*/" + << getNumOperands() << ",\n"; + for (const auto &Operand : Operands) + Operand->emitCxxCaptureStmts(OS, Rule, InsnID); } /// Emit a C++ expression that tests whether the instruction named in /// InsnVarName matches all the predicates and all the operands. void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef InsnVarName) const { - emitCxxPredicateListExpr(OS, Rule, InsnVarName); - for (const auto &Operand : Operands) { - OS << " &&\n("; - Operand->emitCxxPredicateExpr(OS, Rule, InsnVarName); - OS << ")"; - } + unsigned InsnVarID) const { + emitCxxPredicateListExpr(OS, Rule, InsnVarID); + for (const auto &Operand : Operands) + Operand->emitCxxPredicateExpr(OS, Rule, InsnVarID); } /// Compare the priority of this object and B. @@ -783,23 +820,18 @@ } void emitCxxCaptureStmts(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OS << "if (!" << OperandExpr + ".isReg())\n" - << " return false;\n" - << "if (TRI.isPhysicalRegister(" << OperandExpr + ".getReg()))\n" - << " return false;\n"; - std::string InsnVarName = Rule.defineInsnVar( - OS, *InsnMatcher, - ("*MRI.getVRegDef(" + OperandExpr + ".getReg())").str()); - InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarName); + unsigned InsnID, unsigned OpIdx) const override { + OS << " GIM_PushInsnOpDef, /*MI*/" << InsnID << ", /*OpIdx*/" << OpIdx << ",\n"; + unsigned InsnVarID = Rule.defineInsnVar(OS, *InsnMatcher, InsnID, OpIdx); + InsnMatcher->emitCxxCaptureStmts(OS, Rule, InsnVarID); + OS << " GIM_PopInsn,\n"; } void emitCxxPredicateExpr(raw_ostream &OS, RuleMatcher &Rule, - StringRef OperandExpr) const override { - OperandExpr = Rule.getInsnVarName(*InsnMatcher); - OS << "("; - InsnMatcher->emitCxxPredicateExpr(OS, Rule, OperandExpr); - OS << ")\n"; + unsigned InsnVarID_, + unsigned OpIdx_) const override { + unsigned InsnVarID = Rule.getInsnVarID(*InsnMatcher); + InsnMatcher->emitCxxPredicateExpr(OS, Rule, InsnVarID); } }; @@ -850,9 +882,9 @@ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - StringRef InsnVarName = - Rule.getInsnVarName(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarName); + unsigned InsnVarID = + Rule.getInsnVarID(Operand.getInstructionMatcher()); + std::string OperandExpr = Operand.getOperandExpr(InsnVarID); OS << " MIB.add(" << OperandExpr << "/*" << SymbolicName << "*/);\n"; } }; @@ -885,9 +917,8 @@ void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { const OperandMatcher &Operand = Matched.getOperand(SymbolicName); - StringRef InsnVarName = - Rule.getInsnVarName(Operand.getInstructionMatcher()); - std::string OperandExpr = Operand.getOperandExpr(InsnVarName); + unsigned InsnVarID = Rule.getInsnVarID(Operand.getInstructionMatcher()); + std::string OperandExpr = Operand.getOperandExpr(InsnVarID); OS << " MIB.addReg(" << OperandExpr << ".getReg() /*" << SymbolicName << "*/, 0, " << SubReg->EnumValue << ");\n"; } @@ -959,7 +990,7 @@ } void emitCxxRenderStmts(raw_ostream &OS, RuleMatcher &Rule) const override { - OS << "Renderer" << RendererID << "(MIB);\n"; + OS << " Renderers[" << RendererID << "](MIB);\n"; } }; @@ -991,7 +1022,7 @@ void emitCxxActionStmts(raw_ostream &OS, RuleMatcher &Rule, StringRef RecycleVarName) const override { - OS << "// " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n"; + OS << " // " << *P.getSrcPattern() << " => " << *P.getDstPattern() << "\n"; } }; @@ -1067,7 +1098,7 @@ // TODO: Simple permutation looks like it could be almost as common as // mutation due to commutative operations. - OS << "MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, " + OS << " MachineInstrBuilder MIB = BuildMI(*I.getParent(), I, " "I.getDebugLoc(), TII.get(" << I->Namespace << "::" << I->TheDef->getName() << "));\n"; for (const auto &Renderer : OperandRenderers) @@ -1122,22 +1153,34 @@ RequiredFeatures.push_back(Feature); } +const std::vector &RuleMatcher::getRequiredFeatures() const { + return RequiredFeatures; +} + template Kind &RuleMatcher::addAction(Args &&... args) { Actions.emplace_back(llvm::make_unique(std::forward(args)...)); return *static_cast(Actions.back().get()); } -std::string RuleMatcher::defineInsnVar(raw_ostream &OS, - const InstructionMatcher &Matcher, - StringRef Value) { - std::string InsnVarName = "MI" + llvm::to_string(NextInsnVarID++); - OS << "MachineInstr &" << InsnVarName << " = " << Value << ";\n"; - InsnVariableNames[&Matcher] = InsnVarName; - return InsnVarName; +unsigned +RuleMatcher::implicitlyDefineInsnVar(raw_ostream &OS, + const InstructionMatcher &Matcher) { + unsigned NewInsnVarID = NextInsnVarID++; + InsnVariableNames[&Matcher] = NewInsnVarID; + return NewInsnVarID; +} + +unsigned RuleMatcher::defineInsnVar(raw_ostream &OS, + const InstructionMatcher &Matcher, + unsigned InsnID, unsigned OpIdx) { + unsigned NewInsnVarID = NextInsnVarID++; + OS << " GIM_RecordInsn, " << NewInsnVarID << ", // MIs[" << NewInsnVarID << "]\n"; + InsnVariableNames[&Matcher] = NewInsnVarID; + return NewInsnVarID; } -StringRef RuleMatcher::getInsnVarName(const InstructionMatcher &InsnMatcher) const { +unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const { const auto &I = InsnVariableNames.find(&InsnMatcher); if (I != InsnVariableNames.end()) return I->second; @@ -1146,27 +1189,26 @@ /// Emit a C++ initializer_list containing references to every matched instruction. void RuleMatcher::emitCxxCapturedInsnList(raw_ostream &OS) { - SmallVector Names; + SmallVector IDs; for (const auto &Pair : InsnVariableNames) - Names.push_back(Pair.second); - std::sort(Names.begin(), Names.end()); + IDs.push_back(Pair.second); + std::sort(IDs.begin(), IDs.end()); OS << "{"; - for (const auto &Name : Names) - OS << "&" << Name << ", "; + for (const auto &ID : IDs) + OS << "MIs[" << ID << "], "; OS << "}"; } /// Emit C++ statements to check the shape of the match and capture /// instructions into local variables. -void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS, StringRef Expr) { +void RuleMatcher::emitCxxCaptureStmts(raw_ostream &OS) { assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet"); - std::string InsnVarName = defineInsnVar(OS, *Matchers.front(), Expr); - Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarName); + unsigned InsnVarID = implicitlyDefineInsnVar(OS, *Matchers.front()); + Matchers.front()->emitCxxCaptureStmts(OS, *this, InsnVarID); } -void RuleMatcher::emit(raw_ostream &OS, - SubtargetFeatureInfoMap SubtargetFeatures) { +void RuleMatcher::emit(raw_ostream &OS) { if (Matchers.empty()) llvm_unreachable("Unexpected empty matcher!"); @@ -1181,28 +1223,27 @@ // 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 << "if ("; - OS << "[&]() {\n"; + OS << " const static int64_t MatchTable" << NumPatternEmitted << "[] = {\n"; if (!RequiredFeatures.empty()) { - OS << " PredicateBitset ExpectedFeatures = {"; - StringRef Separator = ""; - for (const auto &Predicate : RequiredFeatures) { - const auto &I = SubtargetFeatures.find(Predicate); - assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); - OS << Separator << I->second.getEnumBitName(); - Separator = ", "; - } - OS << "};\n"; - OS << "if ((AvailableFeatures & ExpectedFeatures) != ExpectedFeatures)\n" - << " return false;\n"; + OS << " GIM_CheckFeatures, GIFBS"; + for (const auto &Predicate : RequiredFeatures) + OS << "_" << Predicate->getName(); + OS << ",\n"; } - emitCxxCaptureStmts(OS, "I"); - OS << " if ("; + emitCxxCaptureStmts(OS); + Matchers.front()->emitCxxPredicateExpr(OS, *this, - getInsnVarName(*Matchers.front())); - OS << ") {\n"; + getInsnVarID(*Matchers.front())); + + OS << " GIM_Accept,\n" + << " };\n" + << " MIs.clear();\n" + << " MIs.push_back(&I);\n" + << " if (executeMatchTable(*this, MIs, MIStack, Renderers, TypeObjects, " + "FeatureBitsets, ComplexPredicates, MatchTable" + << NumPatternEmitted << ", MRI, TRI, RBI, AvailableFeatures)) {\n"; // We must also check if it's safe to fold the matched instructions. if (InsnVariableNames.size() >= 2) { @@ -1213,8 +1254,8 @@ continue; // Reject the difficult cases until we have a more accurate check. - OS << " if (!isObviouslySafeToFold(" << Pair.second - << ")) return false;\n"; + OS << " if (!isObviouslySafeToFold(*MIs[" << Pair.second << "]))\n" + << " return false;\n"; // FIXME: Emit checks to determine it's _actually_ safe to fold and/or // account for unsafe cases. @@ -1257,10 +1298,8 @@ MA->emitCxxActionStmts(OS, *this, "I"); } - OS << " return true;\n"; - OS << " }\n"; - OS << " return false;\n"; - OS << " }()) { return true; }\n\n"; + OS << " return true;\n"; + OS << " }\n\n"; } bool RuleMatcher::isHigherPriorityThan(const RuleMatcher &B) const { @@ -1876,6 +1915,14 @@ return false; }); + std::vector ComplexPredicates = + RK.getAllDerivedDefinitions("GIComplexOperandMatcher"); + std::sort(ComplexPredicates.begin(), ComplexPredicates.end(), + [](const Record *A, const Record *B) { + if (A->getName() < B->getName()) + return true; + return false; + }); unsigned MaxTemporaries = 0; for (const auto &Rule : Rules) MaxTemporaries = std::max(MaxTemporaries, Rule.countRendererFns()); @@ -1887,15 +1934,24 @@ "llvm::PredicateBitsetImpl;\n" << "#endif // ifdef GET_GLOBALISEL_PREDICATE_BITSET\n\n"; - OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n"; - for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << " mutable ComplexRendererFn Renderer" << I << ";\n"; - OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; - - OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"; - for (unsigned I = 0; I < MaxTemporaries; ++I) - OS << ", Renderer" << I << "(nullptr)\n"; - OS << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; + OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n" + << " mutable std::vector Renderers;\n" + << " typedef " + "ComplexRendererFn(" + << Target.getName() + << "InstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;\n" + << " const std::vector ComplexPredicates;\n" + << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL\n\n"; + + OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n" + << ", Renderers(" << MaxTemporaries << ", nullptr),\n" + "ComplexPredicates({nullptr, // GICP_Invalid\n"; + for (const auto &Record : ComplexPredicates) + OS << " &" << Target.getName() + << "InstructionSelector::" << Record->getValueAsString("MatcherFn") + << ", // " << Record->getName() << "\n"; + OS << "})\n" + << "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n"; OS << "#ifdef GET_GLOBALISEL_IMPL\n"; SubtargetFeatureInfo::emitSubtargetFeatureBitEnumeration(SubtargetFeatures, @@ -1923,16 +1979,103 @@ "computeAvailableFunctionFeatures", FunctionFeatures, OS, "const MachineFunction *MF"); + // Emit a table containing the LLT objects needed by the matcher and an enum + // for the matcher to reference them with. + std::vector TypeObjects = { + LLT::scalar(8), LLT::scalar(16), LLT::scalar(32), + LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1), + LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1), + LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8), + LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16), + LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32), + LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32), + LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64), + }; + std::sort(TypeObjects.begin(), TypeObjects.end()); + OS << "enum {\n"; + for (const auto &TypeObject : TypeObjects) { + OS << " "; + TypeObject.emitCxxEnumValue(OS); + OS << ",\n"; + } + OS << "};\n" + << "const static LLT TypeObjects[] = {\n"; + for (const auto &TypeObject : TypeObjects) { + OS << " "; + TypeObject.emitCxxConstructorCall(OS); + OS << ",\n"; + } + OS << "};\n\n"; + + // Emit a table containing the PredicateBitsets objects needed by the matcher + // and an enum for the matcher to reference them with. + std::vector> FeatureBitsets; + for (auto &Rule : Rules) + FeatureBitsets.push_back(Rule.getRequiredFeatures()); + std::sort( + FeatureBitsets.begin(), FeatureBitsets.end(), + [&](const std::vector &A, const std::vector &B) { + if (A.size() < B.size()) + return true; + if (A.size() > B.size()) + return false; + for (const auto &Pair : zip(A, B)) { + if (std::get<0>(Pair)->getName() < std::get<1>(Pair)->getName()) + return true; + if (std::get<0>(Pair)->getName() > std::get<1>(Pair)->getName()) + return false; + } + return false; + }); + FeatureBitsets.erase( + std::unique(FeatureBitsets.begin(), FeatureBitsets.end()), + FeatureBitsets.end()); + OS << "enum {\n" + << " GIFBS_Invalid,\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " GIFBS"; + for (const auto &Feature : FeatureBitset) + OS << "_" << Feature->getName(); + OS << ",\n"; + } + OS << "};\n" + << "const static PredicateBitset FeatureBitsets[] {\n" + << " {}, // GIFBS_Invalid\n"; + for (const auto &FeatureBitset : FeatureBitsets) { + if (FeatureBitset.empty()) + continue; + OS << " {"; + for (const auto &Feature : FeatureBitset) { + const auto &I = SubtargetFeatures.find(Feature); + assert(I != SubtargetFeatures.end() && "Didn't import predicate?"); + OS << I->second.getEnumBitName() << ", "; + } + OS << "},\n"; + } + OS << "};\n\n"; + + // Emit complex predicate table and an enum to reference them with. + OS << "enum {\n" + << " GICP_Invalid,\n"; + for (const auto &Record : ComplexPredicates) + OS << " GICP_" << Record->getName() << ",\n"; + OS << "};\n" + << "// See constructor for table contents\n\n"; + OS << "bool " << Target.getName() << "InstructionSelector::selectImpl(MachineInstr &I) const {\n" << " MachineFunction &MF = *I.getParent()->getParent();\n" - << " const MachineRegisterInfo &MRI = MF.getRegInfo();\n" + << " MachineRegisterInfo &MRI = MF.getRegInfo();\n" << " // FIXME: This should be computed on a per-function basis rather than per-insn.\n" << " AvailableFunctionFeatures = computeAvailableFunctionFeatures(&STI, &MF);\n" - << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n"; + << " const PredicateBitset AvailableFeatures = getAvailableFeatures();\n" + << " RecordedMIVector MIs;\n" + << " RecordedMIVector MIStack;\n\n"; for (auto &Rule : Rules) { - Rule.emit(OS, SubtargetFeatures); + Rule.emit(OS); ++NumPatternEmitted; }