[llvm] r332912 - Revert r332907 "[GlobalISel] Improving InstructionSelect's performance by reducing MatchTable..."
Roman Tereshin via llvm-commits
llvm-commits at lists.llvm.org
Mon May 21 15:21:25 PDT 2018
Author: rtereshin
Date: Mon May 21 15:21:24 2018
New Revision: 332912
URL: http://llvm.org/viewvc/llvm-project?rev=332912&view=rev
Log:
Revert r332907 "[GlobalISel] Improving InstructionSelect's performance by reducing MatchTable..."
There is a compile time error I didn't see locally, investigating now.
Modified:
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
llvm/trunk/test/TableGen/GlobalISelEmitter.td
llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h?rev=332912&r1=332911&r2=332912&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelector.h Mon May 21 15:21:24 2018
@@ -20,7 +20,6 @@
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CodeGenCoverage.h"
-#include "llvm/Support/LowLevelTypeImpl.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
@@ -32,6 +31,7 @@ namespace llvm {
class APInt;
class APFloat;
+class LLT;
class MachineInstr;
class MachineInstrBuilder;
class MachineFunction;
@@ -146,14 +146,12 @@ enum {
/// - 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
@@ -170,7 +168,6 @@ enum {
/// - OpIdx - Operand index
/// - Expected Intrinsic ID
GIM_CheckIntrinsicID,
-
/// Check the specified operand is an MBB
/// - InsnID - Instruction ID
/// - OpIdx - Operand index
@@ -199,7 +196,6 @@ enum {
/// - OldInsnID - Instruction ID to mutate
/// - NewOpcode - The new opcode to use
GIR_MutateOpcode,
-
/// Build a new instruction
/// - InsnID - Instruction ID to define
/// - Opcode - The new opcode to use
@@ -210,7 +206,6 @@ enum {
/// - OldInsnID - Instruction ID to copy from
/// - OpIdx - The operand to copy
GIR_Copy,
-
/// Copy an operand to the specified instruction or add a zero register if the
/// operand is a zero immediate.
/// - NewInsnID - Instruction ID to modify
@@ -224,7 +219,6 @@ enum {
/// - OpIdx - The operand to copy
/// - SubRegIdx - The subregister to copy
GIR_CopySubReg,
-
/// Add an implicit register def to the specified instruction
/// - InsnID - Instruction ID to modify
/// - RegNum - The register to add
@@ -237,13 +231,11 @@ enum {
/// - InsnID - Instruction ID to modify
/// - RegNum - The register to add
GIR_AddRegister,
-
/// Add a temporary register to the specified instruction
/// - InsnID - Instruction ID to modify
/// - TempRegID - The temporary register ID to add
/// - TempRegFlags - The register flags to set
GIR_AddTempRegister,
-
/// Add an immediate to the specified instruction
/// - InsnID - Instruction ID to modify
/// - Imm - The immediate to add
@@ -252,7 +244,6 @@ enum {
/// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call
GIR_ComplexRenderer,
-
/// Render sub-operands of complex operands to the specified instruction
/// - InsnID - Instruction ID to modify
/// - RendererID - The renderer to call
@@ -281,23 +272,19 @@ enum {
/// - OpIdx - Operand index
/// - RCEnum - Register class enumeration value
GIR_ConstrainOperandRC,
-
/// Constrain an instructions operands according to the instruction
/// description.
/// - InsnID - Instruction ID to modify
GIR_ConstrainSelectedInstOperands,
-
/// Merge all memory operands into instruction.
/// - InsnID - Instruction ID to modify
/// - MergeInsnID... - One or more Instruction ID to merge into the result.
/// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
/// merge.
GIR_MergeMemOperands,
-
/// Erase from parent.
/// - InsnID - Instruction ID to erase
GIR_EraseFromParent,
-
/// Create a new temporary register that's not constrained.
/// - TempRegID - The temporary register ID to initialize.
/// - Expected type
@@ -310,7 +297,6 @@ enum {
/// - RuleID - The ID of the rule that was covered.
GIR_Coverage,
- /// Keeping track of the number of the GI opcodes. Must be the last entry.
GIU_NumOpcodes,
};
@@ -355,15 +341,6 @@ public:
template <class PredicateBitset, class ComplexMatcherMemFn,
class CustomRendererFn>
struct ISelInfoTy {
- ISelInfoTy(const LLT *TypeObjects, size_t NumTypeObjects,
- const PredicateBitset *FeatureBitsets,
- const ComplexMatcherMemFn *ComplexPredicates,
- const CustomRendererFn *CustomRenderers)
- : TypeObjects(TypeObjects),
- FeatureBitsets(FeatureBitsets),
- ComplexPredicates(ComplexPredicates),
- CustomRenderers(CustomRenderers) {
- }
const LLT *TypeObjects;
const PredicateBitset *FeatureBitsets;
const ComplexMatcherMemFn *ComplexPredicates;
Modified: llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h?rev=332912&r1=332911&r2=332912&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h Mon May 21 15:21:24 2018
@@ -53,9 +53,8 @@ bool InstructionSelector::executeMatchTa
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
CodeGenCoverage &CoverageInfo) const {
-
uint64_t CurrentIdx = 0;
- SmallVector<uint64_t, 4> OnFailResumeAt;
+ SmallVector<uint64_t, 8> OnFailResumeAt;
enum RejectAction { RejectAndGiveUp, RejectAndResume };
auto handleReject = [&]() -> RejectAction {
@@ -63,7 +62,8 @@ bool InstructionSelector::executeMatchTa
dbgs() << CurrentIdx << ": Rejected\n");
if (OnFailResumeAt.empty())
return RejectAndGiveUp;
- CurrentIdx = OnFailResumeAt.pop_back_val();
+ CurrentIdx = OnFailResumeAt.back();
+ OnFailResumeAt.pop_back();
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": Resume at " << CurrentIdx << " ("
<< OnFailResumeAt.size() << " try-blocks remain)\n");
@@ -139,13 +139,12 @@ bool InstructionSelector::executeMatchTa
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t Expected = MatchTable[CurrentIdx++];
- assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
unsigned Opcode = State.MIs[InsnID]->getOpcode();
-
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIM_CheckOpcode(MIs[" << InsnID
<< "], ExpectedOpcode=" << Expected
<< ") // Got=" << Opcode << "\n");
+ assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
if (Opcode != Expected) {
if (handleReject() == RejectAndGiveUp)
return false;
@@ -198,8 +197,7 @@ bool InstructionSelector::executeMatchTa
<< CurrentIdx << ": GIM_CheckAPIntImmPredicate(MIs["
<< InsnID << "], Predicate=" << Predicate << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
- assert(State.MIs[InsnID]->getOpcode() == TargetOpcode::G_CONSTANT &&
- "Expected G_CONSTANT");
+ assert(State.MIs[InsnID]->getOpcode() && "Expected G_CONSTANT");
assert(Predicate > GIPFP_APInt_Invalid && "Expected a valid predicate");
APInt Value;
if (State.MIs[InsnID]->getOperand(1).isCImm())
@@ -238,6 +236,7 @@ bool InstructionSelector::executeMatchTa
dbgs() << CurrentIdx << ": GIM_CheckAtomicOrdering(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp)
return false;
@@ -256,6 +255,7 @@ bool InstructionSelector::executeMatchTa
<< ": GIM_CheckAtomicOrderingOrStrongerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp)
return false;
@@ -274,6 +274,7 @@ bool InstructionSelector::executeMatchTa
<< ": GIM_CheckAtomicOrderingWeakerThan(MIs["
<< InsnID << "], " << (uint64_t)Ordering << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
if (!State.MIs[InsnID]->hasOneMemOperand())
if (handleReject() == RejectAndGiveUp)
return false;
@@ -374,6 +375,7 @@ bool InstructionSelector::executeMatchTa
<< "]->getOperand(" << OpIdx
<< "), TypeID=" << TypeID << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (!MO.isReg() ||
MRI.getType(MO.getReg()) != ISelInfo.TypeObjects[TypeID]) {
@@ -392,6 +394,7 @@ bool InstructionSelector::executeMatchTa
<< InsnID << "]->getOperand(" << OpIdx
<< "), SizeInBits=" << SizeInBits << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
// iPTR must be looked up in the target.
if (SizeInBits == 0) {
MachineFunction *MF = State.MIs[InsnID]->getParent()->getParent();
@@ -463,6 +466,7 @@ bool InstructionSelector::executeMatchTa
<< InsnID << "]->getOperand(" << OpIdx
<< "), Value=" << Value << ")\n");
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
+
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
if (MO.isReg()) {
// isOperandImmEqual() will sign-extend to 64-bits, so should we.
@@ -558,7 +562,7 @@ bool InstructionSelector::executeMatchTa
}
case GIM_Reject:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
- dbgs() << CurrentIdx << ": GIM_Reject\n");
+ dbgs() << CurrentIdx << ": GIM_Reject");
if (handleReject() == RejectAndGiveUp)
return false;
break;
@@ -850,7 +854,7 @@ bool InstructionSelector::executeMatchTa
case GIR_Done:
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
- dbgs() << CurrentIdx << ": GIR_Done\n");
+ dbgs() << CurrentIdx << ": GIR_Done");
return true;
default:
Modified: llvm/trunk/test/TableGen/GlobalISelEmitter.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitter.td?rev=332912&r1=332911&r2=332912&view=diff
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitter.td (original)
+++ llvm/trunk/test/TableGen/GlobalISelEmitter.td Mon May 21 15:21:24 2018
@@ -1,19 +1,11 @@
-// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -optimize-match-table=false %s -o %T/non-optimized.cpp
-// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -optimize-match-table=true %s -o %T/optimized.cpp
-// RUN: llvm-tblgen -gen-global-isel -I %p/../../include %s -o %T/default.cpp
-
-// RUN: FileCheck %s --check-prefixes=CHECK,R19C,R19N -input-file=%T/non-optimized.cpp
-// RUN: FileCheck %s --check-prefixes=CHECK,R19C,R19O -input-file=%T/optimized.cpp
-
-// RUN: FileCheck %s --check-prefixes=CHECK,R21C,R21N -input-file=%T/non-optimized.cpp
-// RUN: FileCheck %s --check-prefixes=CHECK,R21C,R21O -input-file=%T/optimized.cpp
-
-// RUN: FileCheck %s --check-prefixes=CHECK,R20C,R20N -input-file=%T/non-optimized.cpp
-// RUN: FileCheck %s --check-prefixes=CHECK,R00C,R00N -input-file=%T/non-optimized.cpp
-// RUN: FileCheck %s --check-prefixes=CHECK,R01C,R01N -input-file=%T/non-optimized.cpp
-// RUN: FileCheck %s --check-prefixes=CHECK,R02C,R02N,NOOPT -input-file=%T/non-optimized.cpp
-
-// RUN: diff %T/default.cpp %T/optimized.cpp
+// RUN: llvm-tblgen -optimize-match-table=false -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=NOOPT
+//
+// The optimized table can reorder predicates between rules, but the rules
+// order must remain the same.
+// RUN: llvm-tblgen -optimize-match-table=true -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=OPT
+//
+// Make sure the default is to optimize the table.
+// RUN: llvm-tblgen -gen-global-isel -I %p/../../include %s | FileCheck %s --check-prefix=CHECK --check-prefix=OPT
include "llvm/Target/Target.td"
@@ -91,7 +83,7 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-NEXT: , State(2),
-// CHECK-NEXT: ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers)
+// CHECK-NEXT: ISelInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers})
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
@@ -122,7 +114,6 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-NEXT: enum {
// CHECK-NEXT: GILLT_s32,
// CHECK-NEXT: }
-// CHECK-NEXT: const static size_t NumTypeObjects = 1;
// CHECK-NEXT: const static LLT TypeObjects[] = {
// CHECK-NEXT: LLT::scalar(32),
// CHECK-NEXT: };
@@ -233,73 +224,64 @@ def HasC : Predicate<"Subtarget->hasC()"
// CHECK-NEXT: return true;
// CHECK-NEXT: }
-// CHECK: const int64_t *
-// CHECK-LABEL: MyTargetInstructionSelector::getMatchTable() const {
-// CHECK-NEXT: MatchTable0[] = {
-
//===- Test a pattern with multiple ComplexPatterns in multiple instrs ----===//
//
-// R19O-NEXT: GIM_Try, /*On fail goto*//*Label [[GROUP_NUM:[0-9]+]]*/ [[GROUP:[0-9]+]],
-// R19O-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
-//
-// R19C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// R19C-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
-// R19N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
-// R19N-NEXT: // MIs[0] dst
-// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R19N-NEXT: // MIs[0] src1
-// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R19N-NEXT: // MIs[0] Operand 2
-// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex_rr,
-// R19C-NEXT: // MIs[0] Operand 3
-// R19C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
-// R19C-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/3, // MIs[1]
-// R19C-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/4,
-// R19C-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_SELECT,
-// R19C-NEXT: // MIs[1] Operand 0
-// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
-// R19N-NEXT: // MIs[1] src3
-// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R19N-NEXT: // MIs[1] src4
-// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/2, /*Renderer*/1, GICP_gi_complex,
-// R19N-NEXT: // MIs[1] Operand 3
-// R19C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/3, /*Type*/GILLT_s32,
-// R19N-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/3, /*Renderer*/2, GICP_gi_complex,
-// R19C-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
-// R19O-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex_rr,
-// R19O-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/2, /*Renderer*/1, GICP_gi_complex,
-// R19O-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/3, /*Renderer*/2, GICP_gi_complex,
-// R19O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R19O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R19O-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R19C-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, (complex_rr:{ *:[i32] } GPR32:{ *:[i32] }:$src2a, GPR32:{ *:[i32] }:$src2b), (select:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, (complex:{ *:[i32] } i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))) => (INSN3:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2b, GPR32:{ *:[i32] }:$src2a, (INSN4:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))
-// R19C-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
-// R19C-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::INSN4,
-// R19C-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
-// R19C-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // src3
-// R19C-NEXT: GIR_ComplexRenderer, /*InsnID*/1, /*RendererID*/1,
-// R19C-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/0, // src5a
-// R19C-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/1, // src5b
-// R19C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
-// R19C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN3,
-// R19C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R19C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// R19C-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/1, // src2b
-// R19C-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/0, // src2a
-// R19C-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
-// R19C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R19C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R19C-NEXT: // GIR_Coverage, 19,
-// R19C-NEXT: GIR_Done,
-// R19C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
-//
-// R19O: GIM_Reject,
-// R19O-NEXT: // Label [[GROUP_NUM]]: @[[GROUP]]
+
+// CHECK: const int64_t *
+// CHECK-LABEL: MyTargetInstructionSelector::getMatchTable() const {
+// CHECK: MatchTable0[] = {
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[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,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
+// OPT-NEXT: // No instruction predicates
+// 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_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex_rr,
+// CHECK-NEXT: // MIs[0] Operand 3
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_SELECT,
+// CHECK-NEXT: // MIs[1] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[1] src3
+// 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] src4
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/2, /*Renderer*/1, GICP_gi_complex,
+// CHECK-NEXT: // MIs[1] Operand 3
+// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/3, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckComplexPattern, /*MI*/1, /*Op*/3, /*Renderer*/2, GICP_gi_complex,
+// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
+// CHECK-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, (complex_rr:{ *:[i32] } GPR32:{ *:[i32] }:$src2a, GPR32:{ *:[i32] }:$src2b), (select:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, (complex:{ *:[i32] } i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))) => (INSN3:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2b, GPR32:{ *:[i32] }:$src2a, (INSN4:{ *:[i32] } GPR32:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src4, i32imm:{ *:[i32] }:$src5a, i32imm:{ *:[i32] }:$src5b))
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::INSN4,
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // src3
+// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/1, /*RendererID*/1,
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/0, // src5a
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/1, /*RendererID*/2, /*SubOperand*/1, // src5b
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN3,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/1, // src2b
+// CHECK-NEXT: GIR_ComplexSubOperandRenderer, /*InsnID*/0, /*RendererID*/0, /*SubOperand*/0, // src2a
+// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def INSN3 : I<(outs GPR32:$dst),
(ins GPR32Op:$src1, GPR32:$src2a, GPR32:$src2b, GPR32:$scr), []>;
@@ -313,84 +295,77 @@ def : Pat<(select GPR32:$src1, (complex_
(INSN4 GPR32:$src3, complex:$src4, i32imm:$src5a,
i32imm:$src5b))>;
-// R21O-NEXT: GIM_Try, /*On fail goto*//*Label [[GROUP_NUM:[0-9]+]]*/ [[GROUP:[0-9]+]],
-// R21O-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
-//
-// R21C-NEXT: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 19 //
-// R21C-NOT: GIR_Done,
-// R21C: // GIR_Coverage, 19,
-// R21C-NEXT: GIR_Done,
-// R21C-NEXT: // Label [[PREV_NUM]]: @[[PREV]]
-// R21C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 21 //
-//
-// R21C-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
-// R21N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
-// R21N-NEXT: // MIs[0] dst
-// R21C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R21N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R21N-NEXT: // MIs[0] src1
-// R21C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// R21N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R21N-NEXT: // MIs[0] src2
-// R21C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// R21N-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
-// R21N-NEXT: // MIs[0] src3
-// R21C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/3, /*Type*/GILLT_s32,
-// R21O-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
-// R21C-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/3, /*Renderer*/1, GICP_gi_complex,
-// R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R21O-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R21C-NEXT: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3) => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
-// R21C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2,
-// R21C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R21C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// R21C-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/1,
-// R21C-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0,
-// R21C-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList,
-// R21C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R21C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R21C-NEXT: // GIR_Coverage, 21,
-// R21C-NEXT: GIR_Done,
-// R21C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
-//
-// R21O-NEXT: GIM_Reject,
-// R21O-NEXT: // Label [[GROUP_NUM]]: @[[GROUP]]
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/4,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SELECT,
+// OPT-NEXT: // No instruction predicates
+// 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: // (select:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2, complex:{ *:[i32] }:$src3) => (INSN2:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src3, complex:{ *:[i32] }:$src2)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN2,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/1,
+// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0,
+// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*MergeInsnID's*/0, GIU_MergeMemOperands_EndOfList,
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// Closing the G_SELECT group.
+// OPT-NEXT: // Label 2: @[[LABEL]]
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
+// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
//===- Test a pattern with ComplexPattern operands. -----------------------===//
//
-// R20N: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 21 //
-// R20N: // Label [[PREV_NUM]]: @[[PREV]]
-//
-// R20C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 20 //
-//
-// R20N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
-// R20N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
-// R20N-NEXT: // MIs[0] dst
-// R20N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R20N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R20N-NEXT: // MIs[0] src1
-// R20C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-//
-// R20N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R20C-NEXT: // MIs[0] src2
-// R20C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// R20C-NEXT: GIM_CheckComplexPattern, /*MI*/0, /*Op*/2, /*Renderer*/0, GICP_gi_complex,
-// R20C-NEXT: // (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2) => (INSN1:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2)
-// R20C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN1,
-// R20C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R20C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// R20C-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0,
-// R20C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R20C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R20C-NEXT: // GIR_Coverage, 20,
-// R20C-NEXT: GIR_Done,
-// R20C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
+// OPT-NEXT: // No instruction predicates
+// 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: // (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2) => (INSN1:{ *:[i32] } GPR32:{ *:[i32] }:$src1, complex:{ *:[i32] }:$src2)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSN1,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_ComplexRenderer, /*InsnID*/0, /*RendererID*/0,
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def INSN1 : I<(outs GPR32:$dst), (ins GPR32:$src1, complex:$src2), []>;
def : Pat<(sub GPR32:$src1, complex:$src2), (INSN1 GPR32:$src1, complex:$src2)>;
+
//===- Test a pattern with multiple ComplexPattern operands. --------------===//
//
+
+
def : GINodeEquiv<G_SELECT, select>;
let mayLoad = 1 in {
def INSN2 : I<(outs GPR32:$dst), (ins GPR32Op:$src1, complex:$src2, complex:$src3), []>;
@@ -399,57 +374,59 @@ def : Pat<(select GPR32:$src1, complex:$
(INSN2 GPR32:$src1, complex:$src3, complex:$src2)>;
//===- Test a more complex multi-instruction match. -----------------------===//
-//
-// R00C: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 20 //
-// R00C: // Label [[PREV_NUM]]: @[[PREV]]
-//
-// R00C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 0 //
-// R00C-NEXT: GIM_CheckFeatures, GIFBS_HasA,
-// R00N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
-// R00N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
-// R00N-NEXT: // MIs[0] dst
-// R00N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R00N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R00C-NEXT: // MIs[0] Operand 1
-// R00C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// R00C-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
-// R00N-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
-// R00C-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_SUB,
-// R00N-NEXT: // MIs[1] Operand 0
-// R00N-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
-// R00N-NEXT: // MIs[1] src1
-// R00C-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
-// R00N-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R00N-NEXT: // MIs[1] src2
-// R00N-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
-// R00N-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// R00C-NEXT: // MIs[0] Operand 2
-// R00C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// R00C-NEXT: GIM_RecordInsn, /*DefineMI*/2, /*MI*/0, /*OpIdx*/2, // MIs[2]
-// R00N-NEXT: GIM_CheckNumOperands, /*MI*/2, /*Expected*/3,
-// R00C-NEXT: GIM_CheckOpcode, /*MI*/2, TargetOpcode::G_SUB,
-// R00N-NEXT: // MIs[2] Operand 0
-// R00N-NEXT: GIM_CheckType, /*MI*/2, /*Op*/0, /*Type*/GILLT_s32,
-// R00N-NEXT: // MIs[2] src3
-// R00C-NEXT: GIM_CheckType, /*MI*/2, /*Op*/1, /*Type*/GILLT_s32,
-// R00N-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R00N-NEXT: // MIs[2] src4
-// R00N-NEXT: GIM_CheckType, /*MI*/2, /*Op*/2, /*Type*/GILLT_s32,
-// R00N-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// R00C-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
-// R00C-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/2,
-// R00C-NEXT: // (sub:{ *:[i32] } (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2), (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)) => (INSNBOB:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)
-// R00C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSNBOB,
-// R00C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R00C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
-// R00C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
-// R00C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/1, // src3
-// R00C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/2, // src4
-// R00C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R00C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R00C-NEXT: // GIR_Coverage, 0,
-// R00C-NEXT: GIR_Done,
-// R00C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[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: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
+// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/2, /*MI*/0, /*OpIdx*/2, // MIs[2]
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/2, /*Expected*/3,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SUB,
+// OPT-NEXT: // No instruction predicates
+// 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_SUB,
+// 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] Operand 2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/2, TargetOpcode::G_SUB,
+// CHECK-NEXT: // MIs[2] Operand 0
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/0, /*Type*/GILLT_s32,
+// CHECK-NEXT: // MIs[2] src3
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/1, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // MIs[2] src4
+// CHECK-NEXT: GIM_CheckType, /*MI*/2, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/2, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
+// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/2,
+// CHECK-NEXT: // (sub:{ *:[i32] } (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2), (sub:{ *:[i32] } GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)) => (INSNBOB:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src3, GPR32:{ *:[i32] }:$src4)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::INSNBOB,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/1, // src3
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/2, /*OpIdx*/2, // src4
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_SUB group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def INSNBOB : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3, GPR32:$src4),
[(set GPR32:$dst,
@@ -458,63 +435,68 @@ def INSNBOB : I<(outs GPR32:$dst), (ins
//===- Test a simple pattern with an intrinsic. ---------------------------===//
//
-// R01N: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 0 //
-// R01N: // Label [[PREV_NUM]]: @[[PREV]]
-//
-// R01C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 1 //
-// R01C-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
-//
-// R01N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC,
-// R01N-NEXT: // MIs[0] dst
-// R01N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R01N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R01N-NEXT: // MIs[0] Operand 1
-// R01N-NEXT: GIM_CheckIntrinsicID, /*MI*/0, /*Op*/1, Intrinsic::mytarget_nop,
-// R01N-NEXT: // MIs[0] src1
-// R01N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-//
-// R01C-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// R01C-NEXT: // (intrinsic_wo_chain:{ *:[i32] } [[ID:[0-9]+]]:{ *:[iPTR] }, GPR32:{ *:[i32] }:$src1) => (MOV:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// R01C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV,
-// R01C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R01C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src1
-// R01C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R01C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R01C-NEXT: // GIR_Coverage, 1,
-// R01C-NEXT: GIR_Done,
-// R01C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_INTRINSIC,
+// OPT-NEXT: // No instruction predicates
+// 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_CheckIntrinsicID, /*MI*/0, /*Op*/1, Intrinsic::mytarget_nop,
+// CHECK-NEXT: // MIs[0] src1
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // (intrinsic_wo_chain:{ *:[i32] } [[ID:[0-9]+]]:{ *:[iPTR] }, GPR32:{ *:[i32] }:$src1) => (MOV:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_INTRINSIC group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def MOV : I<(outs GPR32:$dst), (ins GPR32:$src1),
[(set GPR32:$dst, (int_mytarget_nop GPR32:$src1))]>;
+
//===- Test a simple pattern with a default operand. ----------------------===//
//
-// R02N: GIM_Try, /*On fail goto*//*Label [[PREV_NUM:[0-9]+]]*/ [[PREV:[0-9]+]], // Rule ID 1 //
-// R02N: // Label [[PREV_NUM]]: @[[PREV]]
-//
-// R02C-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]], // Rule ID 2 //
-//
-// R02N-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
-// R02N-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
-// R02N-NEXT: // MIs[0] dst
-// R02N-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// R02N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// R02N-NEXT: // MIs[0] src1
-// R02C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// R02N-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// R02C-NEXT: // MIs[0] Operand 2
-// R02C-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// R02C-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -2
-// R02C-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -2:{ *:[i32] }) => (XORI:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// R02C-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORI,
-// R02C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// R02C-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
-// R02C-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// R02C-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// R02C-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// R02C-NEXT: // GIR_Coverage, 2,
-// R02C-NEXT: GIR_Done,
-// R02C-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
+// OPT-NEXT: // No instruction predicates
+// 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_CheckConstantInt, /*MI*/0, /*Op*/2, -2
+// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -2:{ *:[i32] }) => (XORI:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORI,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// The -2 is just to distinguish it from the 'not' case below.
def XORI : I<(outs GPR32:$dst), (ins m1:$src2, GPR32:$src1),
@@ -522,28 +504,30 @@ def XORI : I<(outs GPR32:$dst), (ins m1:
//===- Test a simple pattern with a default register operand. -------------===//
//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -3
-// NOOPT-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -3:{ *:[i32] }) => (XOR:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XOR,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 3,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckConstantInt, /*MI*/0, /*Op*/2, -3
+// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -3:{ *:[i32] }) => (XOR:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XOR,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// 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),
@@ -551,29 +535,31 @@ def XOR : I<(outs GPR32:$dst), (ins Z:$s
//===- Test a simple pattern with a multiple default operands. ------------===//
//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -4
-// NOOPT-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -4:{ *:[i32] }) => (XORlike:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORlike,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
-// NOOPT-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 4,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckConstantInt, /*MI*/0, /*Op*/2, -4
+// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -4:{ *:[i32] }) => (XORlike:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORlike,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// The -4 is just to distinguish it from the other 'not' cases.
def XORlike : I<(outs GPR32:$dst), (ins m1Z:$src2, GPR32:$src1),
@@ -581,30 +567,32 @@ def XORlike : I<(outs GPR32:$dst), (ins
//===- Test a simple pattern with multiple operands with defaults. --------===//
//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -5,
-// NOOPT-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -5:{ *:[i32] }) => (XORManyDefaults:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORManyDefaults,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
-// NOOPT-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
-// NOOPT-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 5,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckConstantInt, /*MI*/0, /*Op*/2, -5,
+// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$src1, -5:{ *:[i32] }) => (XORManyDefaults:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::XORManyDefaults,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/-1,
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// The -5 is just to distinguish it from the other cases.
def XORManyDefaults : I<(outs GPR32:$dst), (ins m1Z:$src3, Z:$src2, GPR32:$src1),
@@ -614,108 +602,121 @@ def XORManyDefaults : I<(outs GPR32:$dst
//
// This must precede the 3-register variants because constant immediates have
// priority over register banks.
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_XOR,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Wm
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
-// NOOPT-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$Wm, -1:{ *:[i32] }) => (ORN:{ *:[i32] } R0:{ *:[i32] }, GPR32:{ *:[i32] }:$Wm)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ORN,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // Wm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 22,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
+// CHECK-NEXT: // (xor:{ *:[i32] } GPR32:{ *:[i32] }:$Wm, -1:{ *:[i32] }) => (ORN:{ *:[i32] } R0:{ *:[i32] }, GPR32:{ *:[i32] }:$Wm)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::ORN,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/0, MyTarget::R0,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // Wm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_XOR group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def ORN : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2), []>;
def : Pat<(not GPR32:$Wm), (ORN R0, GPR32:$Wm)>;
+
//===- Test a nested instruction match. -----------------------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckFeatures, GIFBS_HasA,
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[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: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
-// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD,
-// NOOPT-NEXT: // MIs[1] Operand 0
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: // MIs[1] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[1] src2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src3
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
-// NOOPT-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)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src3
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 6,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckIsSafeToFold, /*InsnID*/1,
+// 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: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src3
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
// We also get a second rule by commutativity.
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckFeatures, GIFBS_HasA,
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[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: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src3
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/2,
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/1, /*Expected*/3,
-// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ADD,
-// NOOPT-NEXT: // MIs[1] Operand 0
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: // MIs[1] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[1] src2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
-// NOOPT-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)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src3
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 25,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckIsSafeToFold, /*InsnID*/1,
+// 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: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MULADD,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/2, // src2
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src3
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_MUL group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def MULADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2, GPR32:$src3),
[(set GPR32:$dst,
@@ -723,329 +724,400 @@ def MULADD : I<(outs GPR32:$dst), (ins G
Requires<[HasA]>;
//===- Test a simple pattern with just a specific leaf immediate. ---------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: GIM_CheckLiteralInt, /*MI*/0, /*Op*/1, 1,
-// NOOPT-NEXT: // 1:{ *:[i32] } => (MOV1:{ *:[i32] })
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV1,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 7,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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_CheckLiteralInt, /*MI*/0, /*Op*/1, 1,
+// CHECK-NEXT: // 1:{ *:[i32] } => (MOV1:{ *:[i32] })
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOV1,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def MOV1 : I<(outs GPR32:$dst), (ins), [(set GPR32:$dst, 1)]>;
//===- Test a simple pattern with a leaf immediate and a predicate. -------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
-// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: // No operand predicates
-// NOOPT-NEXT: // (imm:{ *:[i32] })<<P:Predicate_simm8>>:$imm => (MOVimm8:{ *:[i32] } (imm:{ *:[i32] }):$imm)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm8,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 8,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_simm8,
+// 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: // No operand predicates
+// CHECK-NEXT: // (imm:{ *:[i32] })<<P:Predicate_simm8>>:$imm => (MOVimm8:{ *:[i32] } (imm:{ *:[i32] }):$imm)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm8,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def simm8 : ImmLeaf<i32, [{ return isInt<8>(Imm); }]>;
def MOVimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm8:$imm)]>;
//===- Same again but use an IntImmLeaf. ----------------------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
-// NOOPT-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: // No operand predicates
-// NOOPT-NEXT: // (imm:{ *:[i32] })<<P:Predicate_simm9>>:$imm => (MOVimm9:{ *:[i32] } (imm:{ *:[i32] }):$imm)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm9,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 9,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// CHECK-NEXT: GIM_CheckAPIntImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APInt_Predicate_simm9,
+// 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: // No operand predicates
+// CHECK-NEXT: // (imm:{ *:[i32] })<<P:Predicate_simm9>>:$imm => (MOVimm9:{ *:[i32] } (imm:{ *:[i32] }):$imm)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm9,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def simm9 : IntImmLeaf<i32, [{ return isInt<9>(Imm->getSExtValue()); }]>;
def MOVimm9 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, simm9:$imm)]>;
//===- Test a pattern with a custom renderer. -----------------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
-// NOOPT-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_cimm8,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: // No operand predicates
-// NOOPT-NEXT: // (imm:{ *:[i32] })<<P:Predicate_cimm8>><<X:cimm8_xform>>:$imm => (MOVcimm8:{ *:[i32] } (cimm8_xform:{ *:[i32] } (imm:{ *:[i32] }):$imm))
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVcimm8,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_CustomRenderer, /*InsnID*/0, /*OldInsnID*/0, /*Renderer*/GICR_renderImm8, // imm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 10,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
-
+// CHECK-NEXT: GIM_CheckI64ImmPredicate, /*MI*/0, /*Predicate*/GIPFP_I64_Predicate_cimm8,
+// 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: // No operand predicates
+// CHECK-NEXT: // (imm:{ *:[i32] })<<P:Predicate_cimm8>><<X:cimm8_xform>>:$imm => (MOVcimm8:{ *:[i32] } (cimm8_xform:{ *:[i32] } (imm:{ *:[i32] }):$imm))
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVcimm8,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CustomRenderer, /*InsnID*/0, /*OldInsnID*/0, /*Renderer*/GICR_renderImm8, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_CONSTANT group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def MOVcimm8 : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, cimm8:$imm)]>;
//===- Test a simple pattern with a FP immediate and a predicate. ---------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_FCONSTANT,
-// NOOPT-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::FPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: // No operand predicates
-// NOOPT-NEXT: // (fpimm:{ *:[f32] })<<P:Predicate_fpimmz>>:$imm => (MOVfpimmz:{ *:[f32] } (fpimm:{ *:[f32] }):$imm)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVfpimmz,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_CopyFConstantAsFPImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 17,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// CHECK-NEXT: GIM_CheckAPFloatImmPredicate, /*MI*/0, /*Predicate*/GIPFP_APFloat_Predicate_fpimmz,
+// 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::FPR32RegClassID,
+// CHECK-NEXT: // MIs[0] Operand 1
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // (fpimm:{ *:[f32] })<<P:Predicate_fpimmz>>:$imm => (MOVfpimmz:{ *:[f32] } (fpimm:{ *:[f32] }):$imm)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVfpimmz,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CopyFConstantAsFPImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_FCONSTANT group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
//===- Test a simple pattern with inferred pointer operands. ---------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
-// NOOPT-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
-// NOOPT-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // (ld:{ *:[i32] } GPR32:{ *:[i32] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 11,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
+// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
+// 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_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // (ld:{ *:[i32] } GPR32:{ *:[i32] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_LOAD group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def LOAD : I<(outs GPR32:$dst), (ins GPR32:$src1),
[(set GPR32:$dst, (load GPR32:$src1))]>;
//===- Test a simple pattern with a sextload -------------------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXTLOAD,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXTLOAD,
-// NOOPT-NEXT: GIM_CheckMemorySizeEqualTo, /*MI*/0, /*MMO*/0, /*Size*/2,
-// NOOPT-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // (ld:{ *:[i32] } GPR32:{ *:[i32] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_sextload>><<P:Predicate_sextloadi16>> => (SEXTLOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::SEXTLOAD,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 12,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// CHECK-NEXT: GIM_CheckMemorySizeEqualTo, /*MI*/0, /*MMO*/0, /*Size*/2,
+// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
+// 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_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
+// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
+// CHECK-NEXT: // (ld:{ *:[i32] } GPR32:{ *:[i32] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_sextload>><<P:Predicate_sextloadi16>> => (SEXTLOAD:{ *:[i32] } GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::SEXTLOAD,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_SEXT group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def SEXTLOAD : I<(outs GPR32:$dst), (ins GPR32:$src1),
[(set GPR32:$dst, (sextloadi16 GPR32:$src1))]>;
+
//===- Test a simple pattern with regclass operands. ----------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID
-// NOOPT-NEXT: // MIs[0] src2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2)
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 13,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+
def ADD : I<(outs GPR32:$dst), (ins GPR32:$src1, GPR32:$src2),
[(set GPR32:$dst, (add GPR32:$src1, GPR32:$src2))]>;
//===- Test a pattern with a tied operand in the matcher ------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src{{$}}
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src{{$}}
-// NOOPT-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1,
-// NOOPT-NEXT: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src, GPR32:{ *:[i32] }:$src) => (DOUBLE:{ *:[i32] } GPR32:{ *:[i32] }:$src)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::DOUBLE,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 14,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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] src{{$}}
+// 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] src{{$}}
+// CHECK-NEXT: GIM_CheckIsSameOperand, /*MI*/0, /*OpIdx*/2, /*OtherMI*/0, /*OtherOpIdx*/1,
+// CHECK-NEXT: // (add:{ *:[i32] } GPR32:{ *:[i32] }:$src, GPR32:{ *:[i32] }:$src) => (DOUBLE:{ *:[i32] } GPR32:{ *:[i32] }:$src)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::DOUBLE,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
def DOUBLE : I<(outs GPR32:$dst), (ins GPR32:$src), [(set GPR32:$dst, (add GPR32:$src, GPR32:$src))]>;
//===- Test a simple pattern with ValueType operands. ----------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_ADD,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: // MIs[0] src2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2)
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 23,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // MIs[0] src2
+// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
+// CHECK-NEXT: // (add:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2) => (ADD:{ *:[i32] } i32:{ *:[i32] }:$src1, i32:{ *:[i32] }:$src2)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::ADD,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_ADD group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
def : Pat<(add i32:$src1, i32:$src2),
(ADD i32:$src1, i32:$src2)>;
+
+
//===- Test another simple pattern with regclass operands. ----------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC,
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HasA_HasB_HasC,
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/3,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src2
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/2, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/2, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (MUL:{ *:[i32] } GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src1)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MUL,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src2
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 15,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // (mul:{ *:[i32] } GPR32:{ *:[i32] }:$src1, GPR32:{ *:[i32] }:$src2) => (MUL:{ *:[i32] } GPR32:{ *:[i32] }:$src2, GPR32:{ *:[i32] }:$src1)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MUL,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/2, // src2
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src1
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_MUL group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def MUL : I<(outs GPR32:$dst), (ins GPR32:$src2, GPR32:$src1),
[(set GPR32:$dst, (mul GPR32:$src1, GPR32:$src2))]>,
Requires<[HasA, HasB, HasC]>;
+
+
//===- Test a COPY_TO_REGCLASS --------------------------------------------===//
//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BITCAST,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] src1
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/1, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::FPR32RegClassID,
-// NOOPT-NEXT: // (bitconvert:{ *:[i32] } FPR32:{ *:[f32] }:$src1) => (COPY_TO_REGCLASS:{ *:[i32] } FPR32:{ *:[f32] }:$src1, GPR32:{ *:[i32] })
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/TargetOpcode::COPY,
-// NOOPT-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC GPR32*/1,
-// NOOPT-NEXT: // GIR_Coverage, 24,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // (bitconvert:{ *:[i32] } FPR32:{ *:[f32] }:$src1) => (COPY_TO_REGCLASS:{ *:[i32] } FPR32:{ *:[f32] }:$src1, GPR32:{ *:[i32] })
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// 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 [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_BITCAST group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
def : Pat<(i32 (bitconvert FPR32:$src1)),
(COPY_TO_REGCLASS FPR32:$src1, GPR32)>;
+
+
//===- Test a simple pattern with just a leaf immediate. ------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
+
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_CONSTANT,
-// NOOPT-NEXT: // MIs[0] dst
-// NOOPT-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
-// NOOPT-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPR32RegClassID,
-// NOOPT-NEXT: // MIs[0] Operand 1
-// NOOPT-NEXT: // No operand predicates
-// NOOPT-NEXT: // (imm:{ *:[i32] }):$imm => (MOVimm:{ *:[i32] } (imm:{ *:[i32] }):$imm)
-// NOOPT-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm,
-// NOOPT-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
-// NOOPT-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
-// NOOPT-NEXT: GIR_EraseFromParent, /*InsnID*/0,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 16,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // No operand predicates
+// CHECK-NEXT: // (imm:{ *:[i32] }):$imm => (MOVimm:{ *:[i32] } (imm:{ *:[i32] }):$imm)
+// CHECK-NEXT: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::MOVimm,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_CopyConstantAsSImm, /*NewInsnID*/0, /*OldInsnID*/0, // imm
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def MOVimm : I<(outs GPR32:$dst), (ins i32imm:$imm), [(set GPR32:$dst, imm:$imm)]>;
+
+
def fpimmz : FPImmLeaf<f32, [{ return Imm->isExactlyValue(0.0); }]>;
def MOVfpimmz : I<(outs FPR32:$dst), (ins f32imm:$imm), [(set FPR32:$dst, fpimmz:$imm)]>;
+
+
//===- Test a pattern with an MBB operand. --------------------------------===//
-//
-// NOOPT-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
-// NOOPT-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1,
+
+// OPT-NEXT: GIM_Try, /*On fail goto*//*Label [[GRP_LABEL_NUM:[0-9]+]]*/ [[GRP_LABEL:[0-9]+]],
+// OPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR,
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
+// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/1,
// NOOPT-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_BR,
-// NOOPT-NEXT: // MIs[0] target
-// NOOPT-NEXT: GIM_CheckIsMBB, /*MI*/0, /*Op*/0,
-// NOOPT-NEXT: // (br (bb:{ *:[Other] }):$target) => (BR (bb:{ *:[Other] }):$target)
-// NOOPT-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR,
-// NOOPT-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
-// NOOPT-NEXT: // GIR_Coverage, 18,
-// NOOPT-NEXT: GIR_Done,
-// NOOPT-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// OPT-NEXT: // No instruction predicates
+// 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: // Rule ID {{[0-9]+}}
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::BR,
+// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
+// Closing the G_BR group.
+// OPT-NEXT: GIM_Reject,
+// OPT-NEXT: GIR_Done,
+// OPT-NEXT: // Label [[GRP_LABEL_NUM]]: @[[GRP_LABEL]]
def BR : I<(outs), (ins unknown:$target),
[(br bb:$target)]>;
-// NOOPT-NEXT: GIM_Reject,
-// NOOPT-NEXT: };
-// NOOPT-NEXT: return MatchTable0;
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: };
+// CHECK-NEXT: return MatchTable0;
Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=332912&r1=332911&r2=332912&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Mon May 21 15:21:24 2018
@@ -100,7 +100,6 @@ private:
LLT Ty;
public:
- LLTCodeGen() = default;
LLTCodeGen(const LLT &Ty) : Ty(Ty) {}
std::string getCxxEnumValue() const {
@@ -402,34 +401,13 @@ public:
/// A bitfield of RecordFlagsBits flags.
unsigned Flags;
- /// The actual run-time value, if known
- int64_t RawValue;
-
MatchTableRecord(Optional<unsigned> LabelID_, StringRef EmitStr,
- unsigned NumElements, unsigned Flags,
- int64_t RawValue = std::numeric_limits<int64_t>::min())
+ unsigned NumElements, unsigned Flags)
: LabelID(LabelID_.hasValue() ? LabelID_.getValue() : ~0u),
- EmitStr(EmitStr), NumElements(NumElements), Flags(Flags),
- RawValue(RawValue) {
-
+ EmitStr(EmitStr), NumElements(NumElements), Flags(Flags) {
assert((!LabelID_.hasValue() || LabelID != ~0u) &&
"This value is reserved for non-labels");
}
- MatchTableRecord(const MatchTableRecord &Other) = default;
- MatchTableRecord(MatchTableRecord &&Other) = default;
-
- /// Useful if a Match Table Record gets optimized out
- void turnIntoComment() {
- Flags |= MTRF_Comment;
- Flags &= ~MTRF_CommaFollows;
- NumElements = 0;
- }
-
- /// For Jump Table generation purposes
- bool operator<(const MatchTableRecord &Other) const {
- return RawValue < Other.RawValue;
- }
- int64_t getRawValue() const { return RawValue; }
void emit(raw_ostream &OS, bool LineBreakNextAfterThis,
const MatchTable &Table) const;
@@ -475,20 +453,11 @@ public:
return MatchTableRecord(None, NamedValue, 1,
MatchTableRecord::MTRF_CommaFollows);
}
- static MatchTableRecord NamedValue(StringRef NamedValue, int64_t RawValue) {
- return MatchTableRecord(None, NamedValue, 1,
- MatchTableRecord::MTRF_CommaFollows, RawValue);
- }
static MatchTableRecord NamedValue(StringRef Namespace,
StringRef NamedValue) {
return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1,
MatchTableRecord::MTRF_CommaFollows);
}
- static MatchTableRecord NamedValue(StringRef Namespace, StringRef NamedValue,
- int64_t RawValue) {
- return MatchTableRecord(None, (Namespace + "::" + NamedValue).str(), 1,
- MatchTableRecord::MTRF_CommaFollows, RawValue);
- }
static MatchTableRecord IntValue(int64_t IntValue) {
return MatchTableRecord(None, llvm::to_string(IntValue), 1,
MatchTableRecord::MTRF_CommaFollows);
@@ -617,12 +586,8 @@ class RuleMatcher;
class Matcher {
public:
virtual ~Matcher() = default;
- virtual void optimize() {}
virtual void emit(MatchTable &Table) = 0;
-
- virtual bool hasFirstCondition() const = 0;
- virtual const PredicateMatcher &getFirstCondition() const = 0;
- virtual std::unique_ptr<PredicateMatcher> popFirstCondition() = 0;
+ virtual std::unique_ptr<PredicateMatcher> forgetFirstCondition() = 0;
};
MatchTable MatchTable::buildTable(ArrayRef<Matcher *> Rules,
@@ -634,75 +599,34 @@ MatchTable MatchTable::buildTable(ArrayR
return Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
}
-class GroupMatcher final : public Matcher {
- /// Conditions that form a common prefix of all the matchers contained.
- SmallVector<std::unique_ptr<PredicateMatcher>, 1> Conditions;
-
- /// All the nested matchers, sharing a common prefix.
- std::vector<Matcher *> Matchers;
-
- /// An owning collection for any auxiliary matchers created while optimizing
- /// nested matchers contained.
- std::vector<std::unique_ptr<Matcher>> MatcherStorage;
-
-public:
- /// Add a matcher to the collection of nested matchers if it meets the
- /// requirements, and return true. If it doesn't, do nothing and return false.
- ///
- /// Expected to preserve its argument, so it could be moved out later on.
- bool addMatcher(Matcher &Candidate);
-
- /// Mark the matcher as fully-built and ensure any invariants expected by both
- /// optimize() and emit(...) methods. Generally, both sequences of calls
- /// are expected to lead to a sensible result:
- ///
- /// addMatcher(...)*; finalize(); optimize(); emit(...); and
- /// addMatcher(...)*; finalize(); emit(...);
- ///
- /// or generally
- ///
- /// addMatcher(...)*; finalize(); { optimize()*; emit(...); }*
- ///
- /// Multiple calls to optimize() are expected to be handled gracefully, though
- /// optimize() is not expected to be idempotent. Multiple calls to finalize()
- /// aren't generally supported. emit(...) is expected to be non-mutating and
- /// producing the exact same results upon repeated calls.
- ///
- /// addMatcher() calls after the finalize() call are not supported.
- ///
- /// finalize() and optimize() are both allowed to mutate the contained
- /// matchers, so moving them out after finalize() is not supported.
- void finalize();
- void optimize() override {}
+class GroupMatcher : public Matcher {
+ SmallVector<std::unique_ptr<PredicateMatcher>, 8> Conditions;
+ SmallVector<Matcher *, 8> Rules;
+
+public:
+ void addCondition(std::unique_ptr<PredicateMatcher> &&Predicate) {
+ Conditions.emplace_back(std::move(Predicate));
+ }
+ void addRule(Matcher &Rule) { Rules.push_back(&Rule); }
+ const std::unique_ptr<PredicateMatcher> &conditions_back() const {
+ return Conditions.back();
+ }
+ bool lastConditionMatches(const PredicateMatcher &Predicate) const;
+ bool conditions_empty() const { return Conditions.empty(); }
+ void clear() {
+ Conditions.clear();
+ Rules.clear();
+ }
void emit(MatchTable &Table) override;
- /// Could be used to move out the matchers added previously, unless finalize()
- /// has been already called. If any of the matchers are moved out, the group
- /// becomes safe to destroy, but not safe to re-use for anything else.
- iterator_range<std::vector<Matcher *>::iterator> matchers() {
- return make_range(Matchers.begin(), Matchers.end());
- }
- size_t size() const { return Matchers.size(); }
- bool empty() const { return Matchers.empty(); }
-
- std::unique_ptr<PredicateMatcher> popFirstCondition() override {
- assert(!Conditions.empty() &&
- "Trying to pop a condition from a condition-less group");
- std::unique_ptr<PredicateMatcher> P = std::move(Conditions.front());
- Conditions.erase(Conditions.begin());
- return P;
- }
- const PredicateMatcher &getFirstCondition() const override {
- assert(!Conditions.empty() &&
- "Trying to get a condition from a condition-less group");
- return *Conditions.front();
+ std::unique_ptr<PredicateMatcher> forgetFirstCondition() override {
+ // We shouldn't need to mess up with groups, since we
+ // should have merged everything shareable upfront.
+ // If we start to look into reordering predicates,
+ // we may want to reconsider this.
+ assert(0 && "Groups should be formed maximal for now");
+ llvm_unreachable("No need for this for now");
}
- bool hasFirstCondition() const override { return !Conditions.empty(); }
-
-private:
- /// See if a candidate matcher could be added to this group solely by
- /// analyzing its first condition.
- bool candidateConditionMatches(const PredicateMatcher &Predicate) const;
};
/// Generates code to check that a match rule matches.
@@ -716,19 +640,20 @@ protected:
/// FIXME: This currently supports a single match position but could be
/// extended to support multiple positions to support div/rem fusion or
/// load-multiple instructions.
- using MatchersTy = std::vector<std::unique_ptr<InstructionMatcher>> ;
- MatchersTy Matchers;
+ std::vector<std::unique_ptr<InstructionMatcher>> Matchers;
/// A list of actions that need to be taken when all predicates in this rule
/// have succeeded.
ActionList Actions;
- using DefinedInsnVariablesMap = std::map<InstructionMatcher *, unsigned>;
+ using DefinedInsnVariablesMap =
+ std::map<const InstructionMatcher *, unsigned>;
- /// A map of instruction matchers to the local variables
+ /// A map of instruction matchers to the local variables created by
+ /// emitCaptureOpcodes().
DefinedInsnVariablesMap InsnVariableIDs;
- using MutatableInsnSet = SmallPtrSet<InstructionMatcher *, 4>;
+ using MutatableInsnSet = SmallPtrSet<const InstructionMatcher *, 4>;
// The set of instruction matchers that have not yet been claimed for mutation
// by a BuildMI.
@@ -738,7 +663,7 @@ protected:
/// the renderers.
StringMap<OperandMatcher *> DefinedOperands;
- /// ID for the next instruction variable defined with implicitlyDefineInsnVar()
+ /// ID for the next instruction variable defined with defineInsnVar()
unsigned NextInsnVarID;
/// ID for the next output instruction allocated with allocateOutputInsnID()
@@ -748,7 +673,6 @@ protected:
unsigned NextTempRegID;
std::vector<Record *> RequiredFeatures;
- std::vector<std::unique_ptr<PredicateMatcher>> EpilogueMatchers;
ArrayRef<SMLoc> SrcLoc;
@@ -782,9 +706,16 @@ public:
action_iterator insertAction(action_iterator InsertPt, Args &&... args);
/// Define an instruction without emitting any code to do so.
- unsigned implicitlyDefineInsnVar(InstructionMatcher &Matcher);
-
- unsigned getInsnVarID(InstructionMatcher &InsnMatcher) const;
+ /// This is used for the root of the match.
+ unsigned implicitlyDefineInsnVar(const InstructionMatcher &Matcher);
+ void clearImplicitMap() {
+ NextInsnVarID = 0;
+ InsnVariableIDs.clear();
+ };
+ /// Define an instruction and emit corresponding state-machine opcodes.
+ unsigned defineInsnVar(MatchTable &Table, const InstructionMatcher &Matcher,
+ unsigned InsnVarID, unsigned OpIdx);
+ unsigned getInsnVarID(const InstructionMatcher &InsnMatcher) const;
DefinedInsnVariablesMap::const_iterator defined_insn_vars_begin() const {
return InsnVariableIDs.begin();
}
@@ -806,7 +737,7 @@ public:
mutatable_insns() const {
return make_range(mutatable_insns_begin(), mutatable_insns_end());
}
- void reserveInsnMatcherForMutation(InstructionMatcher *InsnMatcher) {
+ void reserveInsnMatcherForMutation(const InstructionMatcher *InsnMatcher) {
bool R = MutatableInsns.erase(InsnMatcher);
assert(R && "Reserving a mutatable insn that isn't available");
(void)R;
@@ -834,10 +765,11 @@ public:
return I->second;
}
- InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
+ const InstructionMatcher &getInstructionMatcher(StringRef SymbolicName) const;
const OperandMatcher &getOperandMatcher(StringRef Name) const;
- void optimize() override;
+ void emitCaptureOpcodes(MatchTable &Table);
+
void emit(MatchTable &Table) override;
/// Compare the priority of this object and B.
@@ -849,11 +781,7 @@ public:
/// matcher.
unsigned countRendererFns() const;
- std::unique_ptr<PredicateMatcher> popFirstCondition() override;
- const PredicateMatcher &getFirstCondition() const override;
- LLTCodeGen getFirstConditionAsRootType();
- bool hasFirstCondition() const override;
- unsigned getNumOperands() const;
+ std::unique_ptr<PredicateMatcher> forgetFirstCondition() override;
// FIXME: Remove this as soon as possible
InstructionMatcher &insnmatchers_front() const { return *Matchers.front(); }
@@ -861,9 +789,6 @@ public:
unsigned allocateOutputInsnID() { return NextOutputInsnID++; }
unsigned allocateTempRegID() { return NextTempRegID++; }
- iterator_range<MatchersTy::iterator> insnmatchers() {
- return make_range(Matchers.begin(), Matchers.end());
- }
bool insnmatchers_empty() const { return Matchers.empty(); }
void insnmatchers_pop_front() { Matchers.erase(Matchers.begin()); }
};
@@ -874,69 +799,58 @@ using action_iterator = RuleMatcher::act
template <class PredicateTy> class PredicateListMatcher {
private:
+ typedef std::vector<std::unique_ptr<PredicateTy>> PredicateVec;
+ PredicateVec Predicates;
+
/// Template instantiations should specialize this to return a string to use
/// for the comment emitted when there are no predicates.
std::string getNoPredicateComment() const;
-protected:
- using PredicatesTy = std::deque<std::unique_ptr<PredicateTy>>;
- PredicatesTy Predicates;
-
- /// Track if the list of predicates was manipulated by one of the optimization
- /// methods.
- bool Optimized = false;
-
public:
- /// Construct a new predicate and add it to the matcher.
+ /// Construct a new operand predicate and add it to the matcher.
template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args);
+ Optional<Kind *> addPredicate(Args&&... args) {
+ Predicates.emplace_back(
+ llvm::make_unique<Kind>(std::forward<Args>(args)...));
+ return static_cast<Kind *>(Predicates.back().get());
+ }
- typename PredicatesTy::iterator predicates_begin() {
+ typename PredicateVec::const_iterator predicates_begin() const {
return Predicates.begin();
}
- typename PredicatesTy::iterator predicates_end() {
+ typename PredicateVec::const_iterator predicates_end() const {
return Predicates.end();
}
- iterator_range<typename PredicatesTy::iterator> predicates() {
+ iterator_range<typename PredicateVec::const_iterator> predicates() const {
return make_range(predicates_begin(), predicates_end());
}
- typename PredicatesTy::size_type predicates_size() const {
+ typename PredicateVec::size_type predicates_size() const {
return Predicates.size();
}
bool predicates_empty() const { return Predicates.empty(); }
std::unique_ptr<PredicateTy> predicates_pop_front() {
std::unique_ptr<PredicateTy> Front = std::move(Predicates.front());
- Predicates.pop_front();
- Optimized = true;
+ Predicates.erase(Predicates.begin());
return Front;
}
- void prependPredicate(std::unique_ptr<PredicateTy> &&Predicate) {
- Predicates.push_front(std::move(Predicate));
- }
-
- void eraseNullPredicates() {
- const auto NewEnd =
- std::stable_partition(Predicates.begin(), Predicates.end(),
- std::logical_not<std::unique_ptr<PredicateTy>>());
- if (NewEnd != Predicates.begin()) {
- Predicates.erase(Predicates.begin(), NewEnd);
- Optimized = true;
- }
- }
-
/// Emit MatchTable opcodes that tests whether all the predicates are met.
template <class... Args>
- void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) {
- if (Predicates.empty() && !Optimized) {
+ void emitPredicateListOpcodes(MatchTable &Table, Args &&... args) const {
+ if (Predicates.empty()) {
Table << MatchTable::Comment(getNoPredicateComment())
<< MatchTable::LineBreak;
return;
}
- for (const auto &Predicate : predicates())
+ unsigned OpIdx = (*predicates_begin())->getOpIdx();
+ (void)OpIdx;
+ for (const auto &Predicate : predicates()) {
+ assert(Predicate->getOpIdx() == OpIdx &&
+ "Checks touch different operands?");
Predicate->emitPredicateOpcodes(Table, std::forward<Args>(args)...);
+ }
}
};
@@ -954,7 +868,6 @@ public:
/// are currently not compared between each other.
enum PredicateKind {
IPM_Opcode,
- IPM_NumOperands,
IPM_ImmPredicate,
IPM_AtomicOrderingMMO,
IPM_MemoryLLTSize,
@@ -980,9 +893,7 @@ public:
PredicateMatcher(PredicateKind Kind, unsigned InsnVarID, unsigned OpIdx = ~0)
: Kind(Kind), InsnVarID(InsnVarID), OpIdx(OpIdx) {}
- unsigned getInsnVarID() const { return InsnVarID; }
unsigned getOpIdx() const { return OpIdx; }
-
virtual ~PredicateMatcher() = default;
/// Emit MatchTable opcodes that check the predicate for the given operand.
virtual void emitPredicateOpcodes(MatchTable &Table,
@@ -991,23 +902,16 @@ public:
PredicateKind getKind() const { return Kind; }
virtual bool isIdentical(const PredicateMatcher &B) const {
+ if (InsnVarID != 0 || OpIdx != (unsigned)~0) {
+ // We currently don't hoist the record of instruction properly.
+ // Therefore we can only work on the orig instruction (InsnVarID
+ // == 0).
+ LLVM_DEBUG(dbgs() << "Non-zero instr ID not supported yet\n");
+ return false;
+ }
return B.getKind() == getKind() && InsnVarID == B.InsnVarID &&
OpIdx == B.OpIdx;
}
-
- virtual bool isIdenticalDownToValue(const PredicateMatcher &B) const {
- return hasValue() && PredicateMatcher::isIdentical(B);
- }
-
- virtual MatchTableRecord getValue() const {
- assert(hasValue() && "Can not get a value of a value-less predicate!");
- llvm_unreachable("Not implemented yet");
- }
- virtual bool hasValue() const { return false; }
-
- /// Report the maximum number of temporary operands needed by the predicate
- /// matcher.
- virtual unsigned countRendererFns() const { return 0; }
};
/// Generates code to check a predicate of an operand.
@@ -1023,10 +927,20 @@ public:
: PredicateMatcher(Kind, InsnVarID, OpIdx) {}
virtual ~OperandPredicateMatcher() {}
+ /// Emit MatchTable opcodes to capture instructions into the MIs table.
+ ///
+ /// Only InstructionOperandMatcher needs to do anything for this method the
+ /// rest just walk the tree.
+ virtual void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const {}
+
/// Compare the priority of this object and B.
///
/// Returns true if this object is more important than B.
virtual bool isHigherPriorityThan(const OperandPredicateMatcher &B) const;
+
+ /// Report the maximum number of temporary operands needed by the predicate
+ /// matcher.
+ virtual unsigned countRendererFns() const { return 0; }
};
template <>
@@ -1045,17 +959,12 @@ public:
: OperandPredicateMatcher(OPM_SameOperand, InsnVarID, OpIdx),
MatchingName(MatchingName) {}
- static bool classof(const PredicateMatcher *P) {
+ static bool classof(const OperandPredicateMatcher *P) {
return P->getKind() == OPM_SameOperand;
}
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override;
-
- bool isIdentical(const PredicateMatcher &B) const override {
- return OperandPredicateMatcher::isIdentical(B) &&
- MatchingName == cast<SameOperandMatcher>(&B)->MatchingName;
- }
};
/// Generates code to check that an operand is a particular LLT.
@@ -1064,16 +973,6 @@ protected:
LLTCodeGen Ty;
public:
- static std::map<LLTCodeGen, unsigned> TypeIDValues;
-
- static void initTypeIDValuesMap() {
- TypeIDValues.clear();
-
- unsigned ID = 0;
- for (const LLTCodeGen LLTy : KnownTypes)
- TypeIDValues[LLTy] = ID++;
- }
-
LLTOperandMatcher(unsigned InsnVarID, unsigned OpIdx, const LLTCodeGen &Ty)
: OperandPredicateMatcher(OPM_LLT, InsnVarID, OpIdx), Ty(Ty) {
KnownTypes.insert(Ty);
@@ -1086,31 +985,17 @@ public:
return OperandPredicateMatcher::isIdentical(B) &&
Ty == cast<LLTOperandMatcher>(&B)->Ty;
}
- MatchTableRecord getValue() const override {
- const auto VI = TypeIDValues.find(Ty);
- if (VI == TypeIDValues.end())
- return MatchTable::NamedValue(getTy().getCxxEnumValue());
- return MatchTable::NamedValue(getTy().getCxxEnumValue(), VI->second);
- }
- bool hasValue() const override {
- if (TypeIDValues.size() != KnownTypes.size())
- initTypeIDValuesMap();
- return TypeIDValues.count(Ty);
- }
-
- LLTCodeGen getTy() const { return Ty; }
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIM_CheckType") << MatchTable::Comment("MI")
<< MatchTable::IntValue(InsnVarID) << MatchTable::Comment("Op")
<< MatchTable::IntValue(OpIdx) << MatchTable::Comment("Type")
- << getValue() << MatchTable::LineBreak;
+ << MatchTable::NamedValue(Ty.getCxxEnumValue())
+ << MatchTable::LineBreak;
}
};
-std::map<LLTCodeGen, unsigned> LLTOperandMatcher::TypeIDValues;
-
/// Generates code to check that an operand is a pointer to any address space.
///
/// In SelectionDAG, the types did not describe pointers or address spaces. As a
@@ -1342,18 +1227,7 @@ public:
assert(SymbolicName.empty() && "Operand already has a symbolic name");
SymbolicName = Name;
}
-
- /// Construct a new operand predicate and add it to the matcher.
- template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args) {
- if (isSameAsAnotherOperand())
- return None;
- Predicates.emplace_back(llvm::make_unique<Kind>(
- getInsnVarID(), getOpIdx(), std::forward<Args>(args)...));
- return static_cast<Kind *>(Predicates.back().get());
- }
-
- unsigned getOpIdx() const { return OpIdx; }
+ unsigned getOperandIndex() const { return OpIdx; }
unsigned getInsnVarID() const;
std::string getOperandExpr(unsigned InsnVarID) const {
@@ -1366,19 +1240,23 @@ public:
Error addTypeCheckPredicate(const TypeSetByHwMode &VTy,
bool OperandIsAPointer);
+ /// Emit MatchTable opcodes to capture instructions into the MIs table.
+ void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const {
+ for (const auto &Predicate : predicates())
+ Predicate->emitCaptureOpcodes(Table, Rule);
+ }
+
/// Emit MatchTable opcodes that test whether the instruction named in
/// InsnVarID matches all the predicates and all the operands.
- void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) {
- if (!Optimized) {
- std::string Comment;
- raw_string_ostream CommentOS(Comment);
- CommentOS << "MIs[" << getInsnVarID() << "] ";
- if (SymbolicName.empty())
- CommentOS << "Operand " << OpIdx;
- else
- CommentOS << SymbolicName;
- Table << MatchTable::Comment(CommentOS.str()) << MatchTable::LineBreak;
- }
+ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const {
+ std::string Comment;
+ raw_string_ostream CommentOS(Comment);
+ CommentOS << "MIs[" << getInsnVarID() << "] ";
+ if (SymbolicName.empty())
+ CommentOS << "Operand " << OpIdx;
+ else
+ CommentOS << SymbolicName;
+ Table << MatchTable::Comment(CommentOS.str()) << MatchTable::LineBreak;
emitPredicateListOpcodes(Table, Rule);
}
@@ -1386,7 +1264,7 @@ public:
/// Compare the priority of this object and B.
///
/// Returns true if this object is more important than B.
- bool isHigherPriorityThan(OperandMatcher &B) {
+ bool isHigherPriorityThan(const OperandMatcher &B) const {
// Operand matchers involving more predicates have higher priority.
if (predicates_size() > B.predicates_size())
return true;
@@ -1394,7 +1272,7 @@ public:
return false;
// This assumes that predicates are added in a consistent order.
- for (auto &&Predicate : zip(predicates(), B.predicates())) {
+ for (const auto &Predicate : zip(predicates(), B.predicates())) {
if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
return true;
if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
@@ -1406,7 +1284,7 @@ public:
/// Report the maximum number of temporary operands needed by the operand
/// matcher.
- unsigned countRendererFns() {
+ unsigned countRendererFns() const {
return std::accumulate(
predicates().begin(), predicates().end(), 0,
[](unsigned A,
@@ -1419,7 +1297,7 @@ public:
return AllocatedTemporariesBaseID;
}
- bool isSameAsAnotherOperand() {
+ bool isSameAsAnotherOperand() const {
for (const auto &Predicate : predicates())
if (isa<SameOperandMatcher>(Predicate))
return true;
@@ -1427,6 +1305,21 @@ public:
}
};
+// Specialize OperandMatcher::addPredicate() to refrain from adding redundant
+// predicates.
+template <>
+template <class Kind, class... Args>
+Optional<Kind *>
+PredicateListMatcher<OperandPredicateMatcher>::addPredicate(Args &&... args) {
+ auto *OpMatcher = static_cast<OperandMatcher *>(this);
+ if (static_cast<OperandMatcher *>(this)->isSameAsAnotherOperand())
+ return None;
+ Predicates.emplace_back(llvm::make_unique<Kind>(OpMatcher->getInsnVarID(),
+ OpMatcher->getOperandIndex(),
+ std::forward<Args>(args)...));
+ return static_cast<Kind *>(Predicates.back().get());
+}
+
Error OperandMatcher::addTypeCheckPredicate(const TypeSetByHwMode &VTy,
bool OperandIsAPointer) {
if (!VTy.isMachineValueType())
@@ -1470,11 +1363,15 @@ public:
isHigherPriorityThan(const InstructionPredicateMatcher &B) const {
return Kind < B.Kind;
};
+
+ /// Report the maximum number of temporary operands needed by the predicate
+ /// matcher.
+ virtual unsigned countRendererFns() const { return 0; }
};
template <>
std::string
-PredicateListMatcher<PredicateMatcher>::getNoPredicateComment() const {
+PredicateListMatcher<InstructionPredicateMatcher>::getNoPredicateComment() const {
return "No instruction predicates";
}
@@ -1483,17 +1380,7 @@ class InstructionOpcodeMatcher : public
protected:
const CodeGenInstruction *I;
- static DenseMap<const CodeGenInstruction *, unsigned> OpcodeValues;
-
public:
- static void initOpcodeValuesMap(const CodeGenTarget &Target) {
- OpcodeValues.clear();
-
- unsigned OpcodeValue = 0;
- for (const CodeGenInstruction *I : Target.getInstructionsByEnumValue())
- OpcodeValues[I] = OpcodeValue++;
- }
-
InstructionOpcodeMatcher(unsigned InsnVarID, const CodeGenInstruction *I)
: InstructionPredicateMatcher(IPM_Opcode, InsnVarID), I(I) {}
@@ -1505,19 +1392,12 @@ public:
return InstructionPredicateMatcher::isIdentical(B) &&
I == cast<InstructionOpcodeMatcher>(&B)->I;
}
- MatchTableRecord getValue() const override {
- const auto VI = OpcodeValues.find(I);
- if (VI != OpcodeValues.end())
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName(),
- VI->second);
- return MatchTable::NamedValue(I->Namespace, I->TheDef->getName());
- }
- bool hasValue() const override { return OpcodeValues.count(I); }
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIM_CheckOpcode") << MatchTable::Comment("MI")
- << MatchTable::IntValue(InsnVarID) << getValue()
+ << MatchTable::IntValue(InsnVarID)
+ << MatchTable::NamedValue(I->Namespace, I->TheDef->getName())
<< MatchTable::LineBreak;
}
@@ -1544,17 +1424,8 @@ public:
bool isConstantInstruction() const {
return I->TheDef->getName() == "G_CONSTANT";
}
-
- unsigned getNumOperands() const { return I->Operands.size(); }
-
- StringRef getOperandType(unsigned OpIdx) const {
- return I->Operands[OpIdx].OperandType;
- }
};
-DenseMap<const CodeGenInstruction *, unsigned>
- InstructionOpcodeMatcher::OpcodeValues;
-
/// Generates code to check that this instruction is a constant whose value
/// meets an immediate predicate.
///
@@ -1632,17 +1503,10 @@ public:
: InstructionPredicateMatcher(IPM_AtomicOrderingMMO, InsnVarID),
Order(Order), Comparator(Comparator) {}
- static bool classof(const PredicateMatcher *P) {
+ static bool classof(const InstructionPredicateMatcher *P) {
return P->getKind() == IPM_AtomicOrderingMMO;
}
- bool isIdentical(const PredicateMatcher &B) const override {
- if (!InstructionPredicateMatcher::isIdentical(B))
- return false;
- const auto &R = *cast<AtomicOrderingMMOPredicateMatcher>(&B);
- return Order == R.Order && Comparator == R.Comparator;
- }
-
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
StringRef Opcode = "GIM_CheckAtomicOrdering";
@@ -1741,7 +1605,8 @@ public:
/// Typical predicates include:
/// * Has a specific opcode.
/// * Has an nsw/nuw flag or doesn't.
-class InstructionMatcher final : public PredicateListMatcher<PredicateMatcher> {
+class InstructionMatcher
+ : public PredicateListMatcher<InstructionPredicateMatcher> {
protected:
typedef std::vector<std::unique_ptr<OperandMatcher>> OperandVec;
@@ -1762,17 +1627,9 @@ public:
InsnVarID = Rule.implicitlyDefineInsnVar(*this);
}
- /// Construct a new instruction predicate and add it to the matcher.
- template <class Kind, class... Args>
- Optional<Kind *> addPredicate(Args &&... args) {
- Predicates.emplace_back(
- llvm::make_unique<Kind>(getInsnVarID(), std::forward<Args>(args)...));
- return static_cast<Kind *>(Predicates.back().get());
- }
-
RuleMatcher &getRuleMatcher() const { return Rule; }
- unsigned getInsnVarID() const { return InsnVarID; }
+ unsigned getVarID() const { return InsnVarID; }
/// Add an operand to the matcher.
OperandMatcher &addOperand(unsigned OpIdx, const std::string &SymbolicName,
@@ -1788,7 +1645,7 @@ public:
OperandMatcher &getOperand(unsigned OpIdx) {
auto I = std::find_if(Operands.begin(), Operands.end(),
[&OpIdx](const std::unique_ptr<OperandMatcher> &X) {
- return X->getOpIdx() == OpIdx;
+ return X->getOperandIndex() == OpIdx;
});
if (I != Operands.end())
return **I;
@@ -1811,18 +1668,21 @@ public:
void pop_front() { Operands.erase(Operands.begin()); }
- void optimize() {}
-
- /// Emit MatchTable opcodes that test whether the instruction named in
- /// InsnVarName matches all the predicates and all the operands.
- void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) {
+ /// Emit MatchTable opcodes to check the shape of the match and capture
+ /// instructions into the MIs table.
+ void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) {
Table << MatchTable::Opcode("GIM_CheckNumOperands")
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
<< MatchTable::Comment("Expected")
<< MatchTable::IntValue(getNumOperands()) << MatchTable::LineBreak;
+ for (const auto &Operand : Operands)
+ Operand->emitCaptureOpcodes(Table, Rule);
+ }
+ /// Emit MatchTable opcodes that test whether the instruction named in
+ /// InsnVarName matches all the predicates and all the operands.
+ void emitPredicateOpcodes(MatchTable &Table, RuleMatcher &Rule) const {
emitPredicateListOpcodes(Table, Rule);
-
for (const auto &Operand : Operands)
Operand->emitPredicateOpcodes(Table, Rule);
}
@@ -1830,19 +1690,17 @@ public:
/// Compare the priority of this object and B.
///
/// Returns true if this object is more important than B.
- bool isHigherPriorityThan(InstructionMatcher &B) {
+ bool isHigherPriorityThan(const InstructionMatcher &B) const {
// Instruction matchers involving more operands have higher priority.
if (Operands.size() > B.Operands.size())
return true;
if (Operands.size() < B.Operands.size())
return false;
- for (auto &&P : zip(predicates(), B.predicates())) {
- auto L = static_cast<InstructionPredicateMatcher *>(std::get<0>(P).get());
- auto R = static_cast<InstructionPredicateMatcher *>(std::get<1>(P).get());
- if (L->isHigherPriorityThan(*R))
+ for (const auto &Predicate : zip(predicates(), B.predicates())) {
+ if (std::get<0>(Predicate)->isHigherPriorityThan(*std::get<1>(Predicate)))
return true;
- if (R->isHigherPriorityThan(*L))
+ if (std::get<1>(Predicate)->isHigherPriorityThan(*std::get<0>(Predicate)))
return false;
}
@@ -1858,13 +1716,13 @@ public:
/// Report the maximum number of temporary operands needed by the instruction
/// matcher.
- unsigned countRendererFns() {
- return std::accumulate(
- predicates().begin(), predicates().end(), 0,
- [](unsigned A,
- const std::unique_ptr<PredicateMatcher> &Predicate) {
- return A + Predicate->countRendererFns();
- }) +
+ unsigned countRendererFns() const {
+ return std::accumulate(predicates().begin(), predicates().end(), 0,
+ [](unsigned A,
+ const std::unique_ptr<InstructionPredicateMatcher>
+ &Predicate) {
+ return A + Predicate->countRendererFns();
+ }) +
std::accumulate(
Operands.begin(), Operands.end(), 0,
[](unsigned A, const std::unique_ptr<OperandMatcher> &Operand) {
@@ -1872,30 +1730,24 @@ public:
});
}
- InstructionOpcodeMatcher &getOpcodeMatcher() {
- for (auto &P : predicates())
- if (auto *OpMatcher = dyn_cast<InstructionOpcodeMatcher>(P.get()))
- return *OpMatcher;
- llvm_unreachable("Didn't find an opcode matcher");
- }
-
- bool isConstantInstruction() {
- return getOpcodeMatcher().isConstantInstruction();
+ bool isConstantInstruction() const {
+ for (const auto &P : predicates())
+ if (const InstructionOpcodeMatcher *Opcode =
+ dyn_cast<InstructionOpcodeMatcher>(P.get()))
+ return Opcode->isConstantInstruction();
+ return false;
}
};
-unsigned RuleMatcher::getNumOperands() const {
- return Matchers.front()->getNumOperands();
-}
-
-LLTCodeGen RuleMatcher::getFirstConditionAsRootType() {
- InstructionMatcher &InsnMatcher = *Matchers.front();
- if (!InsnMatcher.predicates_empty())
- if (const auto *TM =
- dyn_cast<LLTOperandMatcher>(&**InsnMatcher.predicates_begin()))
- if (TM->getInsnVarID() == 0 && TM->getOpIdx() == 0)
- return TM->getTy();
- return {};
+template <>
+template <class Kind, class... Args>
+Optional<Kind *>
+PredicateListMatcher<InstructionPredicateMatcher>::addPredicate(
+ Args &&... args) {
+ InstructionMatcher *InstMatcher = static_cast<InstructionMatcher *>(this);
+ Predicates.emplace_back(llvm::make_unique<Kind>(InstMatcher->getVarID(),
+ std::forward<Args>(args)...));
+ return static_cast<Kind *>(Predicates.back().get());
}
/// Generates code to check that the operand is a register defined by an
@@ -1923,20 +1775,17 @@ public:
InstructionMatcher &getInsnMatcher() const { return *InsnMatcher; }
- void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const {
- const unsigned NewInsnVarID = InsnMatcher->getInsnVarID();
- Table << MatchTable::Opcode("GIM_RecordInsn")
- << MatchTable::Comment("DefineMI")
- << MatchTable::IntValue(NewInsnVarID) << MatchTable::Comment("MI")
- << MatchTable::IntValue(getInsnVarID())
- << MatchTable::Comment("OpIdx") << MatchTable::IntValue(getOpIdx())
- << MatchTable::Comment("MIs[" + llvm::to_string(NewInsnVarID) + "]")
- << MatchTable::LineBreak;
+ void emitCaptureOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
+ unsigned InsnID =
+ Rule.defineInsnVar(Table, *InsnMatcher, InsnVarID, getOpIdx());
+ (void)InsnID;
+ assert(InsnMatcher->getVarID() == InsnID &&
+ "Mismatch between build and emit");
+ InsnMatcher->emitCaptureOpcodes(Table, Rule);
}
void emitPredicateOpcodes(MatchTable &Table,
RuleMatcher &Rule) const override {
- emitCaptureOpcodes(Table, Rule);
InsnMatcher->emitPredicateOpcodes(Table, Rule);
}
@@ -2010,7 +1859,7 @@ public:
Table << MatchTable::Opcode("GIR_Copy") << MatchTable::Comment("NewInsnID")
<< MatchTable::IntValue(NewInsnID) << MatchTable::Comment("OldInsnID")
<< MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::IntValue(Operand.getOperandIndex())
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
}
};
@@ -2046,7 +1895,7 @@ public:
<< MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
<< MatchTable::Comment("OldInsnID")
<< MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::IntValue(Operand.getOperandIndex())
<< MatchTable::NamedValue(
(ZeroRegisterDef->getValue("Namespace")
? ZeroRegisterDef->getValueAsString("Namespace")
@@ -2077,7 +1926,7 @@ public:
const StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ const InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode(Signed ? "GIR_CopyConstantAsSImm"
: "GIR_CopyConstantAsUImm")
@@ -2108,7 +1957,7 @@ public:
const StringRef getSymbolicName() const { return SymbolicName; }
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ const InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode("GIR_CopyFConstantAsFPImm")
<< MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
@@ -2148,7 +1997,7 @@ public:
<< MatchTable::Comment("NewInsnID") << MatchTable::IntValue(NewInsnID)
<< MatchTable::Comment("OldInsnID")
<< MatchTable::IntValue(OldInsnVarID) << MatchTable::Comment("OpIdx")
- << MatchTable::IntValue(Operand.getOpIdx())
+ << MatchTable::IntValue(Operand.getOperandIndex())
<< MatchTable::Comment("SubRegIdx")
<< MatchTable::IntValue(SubReg->EnumValue)
<< MatchTable::Comment(SymbolicName) << MatchTable::LineBreak;
@@ -2297,7 +2146,8 @@ public:
}
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
- InstructionMatcher &InsnMatcher = Rule.getInstructionMatcher(SymbolicName);
+ const InstructionMatcher &InsnMatcher =
+ Rule.getInstructionMatcher(SymbolicName);
unsigned OldInsnVarID = Rule.getInsnVarID(InsnMatcher);
Table << MatchTable::Opcode("GIR_CustomRenderer")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
@@ -2343,7 +2193,7 @@ class BuildMIAction : public MatchAction
private:
unsigned InsnID;
const CodeGenInstruction *I;
- InstructionMatcher *Matched;
+ const InstructionMatcher *Matched;
std::vector<std::unique_ptr<OperandRenderer>> OperandRenderers;
/// True if the instruction can be built solely by mutating the opcode.
@@ -2358,7 +2208,7 @@ private:
if (const auto *Copy = dyn_cast<CopyRenderer>(&*Renderer.value())) {
const OperandMatcher &OM = Rule.getOperandMatcher(Copy->getSymbolicName());
if (Insn != &OM.getInstructionMatcher() ||
- OM.getOpIdx() != Renderer.index())
+ OM.getOperandIndex() != Renderer.index())
return false;
} else
return false;
@@ -2375,7 +2225,7 @@ public:
const CodeGenInstruction *getCGI() const { return I; }
void chooseInsnToMutate(RuleMatcher &Rule) {
- for (auto *MutateCandidate : Rule.mutatable_insns()) {
+ for (const auto *MutateCandidate : Rule.mutatable_insns()) {
if (canMutate(Rule, MutateCandidate)) {
// Take the first one we're offered that we're able to mutate.
Rule.reserveInsnMatcherForMutation(MutateCandidate);
@@ -2567,13 +2417,27 @@ action_iterator RuleMatcher::insertActio
llvm::make_unique<Kind>(std::forward<Args>(args)...));
}
-unsigned RuleMatcher::implicitlyDefineInsnVar(InstructionMatcher &Matcher) {
+unsigned
+RuleMatcher::implicitlyDefineInsnVar(const InstructionMatcher &Matcher) {
unsigned NewInsnVarID = NextInsnVarID++;
InsnVariableIDs[&Matcher] = NewInsnVarID;
return NewInsnVarID;
}
-unsigned RuleMatcher::getInsnVarID(InstructionMatcher &InsnMatcher) const {
+unsigned RuleMatcher::defineInsnVar(MatchTable &Table,
+ const InstructionMatcher &Matcher,
+ unsigned InsnID, unsigned OpIdx) {
+ unsigned NewInsnVarID = implicitlyDefineInsnVar(Matcher);
+ 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;
+}
+
+unsigned RuleMatcher::getInsnVarID(const InstructionMatcher &InsnMatcher) const {
const auto &I = InsnVariableIDs.find(&InsnMatcher);
if (I != InsnVariableIDs.end())
return I->second;
@@ -2591,7 +2455,7 @@ void RuleMatcher::defineOperand(StringRe
OM.addPredicate<SameOperandMatcher>(OM.getSymbolicName());
}
-InstructionMatcher &
+const InstructionMatcher &
RuleMatcher::getInstructionMatcher(StringRef SymbolicName) const {
for (const auto &I : InsnVariableIDs)
if (I.first->getSymbolicName() == SymbolicName)
@@ -2610,10 +2474,25 @@ RuleMatcher::getOperandMatcher(StringRef
return *I->second;
}
+/// Emit MatchTable opcodes to check the shape of the match and capture
+/// instructions into local variables.
+void RuleMatcher::emitCaptureOpcodes(MatchTable &Table) {
+ assert(Matchers.size() == 1 && "Cannot handle multi-root matchers yet");
+ unsigned InsnVarID = implicitlyDefineInsnVar(*Matchers.front());
+ (void)InsnVarID;
+ assert(Matchers.front()->getVarID() == InsnVarID &&
+ "IDs differ between build and emit");
+ Matchers.front()->emitCaptureOpcodes(Table, *this);
+}
+
void RuleMatcher::emit(MatchTable &Table) {
if (Matchers.empty())
llvm_unreachable("Unexpected empty matcher!");
+ // Reset the ID generation so that the emitted IDs match the ones
+ // we set while building the InstructionMatcher and such.
+ clearImplicitMap();
+
// The representation supports rules that require multiple roots such as:
// %ptr(p0) = ...
// %elt0(s32) = G_LOAD %ptr
@@ -2627,9 +2506,7 @@ void RuleMatcher::emit(MatchTable &Table
unsigned LabelID = Table.allocateLabelID();
Table << MatchTable::Opcode("GIM_Try", +1)
- << MatchTable::Comment("On fail goto")
- << MatchTable::JumpTarget(LabelID)
- << MatchTable::Comment(("Rule ID " + Twine(RuleID) + " //").str())
+ << MatchTable::Comment("On fail goto") << MatchTable::JumpTarget(LabelID)
<< MatchTable::LineBreak;
if (!RequiredFeatures.empty()) {
@@ -2638,6 +2515,8 @@ void RuleMatcher::emit(MatchTable &Table
<< MatchTable::LineBreak;
}
+ emitCaptureOpcodes(Table);
+
Matchers.front()->emitPredicateOpcodes(Table, *this);
// We must also check if it's safe to fold the matched instructions.
@@ -2697,18 +2576,12 @@ void RuleMatcher::emit(MatchTable &Table
}
}
- for (const auto &PM : EpilogueMatchers)
- PM->emitPredicateOpcodes(Table, *this);
-
for (const auto &MA : Actions)
MA->emitActionOpcodes(Table, *this);
if (Table.isWithCoverage())
Table << MatchTable::Opcode("GIR_Coverage") << MatchTable::IntValue(RuleID)
<< MatchTable::LineBreak;
- else
- Table << MatchTable::Comment(("GIR_Coverage, " + Twine(RuleID) + ",").str())
- << MatchTable::LineBreak;
Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
<< MatchTable::Label(LabelID);
@@ -2776,7 +2649,7 @@ void SameOperandMatcher::emitPredicateOp
RuleMatcher &Rule) const {
const OperandMatcher &OtherOM = Rule.getOperandMatcher(MatchingName);
unsigned OtherInsnVarID = Rule.getInsnVarID(OtherOM.getInstructionMatcher());
- assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getInsnVarID());
+ assert(OtherInsnVarID == OtherOM.getInstructionMatcher().getVarID());
Table << MatchTable::Opcode("GIM_CheckIsSameOperand")
<< MatchTable::Comment("MI") << MatchTable::IntValue(InsnVarID)
@@ -2784,7 +2657,7 @@ void SameOperandMatcher::emitPredicateOp
<< MatchTable::Comment("OtherMI")
<< MatchTable::IntValue(OtherInsnVarID)
<< MatchTable::Comment("OtherOpIdx")
- << MatchTable::IntValue(OtherOM.getOpIdx())
+ << MatchTable::IntValue(OtherOM.getOperandIndex())
<< MatchTable::LineBreak;
}
@@ -2827,8 +2700,6 @@ private:
// Rule coverage information.
Optional<CodeGenCoverage> RuleCoverage;
- void gatherOpcodeValues();
- void gatherTypeIDValues();
void gatherNodeEquivs();
Record *findNodeEquiv(Record *N) const;
const CodeGenInstruction *getEquivNode(Record &Equiv,
@@ -2879,15 +2750,16 @@ private:
void declareSubtargetFeature(Record *Predicate);
- MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize,
- bool WithCoverage);
-
-public:
/// Takes a sequence of \p Rules and group them based on the predicates
- /// they share. \p MatcherStorage is used as a memory container
+ /// they share. \p StorageGroupMatcher is used as a memory container
/// for the group that are created as part of this process.
+ /// The optimization process does not change the relative order of
+ /// the rules. In particular, we don't try to share predicates if
+ /// that means reordering the rules (e.g., we won't group R1 and R3
+ /// in the following example as it would imply reordering R2 and R3
+ /// => R1 p1, R2 p2, R3 p1).
///
- /// What this optimization does looks like if GroupT = GroupMatcher:
+ /// What this optimization does looks like:
/// Output without optimization:
/// \verbatim
/// # R1
@@ -2908,19 +2780,13 @@ public:
/// # R2
/// # predicate C
/// \endverbatim
- template <class GroupT>
- static std::vector<Matcher *> optimizeRules(
+ std::vector<Matcher *> optimizeRules(
ArrayRef<Matcher *> Rules,
- std::vector<std::unique_ptr<Matcher>> &MatcherStorage);
-};
-
-void GlobalISelEmitter::gatherOpcodeValues() {
- InstructionOpcodeMatcher::initOpcodeValuesMap(Target);
-}
+ std::vector<std::unique_ptr<GroupMatcher>> &StorageGroupMatcher);
-void GlobalISelEmitter::gatherTypeIDValues() {
- LLTOperandMatcher::initTypeIDValuesMap();
-}
+ MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize,
+ bool WithCoverage);
+};
void GlobalISelEmitter::gatherNodeEquivs() {
assert(NodeEquivs.empty());
@@ -3656,6 +3522,7 @@ Expected<RuleMatcher> GlobalISelEmitter:
M.addAction<DebugCommentAction>(llvm::to_string(*P.getSrcPattern()) +
" => " +
llvm::to_string(*P.getDstPattern()));
+ M.addAction<DebugCommentAction>("Rule ID " + llvm::to_string(M.getRuleID()));
if (auto Error = importRulePredicates(M, P.getPredicates()))
return std::move(Error);
@@ -3911,53 +3778,35 @@ void GlobalISelEmitter::emitImmPredicate
<< "}\n";
}
-template <class GroupT>
std::vector<Matcher *> GlobalISelEmitter::optimizeRules(
ArrayRef<Matcher *> Rules,
- std::vector<std::unique_ptr<Matcher>> &MatcherStorage) {
-
+ std::vector<std::unique_ptr<GroupMatcher>> &StorageGroupMatcher) {
std::vector<Matcher *> OptRules;
- std::unique_ptr<GroupT> CurrentGroup = make_unique<GroupT>();
- assert(CurrentGroup->empty() && "Newly created group isn't empty!");
- unsigned NumGroups = 0;
-
- auto ProcessCurrentGroup = [&]() {
- if (CurrentGroup->empty())
- // An empty group is good to be reused:
- return;
-
- // If the group isn't large enough to provide any benefit, move all the
- // added rules out of it and make sure to re-create the group to properly
- // re-initialize it:
- if (CurrentGroup->size() < 2)
- for (Matcher *M : CurrentGroup->matchers())
- OptRules.push_back(M);
- else {
- CurrentGroup->finalize();
- OptRules.push_back(CurrentGroup.get());
- MatcherStorage.emplace_back(std::move(CurrentGroup));
- ++NumGroups;
- }
- CurrentGroup = make_unique<GroupT>();
- };
+ // Start with a stupid grouping for now.
+ std::unique_ptr<GroupMatcher> CurrentGroup = make_unique<GroupMatcher>();
+ assert(CurrentGroup->conditions_empty());
+ unsigned NbGroup = 0;
for (Matcher *Rule : Rules) {
- // Greedily add as many matchers as possible to the current group:
- if (CurrentGroup->addMatcher(*Rule))
- continue;
-
- ProcessCurrentGroup();
- assert(CurrentGroup->empty() && "A group wasn't properly re-initialized");
-
- // Try to add the pending matcher to a newly created empty group:
- if (!CurrentGroup->addMatcher(*Rule))
- // If we couldn't add the matcher to an empty group, that group type
- // doesn't support that kind of matchers at all, so just skip it:
- OptRules.push_back(Rule);
+ std::unique_ptr<PredicateMatcher> Predicate = Rule->forgetFirstCondition();
+ if (!CurrentGroup->conditions_empty() &&
+ !CurrentGroup->lastConditionMatches(*Predicate)) {
+ // Start a new group.
+ ++NbGroup;
+ OptRules.push_back(CurrentGroup.get());
+ StorageGroupMatcher.emplace_back(std::move(CurrentGroup));
+ CurrentGroup = make_unique<GroupMatcher>();
+ assert(CurrentGroup->conditions_empty());
+ }
+ if (CurrentGroup->conditions_empty())
+ CurrentGroup->addCondition(std::move(Predicate));
+ CurrentGroup->addRule(*Rule);
+ }
+ if (!CurrentGroup->conditions_empty()) {
+ ++NbGroup;
+ OptRules.push_back(CurrentGroup.get());
+ StorageGroupMatcher.emplace_back(std::move(CurrentGroup));
}
- ProcessCurrentGroup();
-
- DEBUG(dbgs() << "NumGroups: " << NumGroups << "\n");
- assert(CurrentGroup->empty() && "The last group wasn't properly processed");
+ LLVM_DEBUG(dbgs() << "NbGroup: " << NbGroup << "\n");
return OptRules;
}
@@ -3971,15 +3820,9 @@ GlobalISelEmitter::buildMatchTable(Mutab
if (!Optimize)
return MatchTable::buildTable(InputRules, WithCoverage);
- for (Matcher *Rule : InputRules)
- Rule->optimize();
-
- std::vector<std::unique_ptr<Matcher>> MatcherStorage;
+ std::vector<std::unique_ptr<GroupMatcher>> StorageGroupMatcher;
std::vector<Matcher *> OptRules =
- optimizeRules<GroupMatcher>(InputRules, MatcherStorage);
-
- for (Matcher *Rule : OptRules)
- Rule->optimize();
+ optimizeRules(InputRules, StorageGroupMatcher);
return MatchTable::buildTable(OptRules, WithCoverage);
}
@@ -3999,11 +3842,6 @@ void GlobalISelEmitter::run(raw_ostream
}
}
- // Track the run-time opcode values
- gatherOpcodeValues();
- // Track the run-time LLT ID values
- gatherTypeIDValues();
-
// Track the GINodeEquiv definitions.
gatherNodeEquivs();
@@ -4092,8 +3930,8 @@ void GlobalISelEmitter::run(raw_ostream
OS << "#ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n"
<< ", State(" << MaxTemporaries << "),\n"
- << "ISelInfo(TypeObjects, NumTypeObjects, FeatureBitsets"
- << ", ComplexPredicateFns, CustomRenderers)\n"
+ << "ISelInfo({TypeObjects, FeatureBitsets, ComplexPredicateFns, "
+ "CustomRenderers})\n"
<< "#endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT\n\n";
OS << "#ifdef GET_GLOBALISEL_IMPL\n";
@@ -4135,8 +3973,7 @@ void GlobalISelEmitter::run(raw_ostream
TypeObject.emitCxxEnumValue(OS);
OS << ",\n";
}
- OS << "};\n";
- OS << "const static size_t NumTypeObjects = " << TypeObjects.size() << ";\n"
+ OS << "};\n"
<< "const static LLT TypeObjects[] = {\n";
for (const auto &TypeObject : TypeObjects) {
OS << " ";
@@ -4315,154 +4152,62 @@ void GlobalISelEmitter::declareSubtarget
Predicate, SubtargetFeatureInfo(Predicate, SubtargetFeatures.size()));
}
-void RuleMatcher::optimize() {
- for (auto &Item : InsnVariableIDs) {
- InstructionMatcher &InsnMatcher = *Item.first;
- for (auto &OM : InsnMatcher.operands()) {
- // Register Banks checks rarely fail, but often crash as targets usually
- // provide only partially defined RegisterBankInfo::getRegBankFromRegClass
- // method. Often the problem is hidden as non-optimized MatchTable checks
- // banks rather late, most notably after checking target / function /
- // module features and a few opcodes. That makes these checks a)
- // beneficial to delay until the very end (we don't want to perform a lot
- // of checks that all pass and then fail at the very end) b) not safe to
- // have as early checks.
- for (auto &OP : OM->predicates())
- if (isa<RegisterBankOperandMatcher>(OP) ||
- isa<ComplexPatternOperandMatcher>(OP))
- EpilogueMatchers.emplace_back(std::move(OP));
- OM->eraseNullPredicates();
- }
- InsnMatcher.optimize();
- }
- llvm::sort(
- EpilogueMatchers.begin(), EpilogueMatchers.end(),
- [](const std::unique_ptr<PredicateMatcher> &L,
- const std::unique_ptr<PredicateMatcher> &R) {
- return std::make_tuple(L->getKind(), L->getInsnVarID(), L->getOpIdx()) <
- std::make_tuple(R->getKind(), R->getInsnVarID(), R->getOpIdx());
- });
-}
-
-bool RuleMatcher::hasFirstCondition() const {
- if (insnmatchers_empty())
- return false;
- InstructionMatcher &Matcher = insnmatchers_front();
- if (!Matcher.predicates_empty())
- return true;
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP))
- return true;
- return false;
-}
-
-const PredicateMatcher &RuleMatcher::getFirstCondition() const {
- assert(!insnmatchers_empty() &&
- "Trying to get a condition from an empty RuleMatcher");
-
- InstructionMatcher &Matcher = insnmatchers_front();
- if (!Matcher.predicates_empty())
- return **Matcher.predicates_begin();
- // If there is no more predicate on the instruction itself, look at its
- // operands.
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP))
- return *OP;
-
- llvm_unreachable("Trying to get a condition from an InstructionMatcher with "
- "no conditions");
-}
-
-std::unique_ptr<PredicateMatcher> RuleMatcher::popFirstCondition() {
+std::unique_ptr<PredicateMatcher> RuleMatcher::forgetFirstCondition() {
assert(!insnmatchers_empty() &&
- "Trying to pop a condition from an empty RuleMatcher");
+ "Trying to forget something that does not exist");
InstructionMatcher &Matcher = insnmatchers_front();
+ std::unique_ptr<PredicateMatcher> Condition;
if (!Matcher.predicates_empty())
- return Matcher.predicates_pop_front();
- // If there is no more predicate on the instruction itself, look at its
- // operands.
- for (auto &OM : Matcher.operands())
- for (auto &OP : OM->predicates())
- if (!isa<InstructionOperandMatcher>(OP)) {
- auto Result = std::move(OP);
- OM->eraseNullPredicates();
- return Result;
- }
-
- llvm_unreachable("Trying to pop a condition from an InstructionMatcher with "
- "no conditions");
+ Condition = Matcher.predicates_pop_front();
+ if (!Condition) {
+ // If there is no more predicate on the instruction itself, look at its
+ // operands.
+ assert(!Matcher.operands_empty() &&
+ "Empty instruction should have been discarded");
+ OperandMatcher &OpMatcher = **Matcher.operands_begin();
+ assert(!OpMatcher.predicates_empty() && "no operand constraint");
+ Condition = OpMatcher.predicates_pop_front();
+ // If this operand is free of constraints, rip it off.
+ if (OpMatcher.predicates_empty())
+ Matcher.pop_front();
+ }
+ // Rip the instruction off when it is empty.
+ if (Matcher.operands_empty() && Matcher.predicates_empty())
+ insnmatchers_pop_front();
+ return Condition;
}
-bool GroupMatcher::candidateConditionMatches(
+bool GroupMatcher::lastConditionMatches(
const PredicateMatcher &Predicate) const {
-
- if (empty()) {
- // Sharing predicates for nested instructions is not supported yet as we
- // currently don't hoist the GIM_RecordInsn's properly, therefore we can
- // only work on the original root instruction (InsnVarID == 0):
- if (Predicate.getInsnVarID() != 0)
- return false;
- // ... otherwise an empty group can handle any predicate with no specific
- // requirements:
- return true;
- }
-
- const Matcher &Representative = **Matchers.begin();
- const auto &RepresentativeCondition = Representative.getFirstCondition();
- // ... if not empty, the group can only accomodate matchers with the exact
- // same first condition:
- return Predicate.isIdentical(RepresentativeCondition);
-}
-
-bool GroupMatcher::addMatcher(Matcher &Candidate) {
- if (!Candidate.hasFirstCondition())
- return false;
-
- const PredicateMatcher &Predicate = Candidate.getFirstCondition();
- if (!candidateConditionMatches(Predicate))
- return false;
-
- Matchers.push_back(&Candidate);
- return true;
-}
-
-void GroupMatcher::finalize() {
- assert(Conditions.empty() && "Already finalized?");
- if (empty())
- return;
-
- Matcher &FirstRule = **Matchers.begin();
-
- Conditions.push_back(FirstRule.popFirstCondition());
- for (unsigned I = 1, E = Matchers.size(); I < E; ++I)
- Matchers[I]->popFirstCondition();
+ const auto &LastCondition = conditions_back();
+ return Predicate.isIdentical(*LastCondition);
}
void GroupMatcher::emit(MatchTable &Table) {
- unsigned LabelID = ~0U;
- if (!Conditions.empty()) {
- LabelID = Table.allocateLabelID();
+ unsigned LabelID = Table.allocateLabelID();
+ if (!conditions_empty()) {
Table << MatchTable::Opcode("GIM_Try", +1)
<< MatchTable::Comment("On fail goto")
<< MatchTable::JumpTarget(LabelID) << MatchTable::LineBreak;
+ for (auto &Condition : Conditions)
+ Condition->emitPredicateOpcodes(
+ Table, *static_cast<RuleMatcher *>(*Rules.begin()));
}
- for (auto &Condition : Conditions)
- Condition->emitPredicateOpcodes(
- Table, *static_cast<RuleMatcher *>(*Matchers.begin()));
-
- for (const auto &M : Matchers)
- M->emit(Table);
-
- // Exit the group
- if (!Conditions.empty())
- Table << MatchTable::Opcode("GIM_Reject", -1) << MatchTable::LineBreak
+ // Emit the conditions.
+ // Then checks apply the rules.
+ for (const auto &Rule : Rules)
+ Rule->emit(Table);
+ // If we don't succeeded for that block, that means we are not going to select
+ // this instruction.
+ if (!conditions_empty()) {
+ Table << MatchTable::Opcode("GIM_Reject") << MatchTable::LineBreak;
+ Table << MatchTable::Opcode("GIR_Done", -1) << MatchTable::LineBreak
<< MatchTable::Label(LabelID);
+ }
}
-unsigned OperandMatcher::getInsnVarID() const { return Insn.getInsnVarID(); }
+unsigned OperandMatcher::getInsnVarID() const { return Insn.getVarID(); }
} // end anonymous namespace
More information about the llvm-commits
mailing list