[llvm] [WIP][TableGen][GISel] Learn to import patterns with optional/physreg defs (PR #120343)
Sergei Barannikov via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 17 17:37:24 PST 2024
https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/120343
>From 70dedcfce717d2e87ce2b9b8dd8732e487f3ebc8 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Tue, 17 Dec 2024 19:39:15 +0300
Subject: [PATCH] [TableGen][GISel] Learn to import patterns with
optional/physreg defs
---
.../Target/GlobalISel/SelectionDAGCompat.td | 2 +
.../test/CodeGen/X86/GlobalISel/mul-scalar.ll | 9 +-
.../select-intrinsic-x86-flags-read-u32.mir | 2 +-
.../Common/GlobalISelEmitterCommon.td | 3 +-
.../GlobalISelEmitter-implicit-defs.td | 62 ++++-
.../GlobalISelEmitter-nested-subregs.td | 2 +-
.../TableGen/GlobalISelEmitterRegSequence.td | 2 +-
llvm/test/TableGen/GlobalISelEmitterSubreg.td | 8 +-
.../TableGen/Common/CodeGenRegisters.cpp | 2 +-
llvm/utils/TableGen/Common/CodeGenRegisters.h | 2 +-
.../GlobalISel/GlobalISelMatchTable.cpp | 3 +-
.../Common/GlobalISel/GlobalISelMatchTable.h | 6 +-
llvm/utils/TableGen/GlobalISelEmitter.cpp | 236 +++++++++---------
13 files changed, 195 insertions(+), 144 deletions(-)
diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
index 2148f5be4c41aa..c8c0eeb57099a2 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -70,6 +70,8 @@ def : GINodeEquiv<G_SDIV, sdiv>;
def : GINodeEquiv<G_UDIV, udiv>;
def : GINodeEquiv<G_SREM, srem>;
def : GINodeEquiv<G_UREM, urem>;
+def : GINodeEquiv<G_SDIVREM, sdivrem>;
+def : GINodeEquiv<G_UDIVREM, udivrem>;
def : GINodeEquiv<G_AND, and>;
def : GINodeEquiv<G_OR, or>;
def : GINodeEquiv<G_XOR, xor>;
diff --git a/llvm/test/CodeGen/X86/GlobalISel/mul-scalar.ll b/llvm/test/CodeGen/X86/GlobalISel/mul-scalar.ll
index f401f45a06f6a7..3196668c70d8ec 100644
--- a/llvm/test/CodeGen/X86/GlobalISel/mul-scalar.ll
+++ b/llvm/test/CodeGen/X86/GlobalISel/mul-scalar.ll
@@ -5,16 +5,17 @@
define i8 @test_mul_i8(i8 %arg1, i8 %arg2) nounwind {
; X64-LABEL: test_mul_i8:
; X64: # %bb.0:
-; X64-NEXT: movsbl %dil, %eax
-; X64-NEXT: imulb %sil
+; X64-NEXT: movl %edi, %eax
+; X64-NEXT: # kill: def $al killed $al killed $eax
+; X64-NEXT: mulb %sil
; X64-NEXT: retq
;
; X86-LABEL: test_mul_i8:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
-; X86-NEXT: cbtw
-; X86-NEXT: imulb %cl
+; X86-NEXT: # kill: def $al killed $al killed $eax
+; X86-NEXT: mulb %cl
; X86-NEXT: retl
%ret = mul i8 %arg1, %arg2
ret i8 %ret
diff --git a/llvm/test/CodeGen/X86/GlobalISel/select-intrinsic-x86-flags-read-u32.mir b/llvm/test/CodeGen/X86/GlobalISel/select-intrinsic-x86-flags-read-u32.mir
index 332ec2240c5b60..3d1857a274b4b2 100644
--- a/llvm/test/CodeGen/X86/GlobalISel/select-intrinsic-x86-flags-read-u32.mir
+++ b/llvm/test/CodeGen/X86/GlobalISel/select-intrinsic-x86-flags-read-u32.mir
@@ -9,7 +9,7 @@
define void @read_flags() { ret void }
; CHECK-LABEL: name: read_flags
; CHECK: bb.0:
- ; CHECK: [[RDFLAGS32_:%[0-9]+]]:gr32 = RDFLAGS32 implicit-def $esp, implicit $esp
+ ; CHECK: [[RDFLAGS32_:%[0-9]+]]:gr32 = RDFLAGS32 implicit-def dead $esp, implicit $esp
; CHECK: $eax = COPY [[RDFLAGS32_]]
...
diff --git a/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td b/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
index 8f11fee3751844..cfcaf3c76bbf8a 100644
--- a/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
+++ b/llvm/test/TableGen/Common/GlobalISelEmitterCommon.td
@@ -7,7 +7,8 @@ class MyTargetGenericInstruction : GenericInstruction {
}
def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
-def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0)>;
+def R1 : Register<"r0"> { let Namespace = "MyTarget"; }
+def GPR32 : RegisterClass<"MyTarget", [i32], 32, (add R0, R1)>;
def GPR32Op : RegisterOperand<GPR32>;
def F0 : Register<"f0"> { let Namespace = "MyTarget"; }
def FPR32 : RegisterClass<"MyTarget", [f32], 32, (add F0)>;
diff --git a/llvm/test/TableGen/GlobalISelEmitter-implicit-defs.td b/llvm/test/TableGen/GlobalISelEmitter-implicit-defs.td
index 79af1a336f2890..ebf290a27b13ed 100644
--- a/llvm/test/TableGen/GlobalISelEmitter-implicit-defs.td
+++ b/llvm/test/TableGen/GlobalISelEmitter-implicit-defs.td
@@ -1,12 +1,60 @@
-// RUN: llvm-tblgen -gen-global-isel -warn-on-skipped-patterns -I %p/../../include -I %p/Common %s -o /dev/null 2>&1 < %s | FileCheck %s --implicit-check-not="Skipped pattern"
+// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common %s | FileCheck %s
include "llvm/Target/Target.td"
include "GlobalISelEmitterCommon.td"
-// CHECK: Skipped pattern: Pattern defines a physical register
-let Uses = [B0], Defs = [B0] in
-def tst1 : I<(outs), (ins), [(set B0, (add B0, 1))]>;
+let Defs = [R0, R1] in
+def tst1 : I<(outs), (ins), [(set R0, (get_fpenv))]>;
-// CHECK: Skipped pattern: Src pattern result has 1 def(s) without the HasNoUse predicate set to true but Dst MI has no def
-let Uses = [B0] in
-def tst2 : I<(outs), (ins), [(set B0, (add B0, 1))]>;
+let Defs = [R0, R1] in
+def tst2 : I<(outs GPR32:$rd), (ins GPR32:$rs1, GPR32:$rs2),
+ [(set GPR32:$rd, R0, (udivrem i32:$rs1, i32:$rs2))]>;
+
+def : Pat<(sdiv i32:$rs1, i32:$rs2), (tst2 $rs1, $rs2)>;
+def : Pat<(sdivrem i32:$rs1, i32:$rs2), (tst2 $rs1, $rs2)>;
+
+// CHECK-LABEL: // (sdiv:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2) => (tst2:{ *:[i32] }:{ *:[i32] } ?:{ *:[i32] }:$rs1, ?:{ *:[i32] }:$rs2)
+// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::tst2),
+// CHECK-NEXT: GIR_AddImplicitDef, /*InsnID*/0, GIMT_Encode2(MyTarget::R0), GIMT_Encode2(RegState::Dead),
+// CHECK-NEXT: GIR_AddImplicitDef, /*InsnID*/0, GIMT_Encode2(MyTarget::R1), GIMT_Encode2(RegState::Dead),
+// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT: // GIR_Coverage, 2,
+
+// CHECK-LABEL: // (sdivrem:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2) => (tst2:{ *:[i32] }:{ *:[i32] } ?:{ *:[i32] }:$rs1, ?:{ *:[i32] }:$rs2)
+// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::tst2),
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[rd]
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/2, // rs1
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/3, // rs2
+// CHECK-NEXT: GIR_SetImplicitDefDead, /*InsnID*/0, /*OpIdx for MyTarget::R1*/1,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // DstI[R0]
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::R0), /*AddRegisterRegFlags*/GIMT_Encode2(0),
+// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/0, GIMT_Encode2(MyTarget::GPR32RegClassID),
+// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT: // GIR_Coverage, 3,
+// CHECK-NEXT: GIR_EraseRootFromParent_Done,
+
+// CHECK-LABEL: // (udivrem:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2) => (tst2:{ *:[i32] }:{ *:[i32] } i32:{ *:[i32] }:$rs1, i32:{ *:[i32] }:$rs2)
+// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::tst2),
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/0, // DstI[rd]
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/2, // rs1
+// CHECK-NEXT: GIR_RootToRootCopy, /*OpIdx*/3, // rs2
+// CHECK-NEXT: GIR_SetImplicitDefDead, /*InsnID*/0, /*OpIdx for MyTarget::R1*/1,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // DstI[R0]
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::R0), /*AddRegisterRegFlags*/GIMT_Encode2(0),
+// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/0, GIMT_Encode2(MyTarget::GPR32RegClassID),
+// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT: // GIR_Coverage, 1,
+// CHECK-NEXT: GIR_EraseRootFromParent_Done,
+
+// CHECK-LABEL: // (get_fpenv:{ *:[i32] }) => (tst1:{ *:[i32] })
+// CHECK-NEXT: GIR_BuildRootMI, /*Opcode*/GIMT_Encode2(MyTarget::tst1),
+// CHECK-NEXT: GIR_SetImplicitDefDead, /*InsnID*/0, /*OpIdx for MyTarget::R1*/1,
+// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
+// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // DstI[R0]
+// CHECK-NEXT: GIR_AddRegister, /*InsnID*/1, GIMT_Encode2(MyTarget::R0), /*AddRegisterRegFlags*/GIMT_Encode2(0),
+// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/0, GIMT_Encode2(MyTarget::GPR32RegClassID),
+// CHECK-NEXT: GIR_RootConstrainSelectedInstOperands,
+// CHECK-NEXT: // GIR_Coverage, 0,
+// CHECK-NEXT: GIR_EraseRootFromParent_Done,
diff --git a/llvm/test/TableGen/GlobalISelEmitter-nested-subregs.td b/llvm/test/TableGen/GlobalISelEmitter-nested-subregs.td
index 1fdb973c1f1ec7..79e55ef2e8b8ce 100644
--- a/llvm/test/TableGen/GlobalISelEmitter-nested-subregs.td
+++ b/llvm/test/TableGen/GlobalISelEmitter-nested-subregs.td
@@ -38,11 +38,11 @@ def A0 : RegisterClass<"MyTarget", [i32], 32, (add a0)>;
// CHECK-NEXT: // MIs[0] src
// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s8,
// CHECK-NEXT: // (anyext:{ *:[i16] } i8:{ *:[i8] }:$src) => (EXTRACT_SUBREG:{ *:[i16] } (INSERT_SUBREG:{ *:[i32] } (IMPLICIT_DEF:{ *:[i32] }), A0b:{ *:[i8] }:$src, lo8:{ *:[i32] }), lo16:{ *:[i32] })
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(TargetOpcode::IMPLICIT_DEF),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::INSERT_SUBREG),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_AddSimpleTempRegister, /*InsnID*/1, /*TempRegID*/1,
diff --git a/llvm/test/TableGen/GlobalISelEmitterRegSequence.td b/llvm/test/TableGen/GlobalISelEmitterRegSequence.td
index 3829070b28efeb..69f82eac49c161 100644
--- a/llvm/test/TableGen/GlobalISelEmitterRegSequence.td
+++ b/llvm/test/TableGen/GlobalISelEmitterRegSequence.td
@@ -39,12 +39,12 @@ def SUBSOME_INSN : I<(outs SRegs:$dst), (ins SOP:$src), []>;
// CHECK-NEXT: GIM_RootCheckType, /*Op*/1, /*Type*/GILLT_s16,
// CHECK-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(Test::SRegsRegClassID),
// CHECK-NEXT: // (sext:{ *:[i32] } SOP:{ *:[i16] }:$src) => (REG_SEQUENCE:{ *:[i32] } DRegs:{ *:[i32] }, (SUBSOME_INSN:{ *:[i16] } SOP:{ *:[i16] }:$src), sub0:{ *:[i32] }, (SUBSOME_INSN:{ *:[i16] } SOP:{ *:[i16] }:$src), sub1:{ *:[i32] })
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(MyTarget::SUBSOME_INSN),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(MyTarget::SUBSOME_INSN),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src
diff --git a/llvm/test/TableGen/GlobalISelEmitterSubreg.td b/llvm/test/TableGen/GlobalISelEmitterSubreg.td
index 8df3238f6cc21e..08e690f3e894de 100644
--- a/llvm/test/TableGen/GlobalISelEmitterSubreg.td
+++ b/llvm/test/TableGen/GlobalISelEmitterSubreg.td
@@ -59,13 +59,13 @@ def : Pat<(sub (complex DOP:$src1, DOP:$src2), 77),
(SOME_INSN2 (EXTRACT_SUBREG DOP:$src1, sub0),
(EXTRACT_SUBREG DOP:$src2, sub1))>;
// CHECK-LABEL: // (sub:{ *:[i32] } (complex:{ *:[i32] } DOP:{ *:[i32] }:$src1, DOP:{ *:[i32] }:$src2), 77:{ *:[i32] }) => (SOME_INSN2:{ *:[i32] } (EXTRACT_SUBREG:{ *:[i32] } DOP:{ *:[i32] }:$src1, sub0:{ *:[i32] }), (EXTRACT_SUBREG:{ *:[i32] } DOP:{ *:[i32] }:$src2, sub1:{ *:[i32] }))
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_ComplexSubOperandSubRegRenderer, /*InsnID*/2, /*RendererID*/GIMT_Encode2(0), /*SubOperand*/1, /*SubRegIdx*/GIMT_Encode2(2), // src2
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/2, /*Op*/0, GIMT_Encode2(Test::SRegsRegClassID),
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/2, /*Op*/1, GIMT_Encode2(Test::DRegsRegClassID),
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_ComplexSubOperandSubRegRenderer, /*InsnID*/1, /*RendererID*/GIMT_Encode2(0), /*SubOperand*/0, /*SubRegIdx*/GIMT_Encode2(1), // src1
@@ -103,11 +103,11 @@ def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), SOP:$src
// instruction.
def : Pat<(i32 (anyext i16:$src)), (SOME_INSN (INSERT_SUBREG (i32 (IMPLICIT_DEF)), SOP:$src, sub0))>;
// CHECK-LABEL: (anyext:{ *:[i32] } i16:{ *:[i16] }:$src) => (SOME_INSN:{ *:[i32] } (INSERT_SUBREG:{ *:[i32] } (IMPLICIT_DEF:{ *:[i32] }), SOP:{ *:[i16] }:$src, sub0:{ *:[i32] }))
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(TargetOpcode::IMPLICIT_DEF),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::INSERT_SUBREG),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_AddSimpleTempRegister, /*InsnID*/1, /*TempRegID*/1,
@@ -138,12 +138,12 @@ def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (COPY_TO_REGCLASS SOP:$sr
// by a subinstruction.
def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), (SUBSOME_INSN SOP:$src), sub0)>;
// CHECK-LABEL: (anyext:{ *:[i32] } i16:{ *:[i16] }:$src) => (INSERT_SUBREG:{ *:[i32] } (IMPLICIT_DEF:{ *:[i32] }), (SUBSOME_INSN:{ *:[i16] } SOP:{ *:[i16] }:$src), sub0:{ *:[i32] })
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(MyTarget::SUBSOME_INSN),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::IMPLICIT_DEF),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
@@ -200,12 +200,12 @@ def : Pat<(i16 (trunc (bitreverse DOP:$src))),
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/GIMT_Encode2(Test::DRegsRegClassID),
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*NumInsns*/1,
// CHECK-NEXT: // (trunc:{ *:[i16] } (ctpop:{ *:[i32] } DOP:{ *:[i32] }:$src)) => (SUBSOME_INSN2:{ *:[i16] } (EXTRACT_SUBREG:{ *:[i16] } (SOME_INSN:{ *:[i32] } DOP:{ *:[i32] }:$src), sub0:{ *:[i32] }))
-// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/2, /*Opcode*/GIMT_Encode2(MyTarget::SOME_INSN),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/1, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
+// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/GIMT_Encode2(TargetOpcode::COPY),
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/GIMT_Encode2(RegState::Define),
// CHECK-NEXT: GIR_AddTempSubRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/GIMT_Encode2(0), GIMT_Encode2(sub0),
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
index 2dbee94d7e5406..011d11184c70c7 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.cpp
@@ -2494,7 +2494,7 @@ CodeGenRegBank::getRegClassForRegister(const Record *R) {
const CodeGenRegisterClass *
CodeGenRegBank::getMinimalPhysRegClass(const Record *RegRecord,
- ValueTypeByHwMode *VT) {
+ const ValueTypeByHwMode *VT) {
const CodeGenRegister *Reg = getReg(RegRecord);
const CodeGenRegisterClass *BestRC = nullptr;
for (const auto &RC : getRegClasses()) {
diff --git a/llvm/utils/TableGen/Common/CodeGenRegisters.h b/llvm/utils/TableGen/Common/CodeGenRegisters.h
index 2fa6cab2afb892..90489cae6164ba 100644
--- a/llvm/utils/TableGen/Common/CodeGenRegisters.h
+++ b/llvm/utils/TableGen/Common/CodeGenRegisters.h
@@ -792,7 +792,7 @@ class CodeGenRegBank {
// with a matching type
const CodeGenRegisterClass *
getMinimalPhysRegClass(const Record *RegRecord,
- ValueTypeByHwMode *VT = nullptr);
+ const ValueTypeByHwMode *VT = nullptr);
// Get the sum of unit weights.
unsigned getRegUnitSetWeight(const std::vector<unsigned> &Units) const {
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
index 15ec7e17130de4..6039211bc6cf00 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.cpp
@@ -1994,7 +1994,8 @@ void AddRegisterRenderer::emitRenderOpcodes(MatchTable &Table,
// really needed for a physical register reference. We can pack the
// register and flags in a single field.
if (IsDef)
- Table << MatchTable::NamedValue(2, "RegState::Define");
+ Table << MatchTable::NamedValue(
+ 2, IsDead ? "RegState::Define | RegState::Dead" : "RegState::Define");
else
Table << MatchTable::IntValue(2, 0);
Table << MatchTable::LineBreak;
diff --git a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
index 00fe073057c5c9..48ce71be677c08 100644
--- a/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
+++ b/llvm/utils/TableGen/Common/GlobalISel/GlobalISelMatchTable.h
@@ -2091,13 +2091,15 @@ class AddRegisterRenderer : public OperandRenderer {
unsigned InsnID;
const Record *RegisterDef;
bool IsDef;
+ bool IsDead;
const CodeGenTarget &Target;
public:
AddRegisterRenderer(unsigned InsnID, const CodeGenTarget &Target,
- const Record *RegisterDef, bool IsDef = false)
+ const Record *RegisterDef, bool IsDef = false,
+ bool IsDead = false)
: OperandRenderer(OR_Register), InsnID(InsnID), RegisterDef(RegisterDef),
- IsDef(IsDef), Target(Target) {}
+ IsDef(IsDef), IsDead(IsDead), Target(Target) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_Register;
diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp
index 83599e789e10b9..9ac397548f0b9b 100644
--- a/llvm/utils/TableGen/GlobalISelEmitter.cpp
+++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp
@@ -324,8 +324,6 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
void emitTestSimplePredicate(raw_ostream &OS) override;
void emitRunCustomAction(raw_ostream &OS) override;
- void postProcessRule(RuleMatcher &M);
-
const CodeGenTarget &getTarget() const override { return Target; }
StringRef getClassName() const override { return ClassName; }
@@ -384,44 +382,41 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter {
Error importRulePredicates(RuleMatcher &M,
ArrayRef<const Record *> Predicates);
- Expected<InstructionMatcher &>
- createAndImportSelDAGMatcher(RuleMatcher &Rule,
- InstructionMatcher &InsnMatcher,
- const TreePatternNode &Src, unsigned &TempOpIdx);
+ Expected<InstructionMatcher &> createAndImportSelDAGMatcher(
+ RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ const PatternToMatch &P, const TreePatternNode &Src, unsigned &TempOpIdx);
Error importComplexPatternOperandMatcher(OperandMatcher &OM, const Record *R,
unsigned &TempOpIdx) const;
Error importChildMatcher(RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ const PatternToMatch &P,
const TreePatternNode &SrcChild,
bool OperandIsAPointer, bool OperandIsImmArg,
unsigned OpIdx, unsigned &TempOpIdx);
Expected<BuildMIAction &> createAndImportInstructionRenderer(
- RuleMatcher &M, InstructionMatcher &InsnMatcher,
+ RuleMatcher &M, InstructionMatcher &InsnMatcher, const PatternToMatch &P,
const TreePatternNode &Src, const TreePatternNode &Dst);
Expected<action_iterator> createAndImportSubInstructionRenderer(
- action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst,
- const TreePatternNode &Src, unsigned TempReg);
+ action_iterator InsertPt, RuleMatcher &M, const PatternToMatch &P,
+ const TreePatternNode &Dst, unsigned TempReg);
Expected<action_iterator>
createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M,
const TreePatternNode &Dst);
Expected<action_iterator>
- importExplicitDefRenderers(action_iterator InsertPt, RuleMatcher &M,
- BuildMIAction &DstMIBuilder,
- const TreePatternNode &Src,
- const TreePatternNode &Dst, unsigned Start = 0);
+ importDefRenderers(action_iterator InsertPt, RuleMatcher &M,
+ BuildMIAction &DstMIBuilder, const PatternToMatch &P,
+ const TreePatternNode &Dst, unsigned Start = 0);
Expected<action_iterator> importExplicitUseRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- const llvm::TreePatternNode &Dst, const TreePatternNode &Src);
+ const PatternToMatch &P, const TreePatternNode &Dst);
Expected<action_iterator> importExplicitUseRenderer(
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
- const TreePatternNode &DstChild, const TreePatternNode &Src);
+ const PatternToMatch &P, const TreePatternNode &DstChild);
Error importDefaultOperandRenderers(action_iterator InsertPt, RuleMatcher &M,
BuildMIAction &DstMIBuilder,
const DAGDefaultOperand &DefaultOp) const;
- Error importImplicitDefRenderers(BuildMIAction &DstMIBuilder,
- ArrayRef<const Record *> ImplicitDefs) const;
/// Analyze pattern \p P, returning a matcher for it if possible.
/// Otherwise, return an Error explaining why we don't support it.
@@ -725,7 +720,7 @@ Expected<InstructionMatcher &> GlobalISelEmitter::addBuiltinPredicates(
}
Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
- RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const PatternToMatch &P,
const TreePatternNode &Src, unsigned &TempOpIdx) {
const auto SavedFlags = Rule.setGISelFlags(Src.getGISelFlagsRecord());
@@ -925,9 +920,9 @@ Expected<InstructionMatcher &> GlobalISelEmitter::createAndImportSelDAGMatcher(
OperandIsImmArg |= II->isParamImmArg(I - 1);
}
- if (auto Error =
- importChildMatcher(Rule, InsnMatcher, SrcChild, OperandIsAPointer,
- OperandIsImmArg, OpIdx++, TempOpIdx))
+ if (auto Error = importChildMatcher(Rule, InsnMatcher, P, SrcChild,
+ OperandIsAPointer, OperandIsImmArg,
+ OpIdx++, TempOpIdx))
return std::move(Error);
}
}
@@ -966,7 +961,7 @@ static StringRef getSrcChildName(const TreePatternNode &SrcChild,
}
Error GlobalISelEmitter::importChildMatcher(
- RuleMatcher &Rule, InstructionMatcher &InsnMatcher,
+ RuleMatcher &Rule, InstructionMatcher &InsnMatcher, const PatternToMatch &P,
const TreePatternNode &SrcChild, bool OperandIsAPointer,
bool OperandIsImmArg, unsigned OpIdx, unsigned &TempOpIdx) {
@@ -1087,7 +1082,7 @@ Error GlobalISelEmitter::importChildMatcher(
// Map the node to a gMIR instruction.
InstructionOperandMatcher &InsnOperand = **MaybeInsnOperand;
auto InsnMatcherOrError = createAndImportSelDAGMatcher(
- Rule, InsnOperand.getInsnMatcher(), SrcChild, TempOpIdx);
+ Rule, InsnOperand.getInsnMatcher(), P, SrcChild, TempOpIdx);
if (auto Error = InsnMatcherOrError.takeError())
return Error;
@@ -1178,8 +1173,8 @@ Error GlobalISelEmitter::importChildMatcher(
// has to succeed.
OperandMatcher &OM =
InsnOperand.getInsnMatcher().addOperand(0, "", TempOpIdx);
- if (auto Error =
- OM.addTypeCheckPredicate(TypeSetByHwMode(VTy), false /* OperandIsAPointer */))
+ if (auto Error = OM.addTypeCheckPredicate(TypeSetByHwMode(VTy),
+ false /* OperandIsAPointer */))
return failedImport(toString(std::move(Error)) +
" for result of Src pattern operator");
@@ -1198,7 +1193,7 @@ Error GlobalISelEmitter::importChildMatcher(
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
action_iterator InsertPt, RuleMatcher &Rule, BuildMIAction &DstMIBuilder,
- const TreePatternNode &DstChild, const TreePatternNode &Src) {
+ const PatternToMatch &P, const TreePatternNode &DstChild) {
const auto &SubOperand = Rule.getComplexSubOperand(DstChild.getName());
if (SubOperand) {
@@ -1274,7 +1269,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
auto InsertPtOrError = createAndImportSubInstructionRenderer(
- ++InsertPt, Rule, DstChild, Src, TempRegID);
+ ++InsertPt, Rule, P, DstChild, TempRegID);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
return InsertPtOrError.get();
@@ -1362,8 +1357,8 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
}
Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
- RuleMatcher &M, InstructionMatcher &InsnMatcher, const TreePatternNode &Src,
- const TreePatternNode &Dst) {
+ RuleMatcher &M, InstructionMatcher &InsnMatcher, const PatternToMatch &P,
+ const TreePatternNode &Src, const TreePatternNode &Dst) {
auto InsertPtOrError = createInstructionRenderer(M.actions_end(), M, Dst);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -1383,13 +1378,11 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
}
if (auto Error =
- importExplicitDefRenderers(InsertPt, M, DstMIBuilder, Src, Dst)
- .takeError())
+ importDefRenderers(InsertPt, M, DstMIBuilder, P, Dst).takeError())
return std::move(Error);
- if (auto Error =
- importExplicitUseRenderers(InsertPt, M, DstMIBuilder, Dst, Src)
- .takeError())
+ if (auto Error = importExplicitUseRenderers(InsertPt, M, DstMIBuilder, P, Dst)
+ .takeError())
return std::move(Error);
return DstMIBuilder;
@@ -1397,8 +1390,8 @@ Expected<BuildMIAction &> GlobalISelEmitter::createAndImportInstructionRenderer(
Expected<action_iterator>
GlobalISelEmitter::createAndImportSubInstructionRenderer(
- const action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst,
- const TreePatternNode &Src, unsigned TempRegID) {
+ const action_iterator InsertPt, RuleMatcher &M, const PatternToMatch &P,
+ const TreePatternNode &Dst, unsigned TempRegID) {
auto InsertPtOrError = createInstructionRenderer(InsertPt, M, Dst);
// TODO: Assert there's exactly one result.
@@ -1413,15 +1406,13 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true);
// Handle additional (ignored) results.
- if (DstMIBuilder.getCGI()->Operands.NumDefs > 1) {
- InsertPtOrError = importExplicitDefRenderers(
- std::prev(*InsertPtOrError), M, DstMIBuilder, Src, Dst, /*Start=*/1);
- if (auto Error = InsertPtOrError.takeError())
- return std::move(Error);
- }
+ InsertPtOrError = importDefRenderers(std::prev(*InsertPtOrError), M,
+ DstMIBuilder, P, Dst, /*Start=*/1);
+ if (auto Error = InsertPtOrError.takeError())
+ return std::move(Error);
InsertPtOrError = importExplicitUseRenderers(InsertPtOrError.get(), M,
- DstMIBuilder, Dst, Src);
+ DstMIBuilder, P, Dst);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -1453,29 +1444,39 @@ Expected<action_iterator> GlobalISelEmitter::createInstructionRenderer(
DstI);
}
-Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
+Expected<action_iterator> GlobalISelEmitter::importDefRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- const TreePatternNode &Src, const TreePatternNode &Dst, unsigned Start) {
+ const PatternToMatch &P, const TreePatternNode &Dst, unsigned Start) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
- const unsigned SrcNumDefs = Src.getExtTypes().size();
- const unsigned DstNumDefs = DstI->Operands.NumDefs;
- if (DstNumDefs == 0)
- return InsertPt;
-
- for (unsigned I = Start; I < SrcNumDefs; ++I) {
- std::string OpName = getMangledRootDefName(DstI->Operands[I].Name);
- // CopyRenderer saves a StringRef, so cannot pass OpName itself -
- // let's use a string with an appropriate lifetime.
- StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
- DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
- }
+ const unsigned DstExpDefs = DstI->Operands.NumDefs;
+ const unsigned DstNumDefs = DstExpDefs + DstI->ImplicitDefs.size();
+ bool IsRoot = &Dst == &P.getDstPattern();
+
+ unsigned I = Start;
+ for (; I < DstExpDefs; ++I) {
+ const CGIOperandList::OperandInfo &OpInfo = DstI->Operands[I];
+ std::string OpName = getMangledRootDefName(OpInfo.Name);
+
+ if (M.hasOperand(OpName)) {
+ // CopyRenderer saves a StringRef, so cannot pass OpName itself -
+ // let's use a string with an appropriate lifetime.
+ StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
+ DstMIBuilder.addRenderer<CopyRenderer>(PermanentRef);
+ continue;
+ }
- // Some instructions have multiple defs, but are missing a type entry
- // (e.g. s_cc_out operands).
- if (Dst.getExtTypes().size() < DstNumDefs)
- return failedImport("unhandled discarded def");
+ if (OpInfo.Rec->isSubClassOf("OptionalDefOperand")) {
+ const DAGDefaultOperand &ComplexOp = CGP.getDefaultOperand(OpInfo.Rec);
+ for (const TreePatternNode &SubOp :
+ make_pointee_range(ComplexOp.DefaultOps)) {
+ const Record *Reg = cast<DefInit>(SubOp.getLeafValue())->getDef();
+ assert(Reg->isSubClassOf("Register"));
+ DstMIBuilder.addRenderer<AddRegisterRenderer>(
+ Target, Reg, /*IsDef=*/true, /*IsDead=*/true);
+ }
+ continue;
+ }
- for (unsigned I = SrcNumDefs; I < DstNumDefs; ++I) {
const TypeSetByHwMode &ExtTy = Dst.getExtType(I);
if (!ExtTy.isMachineValueType())
return failedImport("unsupported typeset");
@@ -1487,7 +1488,30 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
unsigned TempRegID = M.allocateTempRegID();
InsertPt =
M.insertAction<MakeTempRegisterAction>(InsertPt, *OpTy, TempRegID);
- DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, true, nullptr, true);
+ DstMIBuilder.addRenderer<TempRegRenderer>(
+ TempRegID, /*IsDef=*/true, /*SubReg=*/nullptr, /*IsDead=*/true);
+ }
+
+ for (; I < DstNumDefs; ++I) {
+ const Record *Reg = DstI->ImplicitDefs[I - DstExpDefs];
+ std::string OpName = getMangledRootDefName(Reg->getName());
+
+ if (!IsRoot || !M.hasOperand(OpName)) {
+ DstMIBuilder.setDeadImplicitDef(Reg);
+ continue;
+ }
+
+ BuildMIAction &CopyBuilder = M.addAction<BuildMIAction>(
+ M.allocateOutputInsnID(), &Target.getInstruction(RK.getDef("COPY")));
+
+ StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName();
+ CopyBuilder.addRenderer<CopyRenderer>(PermanentRef);
+ CopyBuilder.addRenderer<AddRegisterRenderer>(Target, Reg);
+
+ const CodeGenRegisterClass *RC = CGRegs.getRegClassForRegister(Reg);
+ assert(RC);
+ M.addAction<ConstrainOperandToRegClassAction>(CopyBuilder.getInsnID(),
+ /*OpIdx=*/0, *RC);
}
return InsertPt;
@@ -1495,7 +1519,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitDefRenderers(
Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder,
- const llvm::TreePatternNode &Dst, const llvm::TreePatternNode &Src) {
+ const PatternToMatch &P, const TreePatternNode &Dst) {
const CodeGenInstruction *DstI = DstMIBuilder.getCGI();
CodeGenInstruction *OrigDstI = &Target.getInstruction(Dst.getOperator());
@@ -1525,7 +1549,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
TempRegID);
auto InsertPtOrError = createAndImportSubInstructionRenderer(
- ++InsertPt, M, ValChild, Src, TempRegID);
+ ++InsertPt, M, P, ValChild, TempRegID);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
@@ -1583,7 +1607,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
auto InsertPtOrError =
- importExplicitUseRenderer(InsertPt, M, DstMIBuilder, ValChild, Src);
+ importExplicitUseRenderer(InsertPt, M, DstMIBuilder, P, ValChild);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
InsertPt = InsertPtOrError.get();
@@ -1652,7 +1676,7 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
}
auto InsertPtOrError = importExplicitUseRenderer(InsertPt, M, DstMIBuilder,
- Dst.getChild(Child), Src);
+ P, Dst.getChild(Child));
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
InsertPt = InsertPtOrError.get();
@@ -1710,13 +1734,6 @@ Error GlobalISelEmitter::importDefaultOperandRenderers(
return Error::success();
}
-Error GlobalISelEmitter::importImplicitDefRenderers(
- BuildMIAction &DstMIBuilder, ArrayRef<const Record *> ImplicitDefs) const {
- if (!ImplicitDefs.empty())
- return failedImport("Pattern defines a physical register");
- return Error::success();
-}
-
Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt,
RuleMatcher &M, unsigned InsnID,
const TreePatternNode &Dst) {
@@ -2042,7 +2059,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
const auto SavedFlags = M.setGISelFlags(P.getSrcRecord());
auto InsnMatcherOrError =
- createAndImportSelDAGMatcher(M, InsnMatcherTemp, Src, TempOpIdx);
+ createAndImportSelDAGMatcher(M, InsnMatcherTemp, P, Src, TempOpIdx);
if (auto Error = InsnMatcherOrError.takeError())
return std::move(Error);
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();
@@ -2093,13 +2110,14 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
unsigned DstExpDefs = DstI.Operands.NumDefs,
DstNumDefs = DstI.ImplicitDefs.size() + DstExpDefs,
SrcNumDefs = Src.getExtTypes().size();
+
+ bool FoundNoUsePred = false;
if (DstNumDefs < SrcNumDefs) {
if (DstNumDefs != 0)
return failedImport("Src pattern result has more defs than dst MI (" +
to_string(SrcNumDefs) + " def(s) vs " +
to_string(DstNumDefs) + " def(s))");
- bool FoundNoUsePred = false;
for (const auto &Pred : InsnMatcher.predicates()) {
if ((FoundNoUsePred = isa<NoUsePredicateMatcher>(Pred.get())))
break;
@@ -2112,15 +2130,24 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// The root of the match also has constraints on the register bank so that it
// matches the result instruction.
- unsigned N = std::min(DstExpDefs, SrcNumDefs);
- for (unsigned I = 0; I < N; ++I) {
- const auto &DstIOperand = DstI.Operands[I];
+ for (unsigned I = 0; I < SrcNumDefs; ++I) {
+ if (FoundNoUsePred)
+ continue;
OperandMatcher &OM = InsnMatcher.getOperand(I);
+
+ if (I >= DstExpDefs) {
+ const Record *Reg = DstI.ImplicitDefs[I - DstExpDefs];
+ OM.setSymbolicName(getMangledRootDefName(Reg->getName()));
+ M.defineOperand(OM.getSymbolicName(), OM);
+ continue;
+ }
+
// The operand names declared in the DstI instruction are unrelated to
// those used in pattern's source and destination DAGs, so mangle the
// former to prevent implicitly adding unexpected
// GIM_CheckIsSameOperand predicates by the defineOperand method.
+ const CGIOperandList::OperandInfo &DstIOperand = DstI.Operands[I];
OM.setSymbolicName(getMangledRootDefName(DstIOperand.Name));
M.defineOperand(OM.getSymbolicName(), OM);
@@ -2133,16 +2160,11 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
}
auto DstMIBuilderOrError =
- createAndImportInstructionRenderer(M, InsnMatcher, Src, Dst);
+ createAndImportInstructionRenderer(M, InsnMatcher, P, Src, Dst);
if (auto Error = DstMIBuilderOrError.takeError())
return std::move(Error);
BuildMIAction &DstMIBuilder = DstMIBuilderOrError.get();
- // Render the implicit defs.
- // These are only added to the root of the result.
- if (auto Error = importImplicitDefRenderers(DstMIBuilder, P.getDstRegs()))
- return std::move(Error);
-
DstMIBuilder.chooseInsnToMutate(M);
// Constrain the registers to classes. This is normally derived from the
@@ -2179,15 +2201,15 @@ GlobalISelEmitter::buildMatchTable(MutableArrayRef<RuleMatcher> Rules,
OpcodeOrder[Opcode] = CurrentOrdering++;
}
- llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A,
- const Matcher *B) {
- auto *L = static_cast<const RuleMatcher *>(A);
- auto *R = static_cast<const RuleMatcher *>(B);
- return std::tuple(OpcodeOrder[L->getOpcode()],
- L->insnmatchers_front().getNumOperandMatchers()) <
- std::tuple(OpcodeOrder[R->getOpcode()],
- R->insnmatchers_front().getNumOperandMatchers());
- });
+ llvm::stable_sort(
+ InputRules, [&OpcodeOrder](const Matcher *A, const Matcher *B) {
+ auto *L = static_cast<const RuleMatcher *>(A);
+ auto *R = static_cast<const RuleMatcher *>(B);
+ return std::tuple(OpcodeOrder[L->getOpcode()],
+ L->insnmatchers_front().getNumOperandMatchers()) <
+ std::tuple(OpcodeOrder[R->getOpcode()],
+ R->insnmatchers_front().getNumOperandMatchers());
+ });
for (Matcher *Rule : InputRules)
Rule->optimize();
@@ -2302,31 +2324,6 @@ void GlobalISelEmitter::emitRunCustomAction(raw_ostream &OS) {
<< "}\n";
}
-void GlobalISelEmitter::postProcessRule(RuleMatcher &M) {
- SmallPtrSet<const Record *, 16> UsedRegs;
-
- // TODO: deal with subregs?
- for (auto &A : M.actions()) {
- auto *MI = dyn_cast<BuildMIAction>(A.get());
- if (!MI)
- continue;
-
- for (auto *Use : MI->getCGI()->ImplicitUses)
- UsedRegs.insert(Use);
- }
-
- for (auto &A : M.actions()) {
- auto *MI = dyn_cast<BuildMIAction>(A.get());
- if (!MI)
- continue;
-
- for (auto *Def : MI->getCGI()->ImplicitDefs) {
- if (!UsedRegs.contains(Def))
- MI->setDeadImplicitDef(Def);
- }
- }
-}
-
void GlobalISelEmitter::run(raw_ostream &OS) {
if (!UseCoverageFile.empty()) {
RuleCoverage = CodeGenCoverage();
@@ -2386,7 +2383,6 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
"Pattern is not covered by a test");
}
Rules.push_back(std::move(MatcherOrErr.get()));
- postProcessRule(Rules.back());
}
// Comparison function to order records by name.
More information about the llvm-commits
mailing list