From 70dedcfce717d2e87ce2b9b8dd8732e487f3ebc8 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov 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; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; +def : GINodeEquiv; +def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; 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; 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 &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 Predicates); - Expected - createAndImportSelDAGMatcher(RuleMatcher &Rule, - InstructionMatcher &InsnMatcher, - const TreePatternNode &Src, unsigned &TempOpIdx); + Expected 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 createAndImportInstructionRenderer( - RuleMatcher &M, InstructionMatcher &InsnMatcher, + RuleMatcher &M, InstructionMatcher &InsnMatcher, const PatternToMatch &P, const TreePatternNode &Src, const TreePatternNode &Dst); Expected 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 createInstructionRenderer(action_iterator InsertPt, RuleMatcher &M, const TreePatternNode &Dst); Expected - 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 importExplicitUseRenderers( action_iterator InsertPt, RuleMatcher &M, BuildMIAction &DstMIBuilder, - const llvm::TreePatternNode &Dst, const TreePatternNode &Src); + const PatternToMatch &P, const TreePatternNode &Dst); Expected 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 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 GlobalISelEmitter::addBuiltinPredicates( } Expected 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 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 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 GlobalISelEmitter::importExplicitUseRenderer( DstMIBuilder.addRenderer(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 GlobalISelEmitter::importExplicitUseRenderer( } Expected 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 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 GlobalISelEmitter::createAndImportInstructionRenderer( Expected 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(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 GlobalISelEmitter::createInstructionRenderer( DstI); } -Expected GlobalISelEmitter::importExplicitDefRenderers( +Expected 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(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(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(SubOp.getLeafValue())->getDef(); + assert(Reg->isSubClassOf("Register")); + DstMIBuilder.addRenderer( + 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 GlobalISelEmitter::importExplicitDefRenderers( unsigned TempRegID = M.allocateTempRegID(); InsertPt = M.insertAction(InsertPt, *OpTy, TempRegID); - DstMIBuilder.addRenderer(TempRegID, true, nullptr, true); + DstMIBuilder.addRenderer( + 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( + M.allocateOutputInsnID(), &Target.getInstruction(RK.getDef("COPY"))); + + StringRef PermanentRef = M.getOperandMatcher(OpName).getSymbolicName(); + CopyBuilder.addRenderer(PermanentRef); + CopyBuilder.addRenderer(Target, Reg); + + const CodeGenRegisterClass *RC = CGRegs.getRegClassForRegister(Reg); + assert(RC); + M.addAction(CopyBuilder.getInsnID(), + /*OpIdx=*/0, *RC); } return InsertPt; @@ -1495,7 +1519,7 @@ Expected GlobalISelEmitter::importExplicitDefRenderers( Expected 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 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 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 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 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 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 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(Pred.get()))) break; @@ -2112,15 +2130,24 @@ Expected 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 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 Rules, OpcodeOrder[Opcode] = CurrentOrdering++; } - llvm::stable_sort(InputRules, [&OpcodeOrder](const Matcher *A, - const Matcher *B) { - auto *L = static_cast(A); - auto *R = static_cast(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(A); + auto *R = static_cast(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 UsedRegs; - - // TODO: deal with subregs? - for (auto &A : M.actions()) { - auto *MI = dyn_cast(A.get()); - if (!MI) - continue; - - for (auto *Use : MI->getCGI()->ImplicitUses) - UsedRegs.insert(Use); - } - - for (auto &A : M.actions()) { - auto *MI = dyn_cast(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.