[llvm] [TableGen][GlobalISel] Add MIFlags matching & rewriting (PR #71179)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 3 06:02:45 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-globalisel
Author: Pierre van Houtryve (Pierre-vh)
<details>
<summary>Changes</summary>
NOTE: This review is part of a stack. Please only review the last commit. See #<!-- -->66377 to review the first commit.
Also disables generation of MutateOpcode. It's almost never used in combiners anyway.
If we really want to use it, it needs to be investigated & properly fixed (see TODO)
Fixes #<!-- -->70780
---
Patch is 75.04 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71179.diff
14 Files Affected:
- (modified) llvm/docs/GlobalISel/MIRPatterns.rst (+38)
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h (+21)
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h (+59-2)
- (modified) llvm/include/llvm/Target/GenericOpcodes.td (+7)
- (modified) llvm/include/llvm/Target/GlobalISel/Combine.td (+20-1)
- (added) llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-miflags.td (+47)
- (modified) llvm/test/TableGen/GlobalISelCombinerEmitter/patfrag-errors.td (+16-1)
- (modified) llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td (+53-3)
- (modified) llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td (+24-1)
- (added) llvm/test/TableGen/GlobalISelCombinerEmitter/type-inference.td (+75)
- (modified) llvm/test/TableGen/GlobalISelCombinerEmitter/typeof-errors.td (+5-2)
- (modified) llvm/utils/TableGen/GlobalISelCombinerEmitter.cpp (+816-130)
- (modified) llvm/utils/TableGen/GlobalISelMatchTable.cpp (+46)
- (modified) llvm/utils/TableGen/GlobalISelMatchTable.h (+33)
``````````diff
diff --git a/llvm/docs/GlobalISel/MIRPatterns.rst b/llvm/docs/GlobalISel/MIRPatterns.rst
index a3883b14b3e0bd6..9c363a38d29551d 100644
--- a/llvm/docs/GlobalISel/MIRPatterns.rst
+++ b/llvm/docs/GlobalISel/MIRPatterns.rst
@@ -183,6 +183,44 @@ Semantics:
* The root cannot have any output operands.
* The root must be a CodeGenInstruction
+Instruction Flags
+-----------------
+
+MIR Patterns support both matching & writing ``MIFlags``.
+``MIFlags`` are never preserved; output instructions have never have
+any flags unless explicitly set.
+
+.. code-block:: text
+ :caption: Example
+
+ def Test : GICombineRule<
+ (defs root:$dst),
+ (match (G_FOO $dst, $src, (MIFlags FmNoNans, FmNoInfs))),
+ (apply (G_BAR $dst, $src, (MIFlags FmReassoc)))>;
+
+In ``apply`` patterns, we also support referring to a matched instruction to
+"take" its MIFlags.
+
+.. code-block:: text
+ :caption: Example
+
+ ; We match NoNans/NoInfs, but $zext may have more flags.
+ ; Copy them all into the output instruction, but remove Reassoc if present.
+ def TestCpyFlags : GICombineRule<
+ (defs root:$dst),
+ (match (G_FOO $dst, $src, (MIFlags FmNoNans, FmNoInfs)):$zext),
+ (apply (G_BAR $dst, $src, (MIFlags $zext, FmReassoc)))>;
+
+The ``not`` operator can be used to check that a flag is NOT present
+on a matched instruction, and to remove a flag from a generated instruction.
+
+.. code-block:: text
+ :caption: Example
+
+ def TestNot : GICombineRule<
+ (defs root:$dst),
+ (match (G_FOO $dst, $src, (MIFlags FmNoInfs, (not FmNoNans, FmReassoc))):$zext),
+ (apply (G_BAR $dst, $src, (MIFlags $zext, (not FmNoInfs))))>;
Limitations
-----------
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
index 6fcd9d09e1863cc..f5d9f5f40881cb5 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h
@@ -266,6 +266,13 @@ enum {
/// - NewOpIdx
GIM_CheckCanReplaceReg,
+ /// Check that a matched instruction has, or doesn't have a MIFlag.
+ ///
+ /// - InsnID - Instruction to check.
+ /// - Flag(s) - (can be one or more flags OR'd together)
+ GIM_MIFlags,
+ GIM_MIFlagsNot,
+
/// Predicates with 'let PredicateCodeUsesOperands = 1' need to examine some
/// named operands that will be recorded in RecordedOperands. Names of these
/// operands are referenced in predicate argument list. Emitter determines
@@ -344,6 +351,20 @@ enum {
/// OpIdx starts at 0 for the first implicit def.
GIR_SetImplicitDefDead,
+ /// Set or unset a MIFlag on an instruction.
+ ///
+ /// - InsnID - Instruction to modify.
+ /// - Flag(s) - (can be one or more flags OR'd together)
+ GIR_SetMIFlags,
+ GIR_UnsetMIFlags,
+
+ /// Copy the MIFlags of a matched instruction into an
+ /// output instruction. The flags are OR'd together.
+ ///
+ /// - InsnID - Instruction to modify.
+ /// - OldInsnID - Matched instruction to copy flags from.
+ GIR_CopyMIFlags,
+
/// Add a temporary register to the specified instruction
/// - InsnID - Instruction ID to modify
/// - TempRegID - The temporary register ID to add
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
index 32e2f21d775f303..f0ee76c097bcab5 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h
@@ -88,8 +88,6 @@ bool GIMatchTableExecutor::executeMatchTable(
if (Observer)
Observer->changedInstr(*MIB);
}
-
- return true;
};
// If the index is >= 0, it's an index in the type objects generated by
@@ -919,6 +917,32 @@ bool GIMatchTableExecutor::executeMatchTable(
}
break;
}
+ case GIM_MIFlags: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIM_MIFlags(MIs[" << InsnID
+ << "], " << Flags << ")\n");
+ if ((State.MIs[InsnID]->getFlags() & Flags) != Flags) {
+ if (handleReject() == RejectAndGiveUp)
+ return false;
+ }
+ break;
+ }
+ case GIM_MIFlagsNot: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIM_MIFlagsNot(MIs[" << InsnID
+ << "], " << Flags << ")\n");
+ if ((State.MIs[InsnID]->getFlags() & Flags)) {
+ if (handleReject() == RejectAndGiveUp)
+ return false;
+ }
+ break;
+ }
case GIM_Reject:
DEBUG_WITH_TYPE(TgtExecutor::getName(),
dbgs() << CurrentIdx << ": GIM_Reject\n");
@@ -1062,6 +1086,39 @@ bool GIMatchTableExecutor::executeMatchTable(
MI->getOperand(MI->getNumExplicitOperands() + OpIdx).setIsDead();
break;
}
+ case GIR_SetMIFlags: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIR_SetMIFlags(OutMIs["
+ << InsnID << "], " << Flags << ")\n");
+ MachineInstr *MI = OutMIs[InsnID];
+ MI->setFlags(MI->getFlags() | Flags);
+ break;
+ }
+ case GIR_UnsetMIFlags: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ uint32_t Flags = (uint32_t)MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIR_UnsetMIFlags(OutMIs["
+ << InsnID << "], " << Flags << ")\n");
+ MachineInstr *MI = OutMIs[InsnID];
+ MI->setFlags(MI->getFlags() & ~Flags);
+ break;
+ }
+ case GIR_CopyMIFlags: {
+ int64_t InsnID = MatchTable[CurrentIdx++];
+ int64_t OldInsnID = MatchTable[CurrentIdx++];
+
+ DEBUG_WITH_TYPE(TgtExecutor::getName(),
+ dbgs() << CurrentIdx << ": GIR_CopyMIFlags(OutMIs["
+ << InsnID << "], MIs[" << OldInsnID << "])\n");
+ MachineInstr *MI = OutMIs[InsnID];
+ MI->setFlags(MI->getFlags() | State.MIs[OldInsnID]->getFlags());
+ break;
+ }
case GIR_AddTempRegister:
case GIR_AddTempSubRegister: {
int64_t InsnID = MatchTable[CurrentIdx++];
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index a1afc3b8042c284..9a9c09d3c20d612 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -17,6 +17,10 @@
class GenericInstruction : StandardPseudoInstruction {
let isPreISelOpcode = true;
+
+ // When all variadic ops share a type with another operand,
+ // this is the type they share. Used by MIR patterns type inference.
+ TypedOperand variadicOpsType = ?;
}
// Provide a variant of an instruction with the same operands, but
@@ -1228,6 +1232,7 @@ def G_UNMERGE_VALUES : GenericInstruction {
let OutOperandList = (outs type0:$dst0, variable_ops);
let InOperandList = (ins type1:$src);
let hasSideEffects = false;
+ let variadicOpsType = type0;
}
// Insert a smaller register into a larger one at the specified bit-index.
@@ -1245,6 +1250,7 @@ def G_MERGE_VALUES : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$src0, variable_ops);
let hasSideEffects = false;
+ let variadicOpsType = type1;
}
/// Create a vector from multiple scalar registers. No implicit
@@ -1254,6 +1260,7 @@ def G_BUILD_VECTOR : GenericInstruction {
let OutOperandList = (outs type0:$dst);
let InOperandList = (ins type1:$src0, variable_ops);
let hasSideEffects = false;
+ let variadicOpsType = type1;
}
/// Like G_BUILD_VECTOR, but truncates the larger operand types to fit the
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 63c485a5a6c6070..76b83cc5df073ae 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -164,6 +164,25 @@ def GIReplaceReg : GIBuiltinInst;
// TODO: Allow using this directly, like (apply GIEraseRoot)
def GIEraseRoot : GIBuiltinInst;
+//===----------------------------------------------------------------------===//
+// Pattern MIFlags
+//===----------------------------------------------------------------------===//
+
+class MIFlagEnum<string enumName> {
+ string EnumName = "MachineInstr::" # enumName;
+}
+
+def FmNoNans : MIFlagEnum<"FmNoNans">;
+def FmNoInfs : MIFlagEnum<"FmNoInfs">;
+def FmNsz : MIFlagEnum<"FmNsz">;
+def FmArcp : MIFlagEnum<"FmArcp">;
+def FmContract : MIFlagEnum<"FmContract">;
+def FmAfn : MIFlagEnum<"FmAfn">;
+def FmReassoc : MIFlagEnum<"FmReassoc">;
+
+def MIFlags;
+// def not; -> Already defined as a SDNode
+
//===----------------------------------------------------------------------===//
def extending_load_matchdata : GIDefMatchData<"PreferredTuple">;
@@ -796,7 +815,7 @@ def trunc_shift: GICombineRule <
def mul_by_neg_one: GICombineRule <
(defs root:$dst),
(match (G_MUL $dst, $x, -1)),
- (apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
+ (apply (G_SUB $dst, 0, $x))
>;
// Fold (xor (and x, y), y) -> (and (not x), y)
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-miflags.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-miflags.td
new file mode 100644
index 000000000000000..9f02ff17493652d
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-miflags.td
@@ -0,0 +1,47 @@
+// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
+// RUN: -combiners=MyCombiner %s | \
+// RUN: FileCheck %s
+
+include "llvm/Target/Target.td"
+include "llvm/Target/GlobalISel/Combine.td"
+
+def MyTargetISA : InstrInfo;
+def MyTarget : Target { let InstructionSet = MyTargetISA; }
+
+def MIFlagsTest : GICombineRule<
+ (defs root:$dst),
+ (match (G_SEXT $dst, $tmp), (G_ZEXT $tmp, $src, (MIFlags FmReassoc, FmNsz, (not FmNoNans, FmArcp))):$mi),
+ (apply (G_MUL $dst, $src, $src, (MIFlags $mi, FmReassoc, (not FmNsz, FmArcp))))>;
+
+def MyCombiner: GICombiner<"GenMyCombiner", [MIFlagsTest]>;
+
+// CHECK: const int64_t *GenMyCombiner::getMatchTable() const {
+// CHECK-NEXT: constexpr static int64_t MatchTable0[] = {
+// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 49, // Rule ID 0 //
+// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_SEXT,
+// CHECK-NEXT: // MIs[0] dst
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: // MIs[0] tmp
+// CHECK-NEXT: GIM_RecordInsnIgnoreCopies, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
+// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_ZEXT,
+// CHECK-NEXT: GIM_MIFlags, /*MI*/1, MachineInstr::FmNsz | MachineInstr::FmReassoc,
+// CHECK-NEXT: GIM_MIFlagsNot, /*MI*/1, MachineInstr::FmArcp | MachineInstr::FmNoNans,
+// CHECK-NEXT: // MIs[1] src
+// CHECK-NEXT: // No operand predicates
+// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
+// CHECK-NEXT: // Combiner Rule #0: MIFlagsTest
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::G_MUL,
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
+// CHECK-NEXT: GIR_CopyMIFlags, /*InsnID*/0, /*OldInsnID*/1,
+// CHECK-NEXT: GIR_SetMIFlags, /*InsnID*/0, MachineInstr::FmReassoc,
+// CHECK-NEXT: GIR_UnsetMIFlags, /*InsnID*/0, MachineInstr::FmNsz | MachineInstr::FmArcp,
+// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
+// CHECK-NEXT: GIR_Done,
+// CHECK-NEXT: // Label 0: @49
+// CHECK-NEXT: GIM_Reject,
+// CHECK-NEXT: };
+// CHECK-NEXT: return MatchTable0;
+// CHECK-NEXT: }
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/patfrag-errors.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/patfrag-errors.td
index 68bec4fa722d191..6f5c2b93609f428 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/patfrag-errors.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/patfrag-errors.td
@@ -271,6 +271,19 @@ def root_def_has_multi_defs : GICombineRule<
(match (RootDefHasMultiDefs $root, (i32 10))),
(apply (COPY $root, (i32 0)))>;
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: matching/writing MIFlags is only allowed on CodeGenInstruction patterns
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(DummyCXXPF ?:$x, (MIFlags FmArcp))'
+def miflags_in_pf : GICombineRule<
+ (defs root:$x),
+ (match (COPY $x, $y), (DummyCXXPF $x, (MIFlags FmArcp))),
+ (apply (COPY $x, $y))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: '$pf' does not refer to a CodeGenInstruction in MIFlags of '__badtype_for_flagref_in_apply_apply_0'
+def badtype_for_flagref_in_apply : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src), (DummyCXXPF $src):$pf),
+ (apply (G_MUL $dst, $src, $src, (MIFlags $pf)))>;
+
// CHECK: error: Failed to parse one or more rules
def MyCombiner: GICombiner<"GenMyCombiner", [
@@ -293,5 +306,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
patfrag_in_apply,
patfrag_cannot_be_root,
inconsistent_arg_type,
- root_def_has_multi_defs
+ root_def_has_multi_defs,
+ miflags_in_pf,
+ badtype_for_flagref_in_apply
]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td
index 48a06474da78a10..e45a1c866a51544 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-errors.td
@@ -151,7 +151,7 @@ def bad_imm_too_many_args : GICombineRule<
(match (COPY $x, (i32 0, 0)):$d),
(apply (COPY $x, $b):$d)>;
-// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: cannot parse immediate '(COPY 0)', 'COPY' is not a ValueType
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: unknown type 'COPY'
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(COPY ?:$x, (COPY 0))
def bad_imm_not_a_valuetype : GICombineRule<
(defs root:$a),
@@ -186,7 +186,7 @@ def expected_op_name : GICombineRule<
(match (G_FNEG $x, i32)),
(apply (COPY $x, (i32 0)))>;
-// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: invalid operand type: 'not_a_type' is not a ValueType
+// CHECK: :[[@LINE+3]]:{{[0-9]+}}: error: unknown type 'not_a_type'
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_FNEG ?:$x, not_a_type:$y)'
def not_a_type;
def bad_mo_type_not_a_valuetype : GICombineRule<
@@ -217,6 +217,50 @@ def def_named_imm_apply : GICombineRule<
(apply (COPY i32:$tmp, $y),
(COPY $x, (i32 0):$tmp):$foo)>;
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: MIFlags can only be present once on an instruction
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_ZEXT ?:$dst, ?:$src, (MIFlags FmArcp), (MIFlags FmArcp))'
+def multi_miflags : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src, (MIFlags FmArcp), (MIFlags FmArcp)):$mi),
+ (apply (G_MUL $dst, $src, $src))>;
+
+def NotAMIFlagEnum;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: 'NotAMIFlagEnum' is not a subclass of 'MIFlagEnum'
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_ZEXT ?:$dst, ?:$src, (MIFlags NotAMIFlagEnum))'
+def not_miflagenum_1 : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src, (MIFlags NotAMIFlagEnum)):$mi),
+ (apply (G_MUL $dst, $src, $src))>;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: 'NotAMIFlagEnum' is not a subclass of 'MIFlagEnum'
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(G_ZEXT ?:$dst, ?:$src, (MIFlags (not NotAMIFlagEnum)))'
+def not_miflagenum_2 : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src, (MIFlags (not NotAMIFlagEnum))):$mi),
+
+ (apply (G_MUL $dst, $src, $src))>;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: matching/writing MIFlags is only allowed on CodeGenInstruction patterns
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(GIReplaceReg ?:$x, ?:$y, (MIFlags FmArcp))'
+def miflags_in_builtin : GICombineRule<
+ (defs root:$x),
+ (match (COPY $x, $y)),
+ (apply (GIReplaceReg $x, $y, (MIFlags FmArcp)))>;
+
+// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: 'match' patterns cannot refer to flags from other instructions
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: note: MIFlags in 'mi' refer to: impostor
+def using_flagref_in_match : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src, (MIFlags $impostor)):$mi),
+ (apply (G_MUL $dst, $src, $src))>;
+
+// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: unknown instruction '$impostor' referenced in MIFlags of '__badflagref_in_apply_apply_0'
+def badflagref_in_apply : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src):$mi),
+ (apply (G_MUL $dst, $src, $src, (MIFlags $impostor)))>;
+
// CHECK: error: Failed to parse one or more rules
def MyCombiner: GICombiner<"GenMyCombiner", [
@@ -251,5 +295,11 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
bad_mo_type_not_a_valuetype,
untyped_new_reg_in_apply,
def_named_imm_match,
- def_named_imm_apply
+ def_named_imm_apply,
+ multi_miflags,
+ not_miflagenum_1,
+ not_miflagenum_2,
+ miflags_in_builtin,
+ using_flagref_in_match,
+ badflagref_in_apply
]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
index fd41a7d1d72417e..26f3bb88da951c4 100644
--- a/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td
@@ -320,6 +320,28 @@ def TypeOfTest : GICombineRule<
(G_ZEXT $tmp, $src)),
(apply (G_MUL $dst, (GITypeOf<"$src"> 0), (GITypeOf<"$dst"> -1)))>;
+
+// CHECK: (CombineRule name:MIFlagsTest id:11 root:dst
+// CHECK-NEXT: (MatchPats
+// CHECK-NEXT: <match_root>mi:(CodeGenInstructionPattern G_ZEXT operands:[<def>$dst, $src] (MIFlags (set MachineInstr::FmReassoc) (unset MachineInstr::FmNoNans, MachineInstr::FmArcp)))
+// CHECK-NEXT: )
+// CHECK-NEXT: (ApplyPats
+// CHECK-NEXT: <apply_root>__MIFlagsTest_apply_0:(CodeGenInstructionPattern G_MUL operands:[<def>$dst, $src, $src] (MIFlags (set MachineInstr::FmReassoc) (unset MachineInstr::FmNsz, MachineInstr::FmArcp) (copy mi)))
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable MatchPats
+// CHECK-NEXT: dst -> mi
+// CHECK-NEXT: src -> <live-in>
+// CHECK-NEXT: )
+// CHECK-NEXT: (OperandTable ApplyPats
+// CHECK-NEXT: dst -> __MIFlagsTest_apply_0
+// CHECK-NEXT: src -> <live-in>
+// CHECK-NEXT: )
+// CHECK-NEXT: )
+def MIFlagsTest : GICombineRule<
+ (defs root:$dst),
+ (match (G_ZEXT $dst, $src, (MIFlags FmReassoc, (not FmNoNans, FmArcp))):$mi),
+ (apply (G_MUL $dst, $src, $src, (MIFlags $mi, FmReassoc, (not FmNsz, FmArcp))))>;
+
def MyCombiner: GICombiner<"GenMyCombiner", [
WipOpcodeTest0,
WipOpcodeTest1,
@@ -331,5 +353,6 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
PatFragTest1,
VariadicsInTest,
VariadicsOutTest,
- TypeOfTest
+ TypeOfTest,
+ MIFlagsTest
]>;
diff --git a/llvm/test/TableGen/GlobalISelCombinerEmitter/type-inference.td b/llvm/test/TableGen/GlobalISelCombinerEmitter/type-inference.td
new file mode 100644
index 000000000000000..7ed14dd5e6cc0eb
--- /dev/null
+++ b/llvm/test/TableGen/GlobalISelCombinerEmitter/type-inference.td
@@ -0,0 +1,75 @@
+// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
+// RUN: -gicombiner-debug-typeinfer -combiners=MyCombiner %s 2>&1 | \
+// RUN: FileCheck %s
+
+// Checks reasoning of the inference rules.
+
+include "llvm/Target/Target.td"
+include "llvm/Target/GlobalISel/Combine.td"
+
+def MyTargetISA : InstrInfo;
+def MyTarget : Target { let InstructionSet = MyTargetISA; }
+
+// CHECK: Rule Operand Type Equivalence Cla...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/71179
More information about the llvm-commits
mailing list