[llvm] r369973 - [GlobalISel] Import patterns containing INSERT_SUBREG

Jessica Paquette via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 26 14:38:57 PDT 2019


Author: paquette
Date: Mon Aug 26 14:38:57 2019
New Revision: 369973

URL: http://llvm.org/viewvc/llvm-project?rev=369973&view=rev
Log:
[GlobalISel] Import patterns containing INSERT_SUBREG

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

Added:
    llvm/trunk/test/TableGen/GlobalISelEmitterSubreg.td
Modified:
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir
    llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir
    llvm/trunk/test/CodeGen/X86/GlobalISel/select-copy.mir
    llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir
    llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext.mir
    llvm/trunk/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir
    llvm/trunk/utils/TableGen/CodeGenTarget.cpp
    llvm/trunk/utils/TableGen/CodeGenTarget.h
    llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp

Modified: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir (original)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-concat-vectors.mir Mon Aug 26 14:38:57 2019
@@ -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,21 +15,23 @@ 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
 
 ...
 ---
@@ -36,6 +39,7 @@ 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
 
 ...

Modified: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir (original)
+++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-int-ext.mir Mon Aug 26 14:38:57 2019
@@ -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

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/select-copy.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/select-copy.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/select-copy.mir (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/select-copy.mir Mon Aug 26 14:38:57 2019
@@ -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
 
 ...
-

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir Mon Aug 26 14:38:57 2019
@@ -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)

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext.mir (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/select-ext.mir Mon Aug 26 14:38:57 2019
@@ -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:             |

Modified: llvm/trunk/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir (original)
+++ llvm/trunk/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir Mon Aug 26 14:38:57 2019
@@ -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

Added: llvm/trunk/test/TableGen/GlobalISelEmitterSubreg.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/TableGen/GlobalISelEmitterSubreg.td?rev=369973&view=auto
==============================================================================
--- llvm/trunk/test/TableGen/GlobalISelEmitterSubreg.td (added)
+++ llvm/trunk/test/TableGen/GlobalISelEmitterSubreg.td Mon Aug 26 14:38:57 2019
@@ -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,

Modified: llvm/trunk/utils/TableGen/CodeGenTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenTarget.cpp?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenTarget.cpp (original)
+++ llvm/trunk/utils/TableGen/CodeGenTarget.cpp Mon Aug 26 14:38:57 2019
@@ -295,6 +295,46 @@ CodeGenRegBank &CodeGenTarget::getRegBan
   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());

Modified: llvm/trunk/utils/TableGen/CodeGenTarget.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/CodeGenTarget.h?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/CodeGenTarget.h (original)
+++ llvm/trunk/utils/TableGen/CodeGenTarget.h Mon Aug 26 14:38:57 2019
@@ -103,6 +103,12 @@ public:
   /// getRegBank - Return the register bank description.
   CodeGenRegBank &getRegBank() const;
 
+  /// Return the largest register class on \p RegBank which supports \p Ty and
+  /// covers \p SubIdx if it exists.
+  Optional<CodeGenRegisterClass *>
+  getSuperRegForSubReg(const ValueTypeByHwMode &Ty, CodeGenRegBank &RegBank,
+                       const CodeGenSubRegIndex *SubIdx) const;
+
   /// getRegisterByName - If there is a register with the specific AsmName,
   /// return it.
   const CodeGenRegister *getRegisterByName(StringRef Name) const;

Modified: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp?rev=369973&r1=369972&r2=369973&view=diff
==============================================================================
--- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp Mon Aug 26 14:38:57 2019
@@ -3164,6 +3164,24 @@ private:
   MatchTable buildMatchTable(MutableArrayRef<RuleMatcher> Rules, bool Optimize,
                              bool WithCoverage);
 
+  /// Infer a CodeGenRegisterClass for the type of \p SuperRegNode. The returned
+  /// CodeGenRegisterClass will support the CodeGenRegisterClass of
+  /// \p SubRegNode, and the subregister index defined by \p SubRegIdxNode.
+  /// If no register class is found, return None.
+  Optional<const CodeGenRegisterClass *>
+  inferSuperRegisterClass(const TypeSetByHwMode &Ty,
+                          TreePatternNode *SuperRegNode,
+                          TreePatternNode *SubRegIdxNode);
+
+  /// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
+  Optional<const CodeGenRegisterClass *>
+  getRegClassFromLeaf(TreePatternNode *Leaf);
+
+  /// Return a CodeGenRegisterClass for \p N if one can be found. Return None
+  /// otherwise.
+  Optional<const CodeGenRegisterClass *>
+  inferRegClassFromPattern(TreePatternNode *N);
+
 public:
   /// Takes a sequence of \p Rules and group them based on the predicates
   /// they share. \p MatcherStorage is used as a memory container
@@ -3771,6 +3789,12 @@ Expected<action_iterator> GlobalISelEmit
       return InsertPt;
     }
 
+    if (ChildRec->isSubClassOf("SubRegIndex")) {
+      CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(ChildRec);
+      DstMIBuilder.addRenderer<ImmRenderer>(SubIdx->EnumValue);
+      return InsertPt;
+    }
+
     if (ChildRec->isSubClassOf("ComplexPattern")) {
       const auto &ComplexPattern = ComplexPatternEquivs.find(ChildRec);
       if (ComplexPattern == ComplexPatternEquivs.end())
@@ -3831,6 +3855,31 @@ GlobalISelEmitter::createAndImportSubIns
   if (auto Error = InsertPtOrError.takeError())
     return std::move(Error);
 
+  // We need to make sure that when we import an INSERT_SUBREG as a
+  // subinstruction that it ends up being constrained to the correct super
+  // register and subregister classes.
+  if (Target.getInstruction(Dst->getOperator()).TheDef->getName() ==
+      "INSERT_SUBREG") {
+    auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+    if (!SubClass)
+      return failedImport(
+          "Cannot infer register class from INSERT_SUBREG operand #1");
+    Optional<const CodeGenRegisterClass *> SuperClass = inferSuperRegisterClass(
+        Dst->getExtType(0), Dst->getChild(0), Dst->getChild(2));
+    if (!SuperClass)
+      return failedImport(
+          "Cannot infer register class for INSERT_SUBREG operand #0");
+    // The destination and the super register source of an INSERT_SUBREG must
+    // be the same register class.
+    M.insertAction<ConstrainOperandToRegClassAction>(
+        InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
+    M.insertAction<ConstrainOperandToRegClassAction>(
+        InsertPt, DstMIBuilder.getInsnID(), 1, **SuperClass);
+    M.insertAction<ConstrainOperandToRegClassAction>(
+        InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
+    return InsertPtOrError.get();
+  }
+
   M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt,
                                                       DstMIBuilder.getInsnID());
   return InsertPtOrError.get();
@@ -4008,6 +4057,110 @@ Error GlobalISelEmitter::importImplicitD
   return Error::success();
 }
 
+Optional<const CodeGenRegisterClass *>
+GlobalISelEmitter::getRegClassFromLeaf(TreePatternNode *Leaf) {
+  assert(Leaf && "Expected node?");
+  assert(Leaf->isLeaf() && "Expected leaf?");
+  Record *RCRec = getInitValueAsRegClass(Leaf->getLeafValue());
+  if (!RCRec)
+    return None;
+  CodeGenRegisterClass *RC = CGRegs.getRegClass(RCRec);
+  if (!RC)
+    return None;
+  return RC;
+}
+
+Optional<const CodeGenRegisterClass *>
+GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {
+  if (!N)
+    return None;
+
+  if (N->isLeaf())
+    return getRegClassFromLeaf(N);
+
+  // We don't have a leaf node, so we have to try and infer something. Check
+  // that we have an instruction that we an infer something from.
+
+  // Only handle things that produce a single type.
+  if (N->getNumTypes() != 1)
+    return None;
+  Record *OpRec = N->getOperator();
+
+  // We only want instructions.
+  if (!OpRec->isSubClassOf("Instruction"))
+    return None;
+
+  // Don't want to try and infer things when there could potentially be more
+  // than one candidate register class.
+  auto &Inst = Target.getInstruction(OpRec);
+  if (Inst.Operands.NumDefs > 1)
+    return None;
+
+  // Handle any special-case instructions which we can safely infer register
+  // classes from.
+  StringRef InstName = Inst.TheDef->getName();
+  if (InstName == "COPY_TO_REGCLASS") {
+    // If we have a COPY_TO_REGCLASS, then we need to handle it specially. It
+    // has the desired register class as the first child.
+    TreePatternNode *RCChild = N->getChild(1);
+    if (!RCChild->isLeaf())
+      return None;
+    return getRegClassFromLeaf(RCChild);
+  }
+
+  // Handle destination record types that we can safely infer a register class
+  // from.
+  const auto &DstIOperand = Inst.Operands[0];
+  Record *DstIOpRec = DstIOperand.Rec;
+  if (DstIOpRec->isSubClassOf("RegisterOperand")) {
+    DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
+    const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
+    return &RC;
+  }
+
+  if (DstIOpRec->isSubClassOf("RegisterClass")) {
+    const CodeGenRegisterClass &RC = Target.getRegisterClass(DstIOpRec);
+    return &RC;
+  }
+
+  return None;
+}
+
+Optional<const CodeGenRegisterClass *>
+GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
+                                           TreePatternNode *SuperRegNode,
+                                           TreePatternNode *SubRegIdxNode) {
+  // Check if we already have a defined register class for the super register
+  // node. If we do, then we should preserve that rather than inferring anything
+  // from the subregister index node. We can assume that whoever wrote the
+  // pattern in the first place made sure that the super register and
+  // subregister are compatible.
+  if (Optional<const CodeGenRegisterClass *> SuperRegisterClass =
+          inferRegClassFromPattern(SuperRegNode))
+    return SuperRegisterClass;
+
+  // We need a ValueTypeByHwMode for getSuperRegForSubReg.
+  if (!Ty.isValueTypeByHwMode(false))
+    return None;
+
+  // We don't know anything about the super register. Try to use the subregister
+  // index to infer an appropriate register class.
+  if (!SubRegIdxNode->isLeaf())
+    return None;
+  DefInit *SubRegInit = dyn_cast<DefInit>(SubRegIdxNode->getLeafValue());
+  if (!SubRegInit)
+    return None;
+  CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
+
+  // Use the information we found above to find a minimal register class which
+  // supports the subregister and type we want.
+  auto RC =
+      Target.getSuperRegForSubReg(Ty.getValueTypeByHwMode(), CGRegs, SubIdx);
+  if (!RC)
+    return None;
+  return *RC;
+}
+
 Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
   // Keep track of the matchers and actions to emit.
   int Score = P.getPatternComplexity(CGP);
@@ -4126,8 +4279,22 @@ Expected<RuleMatcher> GlobalISelEmitter:
       DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
 
       if (DstIOpRec == nullptr)
+        return failedImport("EXTRACT_SUBREG operand #0 isn't a register class");
+    } else if (DstI.TheDef->getName() == "INSERT_SUBREG") {
+      auto MaybeSuperClass =
+          inferSuperRegisterClass(VTy, Dst->getChild(0), Dst->getChild(2));
+      if (!MaybeSuperClass)
         return failedImport(
-            "EXTRACT_SUBREG operand #0 isn't a register class");
+            "Cannot infer register class for INSERT_SUBREG operand #0");
+      // Move to the next pattern here, because the register class we found
+      // doesn't necessarily have a record associated with it. So, we can't
+      // set DstIOpRec using this.
+      OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
+      OM.setSymbolicName(DstIOperand.Name);
+      M.defineOperand(OM.getSymbolicName(), OM);
+      OM.addPredicate<RegisterBankOperandMatcher>(**MaybeSuperClass);
+      ++OpIdx;
+      continue;
     } else if (DstIOpRec->isSubClassOf("RegisterOperand"))
       DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
     else if (!DstIOpRec->isSubClassOf("RegisterClass"))
@@ -4216,6 +4383,27 @@ Expected<RuleMatcher> GlobalISelEmitter:
     ++NumPatternImported;
     return std::move(M);
   }
+
+  if (DstI.TheDef->getName() == "INSERT_SUBREG") {
+    assert(Src->getExtTypes().size() == 1 &&
+           "Expected Src of INSERT_SUBREG to have one result type");
+    // We need to constrain the destination, a super regsister source, and a
+    // subregister source.
+    auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
+    if (!SubClass)
+      return failedImport(
+          "Cannot infer register class from INSERT_SUBREG operand #1");
+    auto SuperClass = inferSuperRegisterClass(
+        Src->getExtType(0), Dst->getChild(0), Dst->getChild(2));
+    if (!SuperClass)
+      return failedImport(
+          "Cannot infer register class for INSERT_SUBREG operand #0");
+    M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
+    M.addAction<ConstrainOperandToRegClassAction>(0, 1, **SuperClass);
+    M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
+    ++NumPatternImported;
+    return std::move(M);
+  }
 
   M.addAction<ConstrainOperandsToDefinitionAction>(0);
 




More information about the llvm-commits mailing list