5 changes: 3 additions & 2 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-cmp.mir
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ body: |
; CHECK-LABEL: name: cmp_imm_out_of_range
; CHECK: liveins: $x0
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 13132
; CHECK: $xzr = SUBSXrr [[COPY]], [[MOVi64imm]], implicit-def $nzcv
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 13132
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: $xzr = SUBSXrr [[COPY]], [[SUBREG_TO_REG]], implicit-def $nzcv
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr $wzr, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
Expand Down
17 changes: 9 additions & 8 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-cmpxchg.mir
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ body: |
; CHECK-LABEL: name: cmpxchg_i32
; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0
; CHECK: [[CMP:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[CST:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[RES:%[0-9]+]]:gpr32 = CASW [[CMP]], [[CST]], [[COPY]] :: (load store monotonic 4 on %ir.addr)
; CHECK: $w0 = COPY [[RES]]
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[CASW:%[0-9]+]]:gpr32 = CASW [[COPY1]], [[MOVi32imm]], [[COPY]] :: (load store monotonic 4 on %ir.addr)
; CHECK: $w0 = COPY [[CASW]]
%0:gpr(p0) = COPY $x0
%1:gpr(s32) = G_CONSTANT i32 0
%2:gpr(s32) = G_CONSTANT i32 1
Expand All @@ -41,10 +41,11 @@ body: |
; CHECK-LABEL: name: cmpxchg_i64
; CHECK: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0
; CHECK: [[CMP:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[CST:%[0-9]+]]:gpr64 = MOVi64imm 1
; CHECK: [[RES:%[0-9]+]]:gpr64 = CASX [[CMP]], [[CST]], [[COPY]] :: (load store monotonic 8 on %ir.addr)
; CHECK: $x0 = COPY [[RES]]
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[CASX:%[0-9]+]]:gpr64 = CASX [[COPY1]], [[SUBREG_TO_REG]], [[COPY]] :: (load store monotonic 8 on %ir.addr)
; CHECK: $x0 = COPY [[CASX]]
%0:gpr(p0) = COPY $x0
%1:gpr(s64) = G_CONSTANT i64 0
%2:gpr(s64) = G_CONSTANT i64 1
Expand Down
5 changes: 3 additions & 2 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-imm.mir
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ body: |
liveins: $w0, $w1
; CHECK-LABEL: name: imm_s64_gpr
; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 1234
; CHECK: $x0 = COPY [[MOVi64imm]]
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1234
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64all = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: $x0 = COPY [[SUBREG_TO_REG]]
%0(s64) = G_CONSTANT i64 1234
$x0 = COPY %0(s64)
...
10 changes: 6 additions & 4 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-scalar-shift-imm.mir
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ body: |
; CHECK-LABEL: name: lshr_32_notimm64
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 8
; CHECK: [[ANDXri:%[0-9]+]]:gpr64sp = ANDXri [[MOVi64imm]], 8000
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 8
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[ANDXri:%[0-9]+]]:gpr64sp = ANDXri [[SUBREG_TO_REG]], 8000
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY [[ANDXri]].sub_32
; CHECK: [[LSRVWr:%[0-9]+]]:gpr32 = LSRVWr [[COPY]], [[COPY1]]
; CHECK: $w0 = COPY [[LSRVWr]]
Expand All @@ -154,8 +155,9 @@ body: |
; CHECK-LABEL: name: ashr_32_notimm64
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[MOVi64imm:%[0-9]+]]:gpr64 = MOVi64imm 8
; CHECK: [[ANDXri:%[0-9]+]]:gpr64sp = ANDXri [[MOVi64imm]], 8000
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 8
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[ANDXri:%[0-9]+]]:gpr64sp = ANDXri [[SUBREG_TO_REG]], 8000
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY [[ANDXri]].sub_32
; CHECK: [[ASRVWr:%[0-9]+]]:gpr32 = ASRVWr [[COPY]], [[COPY1]]
; CHECK: $w0 = COPY [[ASRVWr]]
Expand Down
3 changes: 2 additions & 1 deletion llvm/test/CodeGen/AArch64/GlobalISel/select.mir
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ registers:

# CHECK: body:
# CHECK: %0:gpr64 = COPY $x0
# CHECK: %1:gpr64 = MOVi64imm 10000
# CHECK: %3:gpr32 = MOVi32imm 10000
# CHECK: %1:gpr64 = SUBREG_TO_REG 0, %3, %subreg.sub_32
# CHECK: %2:gpr64 = ADDXrr %0, %1
body: |
bb.0:
Expand Down
58 changes: 29 additions & 29 deletions llvm/test/CodeGen/AArch64/GlobalISel/swifterror.ll
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ declare void @free(i8*)
define float @foo(%swift_error** swifterror %error_ptr_ref) {
; CHECK-LABEL: foo:
; CHECK: mov [[ID:w[0-9]+]], #1
; CHECK: mov x0, #16
; CHECK: mov w0, #16
; CHECK: malloc
; CHECK: strb [[ID]], [x0, #8]
; CHECK: mov x21, x0
Expand Down Expand Up @@ -99,7 +99,7 @@ define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) {
; CHECK-LABEL: foo_if:
; CHECK: cbz w0
; CHECK: mov [[ID:w[0-9]+]], #1
; CHECK: mov x0, #16
; CHECK: mov w0, #16
; CHECK: malloc
; CHECK: strb [[ID]], [x0, #8]
; CHECK: mov x21, x0
Expand Down Expand Up @@ -127,7 +127,7 @@ normal:
define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) {
; CHECK-LABEL: foo_loop:
; CHECK: cbz
; CHECK: mov x0, #16
; CHECK: mov w0, #16
; CHECK: malloc
; CHECK: mov x21, x0
; CHECK: strb w{{.*}}, [x0, #8]
Expand Down Expand Up @@ -165,7 +165,7 @@ define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swi
; CHECK-LABEL: foo_sret:
; CHECK: mov [[SRET:x[0-9]+]], x8
; CHECK: mov [[ID:w[0-9]+]], #1
; CHECK: mov x0, #16
; CHECK: mov w0, #16
; CHECK: malloc
; CHECK: strb [[ID]], [x0, #8]
; CHECK: str w{{.*}}, [{{.*}}[[SRET]], #4]
Expand Down Expand Up @@ -221,7 +221,7 @@ declare void @llvm.va_start(i8*) nounwind
define float @foo_vararg(%swift_error** swifterror %error_ptr_ref, ...) {
; CHECK-LABEL: foo_vararg:
; CHECK-DAG: mov [[ID:w[0-9]+]], #1
; CHECK: mov x0, #16
; CHECK: mov w0, #16
; CHECK: malloc
; CHECK-DAG: strb [[ID]], [x0, #8]

Expand Down Expand Up @@ -333,14 +333,14 @@ entry:
; CHECK: mov x27, x7
; CHECK: mov x28, x21
; Setup call.
; CHECK: mov x0, #1
; CHECK: mov x1, #2
; CHECK: mov x2, #3
; CHECK: mov x3, #4
; CHECK: mov x4, #5
; CHECK: mov x5, #6
; CHECK: mov x6, #7
; CHECK: mov x7, #8
; CHECK: mov w0, #1
; CHECK: mov w1, #2
; CHECK: mov w2, #3
; CHECK: mov w3, #4
; CHECK: mov w4, #5
; CHECK: mov w5, #6
; CHECK: mov w6, #7
; CHECK: mov w7, #8
; CHECK: str xzr, [sp]
; CHECK: mov x21, xzr
; CHECK: bl _params_in_reg2
Expand Down Expand Up @@ -398,14 +398,14 @@ declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, i8*
; CHECK: mov x27, x7
; CHECK: mov x28, x21
; Setup call arguments.
; CHECK: mov x0, #1
; CHECK: mov x1, #2
; CHECK: mov x2, #3
; CHECK: mov x3, #4
; CHECK: mov x4, #5
; CHECK: mov x5, #6
; CHECK: mov x6, #7
; CHECK: mov x7, #8
; CHECK: mov w0, #1
; CHECK: mov w1, #2
; CHECK: mov w2, #3
; CHECK: mov w3, #4
; CHECK: mov w4, #5
; CHECK: mov w5, #6
; CHECK: mov w6, #7
; CHECK: mov w7, #8
; CHECK: mov x21, xzr
; CHECK: bl _params_in_reg2
; Store swifterror %error_ptr_ref.
Expand Down Expand Up @@ -433,14 +433,14 @@ declare swiftcc void @params_in_reg2(i64, i64, i64, i64, i64, i64, i64, i64, i8*
; Save swifterror %err.
; CHECK: mov x19, x21
; Setup call.
; CHECK: mov x0, #1
; CHECK: mov x1, #2
; CHECK: mov x2, #3
; CHECK: mov x3, #4
; CHECK: mov x4, #5
; CHECK: mov x5, #6
; CHECK: mov x6, #7
; CHECK: mov x7, #8
; CHECK: mov w0, #1
; CHECK: mov w1, #2
; CHECK: mov w2, #3
; CHECK: mov w3, #4
; CHECK: mov w4, #5
; CHECK: mov w5, #6
; CHECK: mov w6, #7
; CHECK: mov w7, #8
; ... setup call with swiferror %error_ptr_ref.
; CHECK: ldr x21, [sp, #8]
; CHECK: bl _params_in_reg2
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/AArch64/arm64-fast-isel-addr-offset.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; RUN: llc -O0 -fast-isel-abort=1 -verify-machineinstrs -mtriple=arm64-apple-darwin < %s | FileCheck %s
; RUN: llc -O0 -fast-isel -fast-isel-abort=1 -verify-machineinstrs -mtriple=arm64-apple-darwin < %s | FileCheck %s

@sortlist = common global [5001 x i32] zeroinitializer, align 16
@sortlist2 = common global [5001 x i64] zeroinitializer, align 16
Expand Down
7 changes: 5 additions & 2 deletions llvm/test/CodeGen/X86/GlobalISel/add-ext.ll
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,19 @@ define void @PR20134_zext(i32* %a, i32 %i) {
; CHECK: # %bb.0:
; CHECK-NEXT: # kill: def $esi killed $esi def $rsi
; CHECK-NEXT: leal 1(%rsi), %eax
; CHECK-NEXT: movl %eax, %eax
; CHECK-NEXT: movq $4, %rcx
; CHECK-NEXT: imulq %rcx, %rax
; CHECK-NEXT: addq %rdi, %rax
; CHECK-NEXT: leal 2(%rsi), %edx
; CHECK-NEXT: movl %edx, %edx
; CHECK-NEXT: imulq %rcx, %rdx
; CHECK-NEXT: addq %rdi, %rdx
; CHECK-NEXT: movl (%rdx), %edx
; CHECK-NEXT: addl (%rax), %edx
; CHECK-NEXT: imulq %rcx, %rsi
; CHECK-NEXT: leaq (%rdi,%rsi), %rax
; CHECK-NEXT: movl %esi, %eax
; CHECK-NEXT: imulq %rcx, %rax
; CHECK-NEXT: addq %rdi, %rax
; CHECK-NEXT: movl %edx, (%rax)
; CHECK-NEXT: retq

Expand Down
6 changes: 4 additions & 2 deletions llvm/test/CodeGen/X86/GlobalISel/select-ext-x86-64.mir
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ body: |
; ALL-LABEL: name: anyext_s64_from_s8
; ALL: [[COPY:%[0-9]+]]:gr64_with_sub_8bit = COPY $rdi
; ALL: [[COPY1:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit
; ALL: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY1]], %subreg.sub_8bit
; ALL: [[MOVZX32rr8_:%[0-9]+]]:gr32 = MOVZX32rr8 [[COPY1]]
; ALL: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[MOVZX32rr8_]], %subreg.sub_32bit
; ALL: $rax = COPY [[SUBREG_TO_REG]]
; ALL: RET 0, implicit $rax
%0(s64) = COPY $rdi
Expand All @@ -161,7 +162,8 @@ body: |
; ALL-LABEL: name: anyext_s64_from_s16
; ALL: [[COPY:%[0-9]+]]:gr64 = COPY $rdi
; ALL: [[COPY1:%[0-9]+]]:gr16 = COPY [[COPY]].sub_16bit
; ALL: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[COPY1]], %subreg.sub_16bit
; ALL: [[MOVZX32rr16_:%[0-9]+]]:gr32 = MOVZX32rr16 [[COPY1]]
; ALL: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[MOVZX32rr16_]], %subreg.sub_32bit
; ALL: $rax = COPY [[SUBREG_TO_REG]]
; ALL: RET 0, implicit $rax
%0(s64) = COPY $rdi
Expand Down
3 changes: 2 additions & 1 deletion llvm/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ body: |
; CHECK-LABEL: name: zext_i32_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: [[MOV32rr:%[0-9]+]]:gr32 = MOV32rr [[COPY]]
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG 0, [[MOV32rr]], %subreg.sub_32bit
; CHECK: $rax = COPY [[SUBREG_TO_REG]]
; CHECK: RET 0, implicit $rax
%0:gpr(s32) = COPY $edi
Expand Down
18 changes: 18 additions & 0 deletions llvm/test/TableGen/GlobalISelEmitterSubreg.td
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,21 @@ def : Pat<(i32 (anyext i16:$src)), (INSERT_SUBREG (i32 (IMPLICIT_DEF)), (SUBSOME
// 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 SUBREG_TO_REG
def : Pat<(i32 (zext SOP:$src)),
(SUBREG_TO_REG (i64 0), (SUBSOME_INSN SOP:$src), sub0)>;
// CHECK-LABEL: (zext:{ *:[i32] } SOP:{ *:[i16] }:$src) => (SUBREG_TO_REG:{ *:[i32] } 0:{ *:[i64] }, (SUBSOME_INSN:{ *:[i16] } SOP:{ *:[i16] }:$src), sub0:{ *:[i32] })
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s16,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::SUBSOME_INSN,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::SUBREG_TO_REG,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddImm, /*InsnID*/0, /*Imm*/0,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*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*/2, /*RC SRegs*/0,
104 changes: 85 additions & 19 deletions llvm/utils/TableGen/GlobalISelEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3169,8 +3169,14 @@ class GlobalISelEmitter {
/// \p SubRegNode, and the subregister index defined by \p SubRegIdxNode.
/// If no register class is found, return None.
Optional<const CodeGenRegisterClass *>
inferSuperRegisterClassForNode(const TypeSetByHwMode &Ty,
TreePatternNode *SuperRegNode,
TreePatternNode *SubRegIdxNode);

/// Infer a CodeGenRegisterClass which suppoorts \p Ty and \p SubRegIdxNode.
/// Return None if no such class exists.
Optional<const CodeGenRegisterClass *>
inferSuperRegisterClass(const TypeSetByHwMode &Ty,
TreePatternNode *SuperRegNode,
TreePatternNode *SubRegIdxNode);

/// Return the CodeGenRegisterClass associated with \p Leaf if it has one.
Expand Down Expand Up @@ -3864,8 +3870,9 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
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));
Optional<const CodeGenRegisterClass *> SuperClass =
inferSuperRegisterClassForNode(Dst->getExtType(0), Dst->getChild(0),
Dst->getChild(2));
if (!SuperClass)
return failedImport(
"Cannot infer register class for INSERT_SUBREG operand #0");
Expand All @@ -3880,6 +3887,26 @@ GlobalISelEmitter::createAndImportSubInstructionRenderer(
return InsertPtOrError.get();
}

// Similar to INSERT_SUBREG, we also have to handle SUBREG_TO_REG as a
// subinstruction.
if (Target.getInstruction(Dst->getOperator()).TheDef->getName() ==
"SUBREG_TO_REG") {
auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
if (!SubClass)
return failedImport(
"Cannot infer register class from SUBREG_TO_REG child #1");
auto SuperClass = inferSuperRegisterClass(Dst->getExtType(0),
Dst->getChild(2));
if (!SuperClass)
return failedImport(
"Cannot infer register class for SUBREG_TO_REG operand #0");
M.insertAction<ConstrainOperandToRegClassAction>(
InsertPt, DstMIBuilder.getInsnID(), 0, **SuperClass);
M.insertAction<ConstrainOperandToRegClassAction>(
InsertPt, DstMIBuilder.getInsnID(), 2, **SubClass);
return InsertPtOrError.get();
}

M.insertAction<ConstrainOperandsToDefinitionAction>(InsertPt,
DstMIBuilder.getInsnID());
return InsertPtOrError.get();
Expand Down Expand Up @@ -4128,23 +4155,11 @@ GlobalISelEmitter::inferRegClassFromPattern(TreePatternNode *N) {

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;

assert(SubRegIdxNode && "Expected subregister index node!");
// 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());
Expand All @@ -4161,6 +4176,22 @@ GlobalISelEmitter::inferSuperRegisterClass(const TypeSetByHwMode &Ty,
return *RC;
}

Optional<const CodeGenRegisterClass *>
GlobalISelEmitter::inferSuperRegisterClassForNode(
const TypeSetByHwMode &Ty, TreePatternNode *SuperRegNode,
TreePatternNode *SubRegIdxNode) {
assert(SuperRegNode && "Expected super register node!");
// 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;
return inferSuperRegisterClass(Ty, SubRegIdxNode);
}

Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
// Keep track of the matchers and actions to emit.
int Score = P.getPatternComplexity(CGP);
Expand Down Expand Up @@ -4281,8 +4312,8 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
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));
auto MaybeSuperClass = inferSuperRegisterClassForNode(
VTy, Dst->getChild(0), Dst->getChild(2));
if (!MaybeSuperClass)
return failedImport(
"Cannot infer register class for INSERT_SUBREG operand #0");
Expand All @@ -4295,6 +4326,17 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
OM.addPredicate<RegisterBankOperandMatcher>(**MaybeSuperClass);
++OpIdx;
continue;
} else if (DstI.TheDef->getName() == "SUBREG_TO_REG") {
auto MaybeRegClass = inferSuperRegisterClass(VTy, Dst->getChild(2));
if (!MaybeRegClass)
return failedImport(
"Cannot infer register class for SUBREG_TO_REG operand #0");
OperandMatcher &OM = InsnMatcher.getOperand(OpIdx);
OM.setSymbolicName(DstIOperand.Name);
M.defineOperand(OM.getSymbolicName(), OM);
OM.addPredicate<RegisterBankOperandMatcher>(**MaybeRegClass);
++OpIdx;
continue;
} else if (DstIOpRec->isSubClassOf("RegisterOperand"))
DstIOpRec = DstIOpRec->getValueAsDef("RegClass");
else if (!DstIOpRec->isSubClassOf("RegisterClass"))
Expand Down Expand Up @@ -4393,7 +4435,7 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
if (!SubClass)
return failedImport(
"Cannot infer register class from INSERT_SUBREG operand #1");
auto SuperClass = inferSuperRegisterClass(
auto SuperClass = inferSuperRegisterClassForNode(
Src->getExtType(0), Dst->getChild(0), Dst->getChild(2));
if (!SuperClass)
return failedImport(
Expand All @@ -4405,6 +4447,30 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return std::move(M);
}

if (DstI.TheDef->getName() == "SUBREG_TO_REG") {
// We need to constrain the destination and subregister source.
assert(Src->getExtTypes().size() == 1 &&
"Expected Src of SUBREG_TO_REG to have one result type");

// Attempt to infer the subregister source from the first child. If it has
// an explicitly given register class, we'll use that. Otherwise, we will
// fail.
auto SubClass = inferRegClassFromPattern(Dst->getChild(1));
if (!SubClass)
return failedImport(
"Cannot infer register class from SUBREG_TO_REG child #1");
// We don't have a child to look at that might have a super register node.
auto SuperClass =
inferSuperRegisterClass(Src->getExtType(0), Dst->getChild(2));
if (!SuperClass)
return failedImport(
"Cannot infer register class for SUBREG_TO_REG operand #0");
M.addAction<ConstrainOperandToRegClassAction>(0, 0, **SuperClass);
M.addAction<ConstrainOperandToRegClassAction>(0, 2, **SubClass);
++NumPatternImported;
return std::move(M);
}

M.addAction<ConstrainOperandsToDefinitionAction>(0);

// We're done with this pattern! It's eligible for GISel emission; return it.
Expand Down