Skip to content

Commit

Permalink
[GlobalISel] Import patterns containing INSERT_SUBREG
Browse files Browse the repository at this point in the history
This teaches the importer to handle INSERT_SUBREG instructions.

We were missing patterns involving INSERT_SUBREG in AArch64. It appears in
AArch64InstrInfo.td 107 times, and 14 times in AArch64InstrFormats.td.

To meaningfully import it, the GlobalISelEmitter needs to know how to infer a
super register class for a given register class.

This patch introduces the following:

- `getSuperRegForSubReg`, a function which finds the largest register class
which supports a value type and subregister index

- `inferSuperRegisterClass`, a function which finds the appropriate super
register class for an INSERT_SUBREG'

- `inferRegClassFromPattern`, a function which allows for some trivial
lookthrough into instructions

- `getRegClassFromLeaf`, a helper function which returns the register class for
a leaf `TreePatternNode`

- Support for subregister index operands in `importExplicitUseRenderer`

It also

- Updates tests in each backend which are impacted by the change

- Adds GlobalISelEmitterSubreg.td to test that we import and skip the expected
patterns

As a result of this patch, INSERT_SUBREG patterns in X86 may use the
LOW32_ADDR_ACCESS_RBP register class instead of GR32. This is correct, since the
register class contains the same registers as GR32 (except with the addition of
RBP). So, this also teaches X86 to handle that register class. This is in line
with X86ISelLowering, which treats this as a GR class.

Differential Revision: https://reviews.llvm.org/D66498

llvm-svn: 369973
  • Loading branch information
Jessica Paquette committed Aug 26, 2019
1 parent 88fd2d0 commit 69400f8
Showing 10 changed files with 407 additions and 39 deletions.
26 changes: 16 additions & 10 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ name: legal_v4s32_v2s32
alignment: 2
legalized: true
regBankSelected: true
tracksRegLiveness: true
registers:
- { id: 0, class: fpr }
- { id: 1, class: fpr }
@@ -14,28 +15,31 @@ frameInfo:
maxCallFrameSize: 0
body: |
bb.0:
liveins: $d0, $d1
; CHECK-LABEL: name: legal_v4s32_v2s32
; CHECK: liveins: $d0, $d1
; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY $d0
; CHECK: [[COPY1:%[0-9]+]]:fpr64 = COPY $d1
; CHECK: [[DEF:%[0-9]+]]:fpr128 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.dsub
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY1]], %subreg.dsub
; CHECK: [[DEF1:%[0-9]+]]:fpr128 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY1]], %subreg.dsub
; CHECK: [[INSvi64lane:%[0-9]+]]:fpr128 = INSvi64lane [[INSERT_SUBREG]], 1, [[INSERT_SUBREG1]], 0
; CHECK: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY]], %subreg.dsub
; CHECK: [[INSvi64lane:%[0-9]+]]:fpr128 = INSvi64lane [[INSERT_SUBREG1]], 1, [[INSERT_SUBREG]], 0
; CHECK: $q0 = COPY [[INSvi64lane]]
; CHECK: RET_ReallyLR
; CHECK: RET_ReallyLR implicit $q0
%0:fpr(<2 x s32>) = COPY $d0
%1:fpr(<2 x s32>) = COPY $d1
%2:fpr(<4 x s32>) = G_CONCAT_VECTORS %0(<2 x s32>), %1(<2 x s32>)
$q0 = COPY %2(<4 x s32>)
RET_ReallyLR
RET_ReallyLR implicit $q0
...
---
name: legal_v8s16_v4s16
alignment: 2
legalized: true
regBankSelected: true
tracksRegLiveness: true
registers:
- { id: 0, class: fpr }
- { id: 1, class: fpr }
@@ -44,20 +48,22 @@ frameInfo:
maxCallFrameSize: 0
body: |
bb.0:
liveins: $d0, $d1
; CHECK-LABEL: name: legal_v8s16_v4s16
; CHECK: liveins: $d0, $d1
; CHECK: [[COPY:%[0-9]+]]:fpr64 = COPY $d0
; CHECK: [[COPY1:%[0-9]+]]:fpr64 = COPY $d1
; CHECK: [[DEF:%[0-9]+]]:fpr128 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.dsub
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY1]], %subreg.dsub
; CHECK: [[DEF1:%[0-9]+]]:fpr128 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY1]], %subreg.dsub
; CHECK: [[INSvi64lane:%[0-9]+]]:fpr128 = INSvi64lane [[INSERT_SUBREG]], 1, [[INSERT_SUBREG1]], 0
; CHECK: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY]], %subreg.dsub
; CHECK: [[INSvi64lane:%[0-9]+]]:fpr128 = INSvi64lane [[INSERT_SUBREG1]], 1, [[INSERT_SUBREG]], 0
; CHECK: $q0 = COPY [[INSvi64lane]]
; CHECK: RET_ReallyLR
; CHECK: RET_ReallyLR implicit $q0
%0:fpr(<4 x s16>) = COPY $d0
%1:fpr(<4 x s16>) = COPY $d1
%2:fpr(<8 x s16>) = G_CONCAT_VECTORS %0(<4 x s16>), %1(<4 x s16>)
$q0 = COPY %2(<8 x s16>)
RET_ReallyLR
RET_ReallyLR implicit $q0
...
24 changes: 13 additions & 11 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir
Original file line number Diff line number Diff line change
@@ -41,9 +41,10 @@ body: |
liveins: $w0
; CHECK-LABEL: name: anyext_s64_from_s32
; CHECK: [[COPY:%[0-9]+]]:gpr32all = COPY $w0
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64all = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32
; CHECK: $x0 = COPY [[SUBREG_TO_REG]]
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[DEF:%[0-9]+]]:gpr64all = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:gpr64all = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.sub_32
; CHECK: $x0 = COPY [[INSERT_SUBREG]]
%0(s32) = COPY $w0
%1(s64) = G_ANYEXT %0
$x0 = COPY %1(s64)
@@ -64,8 +65,8 @@ body: |
; CHECK-LABEL: name: anyext_s32_from_s8
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[COPY2:%[0-9]+]]:gpr32all = COPY [[COPY]]
; CHECK: $w0 = COPY [[COPY2]]
; CHECK: [[COPY1:%[0-9]+]]:gpr32all = COPY [[COPY]]
; CHECK: $w0 = COPY [[COPY1]]
%2:gpr(s32) = COPY $w0
%0(s8) = G_TRUNC %2
%1(s32) = G_ANYEXT %0
@@ -236,8 +237,8 @@ body: |
; CHECK-LABEL: name: zext_s16_from_s8
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[UBFMWri:%[0-9]+]]:gpr32 = UBFMWri [[COPY]], 0, 7
; CHECK: [[COPY2:%[0-9]+]]:gpr32all = COPY [[UBFMWri]]
; CHECK: $w0 = COPY [[COPY2]]
; CHECK: [[COPY1:%[0-9]+]]:gpr32all = COPY [[UBFMWri]]
; CHECK: $w0 = COPY [[COPY1]]
%2:gpr(s32) = COPY $w0
%0(s8) = G_TRUNC %2
%1(s16) = G_ZEXT %0
@@ -339,8 +340,9 @@ body: |
; CHECK-LABEL: name: sext_s64_from_s32
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32
; CHECK: [[SBFMXri:%[0-9]+]]:gpr64 = SBFMXri [[SUBREG_TO_REG]], 0, 31
; CHECK: [[DEF:%[0-9]+]]:gpr64all = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:gpr64 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.sub_32
; CHECK: [[SBFMXri:%[0-9]+]]:gpr64 = SBFMXri [[INSERT_SUBREG]], 0, 31
; CHECK: $x0 = COPY [[SBFMXri]]
%0(s32) = COPY $w0
%1(s64) = G_SEXT %0
@@ -409,8 +411,8 @@ body: |
; CHECK-LABEL: name: sext_s16_from_s8
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[SBFMWri:%[0-9]+]]:gpr32 = SBFMWri [[COPY]], 0, 7
; CHECK: [[COPY2:%[0-9]+]]:gpr32all = COPY [[SBFMWri]]
; CHECK: $w0 = COPY [[COPY2]]
; CHECK: [[COPY1:%[0-9]+]]:gpr32all = COPY [[SBFMWri]]
; CHECK: $w0 = COPY [[COPY1]]
%2:gpr(s32) = COPY $w0
%0(s8) = G_TRUNC %2
%1(s16) = G_SEXT %0
15 changes: 8 additions & 7 deletions llvm/test/CodeGen/X86/GlobalISel/select-copy.mir
Original file line number Diff line number Diff line change
@@ -179,16 +179,18 @@ regBankSelected: true
# ALL: registers:
# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' }
# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: low32_addr_access_rbp, preferred-register: '' }
# ALL-NEXT: - { id: 3, class: low32_addr_access_rbp, preferred-register: '' }
registers:
- { id: 0, class: gpr, preferred-register: '' }
- { id: 1, class: gpr, preferred-register: '' }
- { id: 2, class: gpr, preferred-register: '' }
# ALL %0:gr32 = COPY $edx
# ALL-NEXT %1:gr16 = COPY %0.sub_16bit
# ALL-NEXT %2:gr32 = SUBREG_TO_REG 0, %1, %subreg.sub_16bit
# ALL-NEXT $eax = COPY %2
# ALL-NEXT RET 0, implicit $eax
# ALL: %0:gr32 = COPY $edx
# ALL-NEXT: %1:gr16 = COPY %0.sub_16bit
# ALL-NEXT: %3:low32_addr_access_rbp = IMPLICIT_DEF
# ALL-NEXT: %2:low32_addr_access_rbp = INSERT_SUBREG %3, %1, %subreg.sub_16bit
# ALL-NEXT: $eax = COPY %2
# ALL-NEXT: RET 0, implicit $eax
body: |
bb.1 (%ir-block.0):
liveins: $eax,$edx
@@ -200,4 +202,3 @@ body: |
RET 0, implicit $eax
...

5 changes: 3 additions & 2 deletions llvm/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir
Original file line number Diff line number Diff line change
@@ -186,8 +186,9 @@ body: |
; ALL-LABEL: name: anyext_s64_from_s32
; ALL: [[COPY:%[0-9]+]]:gr64 = COPY $rdi
; ALL: [[COPY1:%[0-9]+]]:gr32 = COPY [[COPY]].sub_32bit
; ALL: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY1]], %subreg.sub_32bit
; ALL: $rax = COPY [[SUBREG_TO_REG]]
; ALL: [[DEF:%[0-9]+]]:gr64 = IMPLICIT_DEF
; ALL: [[INSERT_SUBREG:%[0-9]+]]:gr64 = INSERT_SUBREG [[DEF]], [[COPY1]], %subreg.sub_32bit
; ALL: $rax = COPY [[INSERT_SUBREG]]
; ALL: RET 0, implicit $rax
%0(s64) = COPY $rdi
%1(s32) = G_TRUNC %0(s64)
6 changes: 4 additions & 2 deletions llvm/test/CodeGen/X86/GlobalISel/select-ext.mir
Original file line number Diff line number Diff line change
@@ -446,14 +446,16 @@ regBankSelected: true
# ALL: registers:
# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' }
# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: low32_addr_access_rbp, preferred-register: '' }
# ALL-NEXT: - { id: 3, class: low32_addr_access_rbp, preferred-register: '' }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
# ALL: %0:gr32 = COPY $edi
# ALL-NEXT: %1:gr16 = COPY %0.sub_16bit
# ALL-NEXT: %2:gr32 = SUBREG_TO_REG 0, %1, %subreg.sub_16bit
# ALL-NEXT: %3:low32_addr_access_rbp = IMPLICIT_DEF
# ALL-NEXT: %2:low32_addr_access_rbp = INSERT_SUBREG %3, %1, %subreg.sub_16bit
# ALL-NEXT: $eax = COPY %2
# ALL-NEXT: RET 0, implicit $eax
body: |
15 changes: 9 additions & 6 deletions llvm/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir
Original file line number Diff line number Diff line change
@@ -165,8 +165,9 @@ body: |
; CHECK-LABEL: name: zext_i1_to_i64
; CHECK: liveins: $edi
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri8_:%[0-9]+]]:gr64 = AND64ri8 [[SUBREG_TO_REG]], 1, implicit-def $eflags
; CHECK: [[DEF:%[0-9]+]]:gr64 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:gr64 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri8_:%[0-9]+]]:gr64 = AND64ri8 [[INSERT_SUBREG]], 1, implicit-def $eflags
; CHECK: $rax = COPY [[AND64ri8_]]
; CHECK: RET 0, implicit $rax
%1:gpr(s32) = COPY $edi
@@ -258,8 +259,9 @@ body: |
; CHECK-LABEL: name: zext_i8_to_i64
; CHECK: liveins: $edi
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri32_:%[0-9]+]]:gr64 = AND64ri32 [[SUBREG_TO_REG]], 255, implicit-def $eflags
; CHECK: [[DEF:%[0-9]+]]:gr64 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:gr64 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri32_:%[0-9]+]]:gr64 = AND64ri32 [[INSERT_SUBREG]], 255, implicit-def $eflags
; CHECK: $rax = COPY [[AND64ri32_]]
; CHECK: RET 0, implicit $rax
%1:gpr(s32) = COPY $edi
@@ -320,8 +322,9 @@ body: |
; CHECK-LABEL: name: zext_i16_to_i64
; CHECK: liveins: $edi
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri32_:%[0-9]+]]:gr64 = AND64ri32 [[SUBREG_TO_REG]], 65535, implicit-def $eflags
; CHECK: [[DEF:%[0-9]+]]:gr64 = IMPLICIT_DEF
; CHECK: [[INSERT_SUBREG:%[0-9]+]]:gr64 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.sub_32bit
; CHECK: [[AND64ri32_:%[0-9]+]]:gr64 = AND64ri32 [[INSERT_SUBREG]], 65535, implicit-def $eflags
; CHECK: $rax = COPY [[AND64ri32_]]
; CHECK: RET 0, implicit $rax
%1:gpr(s32) = COPY $edi
119 changes: 119 additions & 0 deletions llvm/test/TableGen/GlobalISelEmitterSubreg.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// RUN: llvm-tblgen %s -gen-global-isel -warn-on-skipped-patterns -I %p/../../include -I %p/Common -o - 2> %t.skipped | FileCheck %s
// RUN: cat %t.skipped | FileCheck %s --check-prefix=SKIPPED

include "llvm/Target/Target.td"
include "GlobalISelEmitterCommon.td"

// Boilerplate code for setting up some registers with subregs.
class MyReg<string n, list<Register> subregs = []>
: Register<n> {
let SubRegs = subregs;
}

class MyClass<int size, list<ValueType> types, dag registers>
: RegisterClass<"Test", types, size, registers> {
let Size = size;
}

def sub0 : SubRegIndex<16>;
def sub1 : SubRegIndex<16, 16>;
def S0 : MyReg<"s0">;
def S1 : MyReg<"s1">;
def S2 : MyReg<"s14">;
def S3 : MyReg<"s15">;
def SRegs : MyClass<16, [i16], (sequence "S%u", 0, 3)>;

let SubRegIndices = [sub0, sub1] in {
def D0 : MyReg<"d0", [S0, S1]>;
def E0 : MyReg<"e0", [S2, S3]>;
}

def DRegs : MyClass<32, [i32], (sequence "D%u", 0, 0)>;
def ERegs : MyClass<32, [i32], (sequence "E%u", 0, 0)>;
def SOP : RegisterOperand<SRegs>;
def DOP : RegisterOperand<DRegs>;
def SOME_INSN : I<(outs DRegs:$dst), (ins DOP:$src), []>;

// We should skip cases where we don't have a given register class for the
// subregister source.
// SKIPPED: def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), i16:$src, sub0)>;
// SKIPPED: def : Pat<(i32 (anyext i16:$src)), (SOME_INSN (INSERT_SUBREG (i32 (IMPLICIT_DEF)), i16:$src, sub0))>;
def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), i16:$src, sub0)>;
def : Pat<(i32 (anyext i16:$src)), (SOME_INSN (INSERT_SUBREG (i32 (IMPLICIT_DEF)), i16:$src, sub0))>;

// Test that we import INSERT_SUBREG when its subregister source has a given
// class.
def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), SOP:$src, sub0)>;
// CHECK-LABEL: (anyext:{ *:[i32] } i16:{ *:[i16] }:$src) => (INSERT_SUBREG:{ *:[i32] } (IMPLICIT_DEF:{ *:[i32] }), SOP:{ *:[i16] }:$src, sub0:{ *:[i32] })
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::IMPLICIT_DEF,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::INSERT_SUBREG,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/1,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/1, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/2, /*RC SRegs*/0,


// Test that we can import INSERT_SUBREG when it is a subinstruction of another
// 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*/TargetOpcode::IMPLICIT_DEF,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::INSERT_SUBREG,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_AddImm, /*InsnID*/1, /*Imm*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/0, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/1, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/2, /*RC SRegs*/0,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SOME_INSN,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,


// Test that we correctly infer the super register class for INSERT_SUBREG when
// we have COPY_TO_REGCLASS. We want to make sure we get an E register here,
// not a D register.
def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (COPY_TO_REGCLASS SOP:$src, ERegs)), SOP:$src, sub0)>;
// CHECK-LABEL: (anyext:{ *:[i32] } i16:{ *:[i16] }:$src) => (INSERT_SUBREG:{ *:[i32] } (COPY_TO_REGCLASS:{ *:[i32] } SOP:{ *:[i16] }:$src, ERegs:{ *:[i32] }), SOP:{ *:[i16] }:$src, sub0:{ *:[i32] })
// CHECK: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::INSERT_SUBREG,
// CHECK-DAG: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC ERegs*/2,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/1, /*RC ERegs*/2,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/2, /*RC SRegs*/0,

// Test that we can import INSERT_SUBREG when its subregister source is defined
// by a subinstruction.
def SUBSOME_INSN : I<(outs SRegs:$dst), (ins SOP:$src), []>;
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*/MyTarget::SUBSOME_INSN,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::IMPLICIT_DEF,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::INSERT_SUBREG,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/1, /*TempRegFlags*/0,
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/1,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/1, /*RC DRegs*/1,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/2, /*RC SRegs*/0,
40 changes: 40 additions & 0 deletions llvm/utils/TableGen/CodeGenTarget.cpp
Original file line number Diff line number Diff line change
@@ -295,6 +295,46 @@ CodeGenRegBank &CodeGenTarget::getRegBank() const {
return *RegBank;
}

Optional<CodeGenRegisterClass *>
CodeGenTarget::getSuperRegForSubReg(const ValueTypeByHwMode &ValueTy,
CodeGenRegBank &RegBank,
const CodeGenSubRegIndex *SubIdx) const {
std::vector<CodeGenRegisterClass *> Candidates;
auto &RegClasses = RegBank.getRegClasses();

// Try to find a register class which supports ValueTy, and also contains
// SubIdx.
for (CodeGenRegisterClass &RC : RegClasses) {
// Is there a subclass of this class which contains this subregister index?
CodeGenRegisterClass *SubClassWithSubReg = RC.getSubClassWithSubReg(SubIdx);
if (!SubClassWithSubReg)
continue;

// We have a class. Check if it supports this value type.
if (llvm::none_of(SubClassWithSubReg->VTs,
[&ValueTy](const ValueTypeByHwMode &ClassVT) {
return ClassVT == ValueTy;
}))
continue;

// We have a register class which supports both the value type and
// subregister index. Remember it.
Candidates.push_back(SubClassWithSubReg);
}

// If we didn't find anything, we're done.
if (Candidates.empty())
return None;

// Find and return the largest of our candidate classes.
llvm::sort(Candidates,
[&](const CodeGenRegisterClass *A, const CodeGenRegisterClass *B) {
return A->getMembers().size() > B->getMembers().size();
});

return Candidates[0];
}

void CodeGenTarget::ReadRegAltNameIndices() const {
RegAltNameIndices = Records.getAllDerivedDefinitions("RegAltNameIndex");
llvm::sort(RegAltNameIndices, LessRecord());
Loading

0 comments on commit 69400f8

Please sign in to comment.