Files
clang-p2996/llvm/test/TableGen/GlobalISelEmitterMatchTableOptimizer.td
Sergei Barannikov 8e8c954a17 [GISel] Erase the root instruction after emitting all its potential uses (#77494)
This tries to fix a bug by resolving a few FIXMEs. The bug is that
`EraseInstAction` is emitted after emitting the _first_ `BuildMIAction`,
which is too early because the erased instruction may still be used by
subsequent `BuildMIAction`s (in particular, by `CopyRenderer`).

An example of the bug (from `match-table-operand-types.td`):
```
def InstTest0 : GICombineRule<
  (defs root:$a),
  (match  (G_MUL i32:$x, i32:$b, i32:$c),
          (G_MUL $a, i32:$b, i32:$x)),
  (apply  (G_ADD i64:$tmp, $b, i32:$c),
          (G_ADD i8:$a, $b, i64:$tmp))>;

GIR_EraseFromParent, /*InsnID*/0,
GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::G_ADD),
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // a
GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // b
GIR_AddSimpleTempRegister, /*InsnID*/1, /*TempRegID*/0,
```

Here, the root instruction is destroyed before copying its operands ('a'
and 'b') to the new instruction.

The solution is to emit `EraseInstAction` for the root instruction as
the last action in the emission pipeline.
2024-01-13 11:17:41 +03:00

86 lines
5.4 KiB
TableGen

// RUN: llvm-tblgen %s -gen-global-isel -optimize-match-table=true -I %p/../../include -I %p/Common -o - | FileCheck %s
include "llvm/Target/Target.td"
include "GlobalISelEmitterCommon.td"
// Two LOADs with same output size but different input size, hence their
// GIM_CheckPointerToAny should *not* be merged
def LOAD8 : I<(outs GPR8:$dst), (ins GPR8:$src), []>;
def LOAD32 : I<(outs GPR8:$dst), (ins GPR32:$src), []>;
// CHECK: Label 1: @{{[0-9]+}}
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L1_ID:[0-9]+]]*/ GIMT_Encode4([[L1_AT:[0-9]+]]),
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR8RegClassID),
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L2_ID:[0-9]+]]*/ GIMT_Encode4([[L2_AT:[0-9]+]]),
// CHECK-NEXT: // MIs[0] src
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/8,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR8RegClassID),
// CHECK-NEXT: // (ld:{ *:[i8] } GPR8:{ *:[i8] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD8:{ *:[i8] } GPR8:{ *:[i8] }:$src)
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD8),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: // GIR_Coverage, 0,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label [[L2_ID]]: @[[L2_AT]]
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L3_ID:[0-9]+]]*/ GIMT_Encode4([[L3_AT:[0-9]+]]),
// CHECK-NEXT: // MIs[0] src
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR32RegClassID),
// CHECK-NEXT: // (ld:{ *:[i8] } GPR32:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD32:{ *:[i8] } GPR32:{ *:[i32] }:$src)
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD32),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: // GIR_Coverage, 1,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label [[L3_ID]]: @[[L3_AT]]
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: // Label [[L1_ID]]: @[[L1_AT]]
def : Pat<(i8 (load GPR8:$src)),
(LOAD8 GPR8:$src)>;
def : Pat<(i8 (load GPR32:$src)),
(LOAD32 GPR32:$src)>;
// Two LOADs with same output size and input size, hence their
// GIM_CheckPointerToAny *should* be merged
def S0 : Register<"s0"> { let Namespace = "MyTarget"; }
def GPR16 : RegisterClass<"MyTarget", [i16], 16, (add S0)>;
def LOAD16 : I<(outs GPR16:$dst), (ins GPR16:$src), []>;
def LOAD16Imm : I<(outs GPR16:$dst), (ins GPR16:$src), []>;
// CHECK: // Label 2: @{{[0-9]+}}
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L1_ID:[0-9]+]]*/ GIMT_Encode4([[L1_AT:[0-9]+]]),
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::GPR16RegClassID),
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/16,
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L2_ID:[0-9]+]]*/ GIMT_Encode4([[L2_AT:[0-9]+]]),
// CHECK-NEXT: GIM_RecordInsn, /*DefineMI*/1, /*MI*/0, /*OpIdx*/1, // MIs[1]
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/1, GIMT_Encode2(TargetOpcode::G_ADD),
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s16,
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/2, /*Type*/GILLT_s16,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16RegClassID),
// CHECK-NEXT: GIM_CheckConstantInt8, /*MI*/1, /*Op*/2, 10,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (ld:{ *:[i16] } (add:{ *:[i16] } GPR16:{ *:[i16] }:$src, 10:{ *:[i16] }))<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD16Imm:{ *:[i16] } GPR16:{ *:[i16] }:$src)
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16Imm),
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // DstI[dst]
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/1, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_MergeMemOperands, /*InsnID*/0, /*NumInsns*/2, /*MergeInsnID's*/0, 1,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: // GIR_Coverage, 3,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label [[L2_ID]]: @[[L2_AT]]
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[L3_ID:[0-9]+]]*/ GIMT_Encode4([[L3_AT:[0-9]+]]),
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::GPR16RegClassID),
// CHECK-NEXT: // (ld:{ *:[i16] } GPR16:{ *:[i16] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD16:{ *:[i16] } GPR16:{ *:[i16] }:$src)
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::LOAD16),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
// CHECK-NEXT: // GIR_Coverage, 2,
// CHECK-NEXT: GIR_Done,
// CHECK-NEXT: // Label [[L3_ID]]: @[[L3_AT]]
// CHECK-NEXT: GIM_Reject,
// CHECK-NEXT: // Label [[L1_ID]]: @[[L1_AT]]
def : Pat<(i16 (load GPR16:$src)),
(LOAD16 GPR16:$src)>;
def : Pat<(i16 (load (add GPR16:$src, 10))),
(LOAD16Imm GPR16:$src)>;