1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

TableGen/GlobalISel: Handle non-leaf EXTRACT_SUBREG

This previously only handled EXTRACT_SUBREGs from leafs, such as
operands directly in the original output. Handle extracting from a
result instruction.
This commit is contained in:
Matt Arsenault 2020-01-14 16:02:02 -05:00
parent a3296c73e9
commit 653b9c5a80
9 changed files with 187 additions and 68 deletions

View File

@ -293,6 +293,13 @@ enum {
/// - TempRegFlags - The register flags to set
GIR_AddTempRegister,
/// Add a temporary register to the specified instruction
/// - InsnID - Instruction ID to modify
/// - TempRegID - The temporary register ID to add
/// - TempRegFlags - The register flags to set
/// - SubRegIndex - The subregister index to set
GIR_AddTempSubRegister,
/// Add an immediate to the specified instruction
/// - InsnID - Instruction ID to modify
/// - Imm - The immediate to add

View File

@ -859,16 +859,25 @@ bool InstructionSelector::executeMatchTable(
break;
}
case GIR_AddTempRegister: {
case GIR_AddTempRegister:
case GIR_AddTempSubRegister: {
int64_t InsnID = MatchTable[CurrentIdx++];
int64_t TempRegID = MatchTable[CurrentIdx++];
uint64_t TempRegFlags = MatchTable[CurrentIdx++];
unsigned SubReg = 0;
if (MatcherOpcode == GIR_AddTempSubRegister)
SubReg = MatchTable[CurrentIdx++];
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
OutMIs[InsnID].addReg(State.TempRegisters[TempRegID], TempRegFlags);
OutMIs[InsnID].addReg(State.TempRegisters[TempRegID], TempRegFlags, SubReg);
DEBUG_WITH_TYPE(TgtInstructionSelector::getName(),
dbgs() << CurrentIdx << ": GIR_AddTempRegister(OutMIs["
<< InsnID << "], TempRegisters[" << TempRegID
<< "], " << TempRegFlags << ")\n");
<< "]";
if (SubReg)
dbgs() << '.' << TRI.getSubRegIndexName(SubReg);
dbgs() << ", " << TempRegFlags << ")\n");
break;
}

View File

@ -88,7 +88,8 @@ legalized: true
regBankSelected: true
# ALL: registers:
# ALL-NEXT: - { id: 0, class: gr16[[ABCD:(_abcd)?]], preferred-register: '' }
# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8_abcd_l, preferred-register: '' }
# X64-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' }
registers:
- { id: 0, class: gpr, preferred-register: '' }
@ -148,7 +149,8 @@ legalized: true
regBankSelected: true
# ALL: registers:
# ALL-NEXT: - { id: 0, class: gr32[[ABCD:(_abcd)?]], preferred-register: '' }
# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8_abcd_l, preferred-register: '' }
# X64-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' }
registers:
- { id: 0, class: gpr, preferred-register: '' }

View File

@ -374,8 +374,8 @@ alignment: 16
legalized: true
regBankSelected: true
# X32: registers:
# X32-NEXT: - { id: 0, class: gr32_abcd, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# X32-NEXT: - { id: 0, class: gr32, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8_abcd_l, preferred-register: '' }
# X32-NEXT: - { id: 2, class: gr16, preferred-register: '' }
#
# X64: registers:
@ -386,10 +386,15 @@ registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
# X32: %0:gr32_abcd = COPY $edi
# X64: %0:gr32 = COPY $edi
# ALL-NEXT: %1:gr8 = COPY %0.sub_8bit
# ALL-NEXT: %2:gr16 = SUBREG_TO_REG 0, %1, %subreg.sub_8bit
# X32: %0:gr32 = COPY $edi
# X32-NEXT: %4:gr32_abcd = COPY %0
# X32-NEXT: %1:gr8_abcd_l = COPY %4.sub_8bit
# X64: %0:gr32 = COPY $edi
# X64-NEXT: %1:gr8 = COPY %0.sub_8bit
# ALL-NEXT: %3:gr32 = MOVZX32rr8 %1
# ALL-NEXT: %2:gr16 = COPY %3.sub_16bit
# ALL-NEXT: $ax = COPY %2
# ALL-NEXT: RET 0, implicit $ax
body: |
@ -409,8 +414,8 @@ alignment: 16
legalized: true
regBankSelected: true
# X32: registers:
# X32-NEXT: - { id: 0, class: gr32_abcd, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8, preferred-register: '' }
# X32-NEXT: - { id: 0, class: gr32, preferred-register: '' }
# X32-NEXT: - { id: 1, class: gr8_abcd_l, preferred-register: '' }
# X32-NEXT: - { id: 2, class: gr32, preferred-register: '' }
#
# X64: registers:
@ -421,9 +426,13 @@ registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
# X32: %0:gr32_abcd = COPY $edi
# X32: %0:gr32 = COPY $edi
# X32-NEXT: %3:gr32_abcd = COPY %0
# X32-NEXT: %1:gr8_abcd_l = COPY %3.sub_8bit
# X64: %0:gr32 = COPY $edi
# ALL-NEXT: %1:gr8 = COPY %0.sub_8bit
# X64-NEXT: %1:gr8 = COPY %0.sub_8bit
# ALL-NEXT: %2:gr32 = MOVZX32rr8 %1
# ALL-NEXT: $eax = COPY %2
# ALL-NEXT: RET 0, implicit $eax

View File

@ -10,13 +10,13 @@ define i16 @test_shl_i4(i16 %v, i16 %a, i16 %b) {
; %b: 72 (0000 0000 0100 1000)
; X64-LABEL: test_shl_i4:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: # kill: def $esi killed $esi def $rsi
; X64-NEXT: # kill: def $edx killed $edx def $rdx
; X64-NEXT: leal (%rdx,%rsi), %ecx
; X64-NEXT: andb $15, %cl
; X64-NEXT: # kill: def $cl killed $cl killed $ecx
; X64-NEXT: shlb %cl, %al
; X64-NEXT: shlb %cl, %dil
; X64-NEXT: movzbl %dil, %eax
; X64-NEXT: andw $15, %ax
; X64-NEXT: # kill: def $ax killed $ax killed $eax
; X64-NEXT: retq

View File

@ -40,14 +40,16 @@ body: |
; CHECK-LABEL: name: test_sdiv_i8
; CHECK: liveins: $edi, $esi
; CHECK: [[COPY:%[0-9]+]]:gr32_abcd = COPY $edi
; CHECK: [[COPY1:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit
; CHECK: [[COPY2:%[0-9]+]]:gr32_abcd = COPY $esi
; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY2]].sub_8bit
; CHECK: $ax = MOVSX16rr8 [[COPY1]]
; CHECK: IDIV8r [[COPY3]], implicit-def $al, implicit-def $ah, implicit-def $eflags, implicit $ax
; CHECK: [[COPY4:%[0-9]+]]:gr8 = COPY $al
; CHECK: $al = COPY [[COPY4]]
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
; CHECK: [[COPY1:%[0-9]+]]:gr32_abcd = COPY [[COPY]]
; CHECK: [[COPY2:%[0-9]+]]:gr8_abcd_l = COPY [[COPY1]].sub_8bit
; CHECK: [[COPY3:%[0-9]+]]:gr32 = COPY $esi
; CHECK: [[COPY4:%[0-9]+]]:gr32_abcd = COPY [[COPY3]]
; CHECK: [[COPY5:%[0-9]+]]:gr8_abcd_l = COPY [[COPY4]].sub_8bit
; CHECK: $ax = MOVSX16rr8 [[COPY2]]
; CHECK: IDIV8r [[COPY5]], implicit-def $al, implicit-def $ah, implicit-def $eflags, implicit $ax
; CHECK: [[COPY6:%[0-9]+]]:gr8 = COPY $al
; CHECK: $al = COPY [[COPY6]]
; CHECK: RET 0, implicit $al
%2:gpr(s32) = COPY $edi
%0:gpr(s8) = G_TRUNC %2(s32)

View File

@ -198,8 +198,10 @@ body: |
; CHECK: liveins: $edi
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
; CHECK: [[COPY1:%[0-9]+]]:gr16 = COPY [[COPY]].sub_16bit
; CHECK: [[AND16ri:%[0-9]+]]:gr16 = AND16ri [[COPY1]], 255, implicit-def $eflags
; CHECK: $ax = COPY [[AND16ri]]
; CHECK: [[COPY2:%[0-9]+]]:gr8 = COPY [[COPY1]].sub_8bit
; CHECK: [[MOVZX32rr8_:%[0-9]+]]:gr32 = MOVZX32rr8 [[COPY2]]
; CHECK: [[COPY3:%[0-9]+]]:gr16 = COPY [[MOVZX32rr8_]].sub_16bit
; CHECK: $ax = COPY [[COPY3]]
; CHECK: RET 0, implicit $ax
%1:gpr(s32) = COPY $edi
%3:gpr(s16) = G_CONSTANT i16 255

View File

@ -34,6 +34,7 @@ def SOP : RegisterOperand<SRegs>;
def DOP : RegisterOperand<DRegs>;
def SOME_INSN : I<(outs DRegs:$dst), (ins DOP:$src), []>;
def SUBSOME_INSN : I<(outs SRegs:$dst), (ins SOP:$src), []>;
def SUBSOME_INSN2 : I<(outs SRegs:$dst), (ins SOP:$src), []>;
// We should skip cases where we don't have a given register class for the
// subregister source.
@ -132,6 +133,52 @@ def : Pat<(i16 (trunc (not DOP:$src))),
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/1, /*RC DRegs*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SUBSOME_INSN,
// Test an extract from an output instruction result (nonleaf)
def : Pat<(i16 (trunc (bitreverse DOP:$src))),
(EXTRACT_SUBREG (SOME_INSN DOP:$src), sub0)>;
// CHECK-LABEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_BITREVERSE,
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/Test::DRegsRegClassID,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/1,
// CHECK-NEXT: // (trunc:{ *:[i16] } (bitreverse:{ *:[i32] } DOP:{ *:[i32] }:$src)) => (EXTRACT_SUBREG:{ *:[i16] } (SOME_INSN:{ *:[i32] } DOP:{ *:[i32] }:$src), sub0:{ *:[i32] })
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/GILLT_s32,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/MyTarget::SOME_INSN,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/1, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/0, /*OldInsnID*/0, /*OpIdx*/0, // dst
// CHECK-NEXT: GIR_AddTempSubRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0, sub0,
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/0, /*RC SRegs*/0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/0, /*Op*/1, /*RC DRegs*/1,
// EXTRACT_SUBREG is subinstruction, but also doesn't have a leaf input
// CHECK-LABEL: GIM_CheckOpcode, /*MI*/1, TargetOpcode::G_CTPOP,
// CHECK-NEXT: GIM_CheckType, /*MI*/1, /*Op*/1, /*Type*/GILLT_s32,
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/1, /*Op*/1, /*RC*/Test::DRegsRegClassID,
// CHECK-NEXT: GIM_CheckIsSafeToFold, /*InsnID*/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*/MyTarget::SOME_INSN,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/2, /*TempRegID*/1, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/2, /*OldInsnID*/1, /*OpIdx*/1, // src
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/2,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::COPY,
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/RegState::Define,
// CHECK-NEXT: GIR_AddTempSubRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/0, sub0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/0, /*RC SRegs*/0,
// CHECK-NEXT: GIR_ConstrainOperandRC, /*InsnID*/1, /*Op*/1, /*RC DRegs*/1,
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/MyTarget::SUBSOME_INSN2,
// 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,
def : Pat<(i16 (trunc (ctpop DOP:$src))),
(SUBSOME_INSN2 (EXTRACT_SUBREG (SOME_INSN DOP:$src), sub0))>;
// Test an EXTRACT_SUBREG that is the final instruction.
def : Pat<(i16 (trunc DOP:$src)),
(EXTRACT_SUBREG DOP:$src, sub0)>;

View File

@ -2585,26 +2585,37 @@ class TempRegRenderer : public OperandRenderer {
protected:
unsigned InsnID;
unsigned TempRegID;
const CodeGenSubRegIndex *SubRegIdx;
bool IsDef;
public:
TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false)
TempRegRenderer(unsigned InsnID, unsigned TempRegID, bool IsDef = false,
const CodeGenSubRegIndex *SubReg = nullptr)
: OperandRenderer(OR_Register), InsnID(InsnID), TempRegID(TempRegID),
IsDef(IsDef) {}
SubRegIdx(SubReg), IsDef(IsDef) {}
static bool classof(const OperandRenderer *R) {
return R->getKind() == OR_TempRegister;
}
void emitRenderOpcodes(MatchTable &Table, RuleMatcher &Rule) const override {
Table << MatchTable::Opcode("GIR_AddTempRegister")
<< MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
if (SubRegIdx) {
assert(!IsDef);
Table << MatchTable::Opcode("GIR_AddTempSubRegister");
} else
Table << MatchTable::Opcode("GIR_AddTempRegister");
Table << MatchTable::Comment("InsnID") << MatchTable::IntValue(InsnID)
<< MatchTable::Comment("TempRegID") << MatchTable::IntValue(TempRegID)
<< MatchTable::Comment("TempRegFlags");
if (IsDef)
Table << MatchTable::NamedValue("RegState::Define");
else
Table << MatchTable::IntValue(0);
if (SubRegIdx)
Table << MatchTable::NamedValue(SubRegIdx->getQualifiedName());
Table << MatchTable::LineBreak;
}
};
@ -3260,6 +3271,22 @@ void SameOperandMatcher::emitPredicateOpcodes(MatchTable &Table,
//===- GlobalISelEmitter class --------------------------------------------===//
static Expected<LLTCodeGen> getInstResultType(const TreePatternNode *Dst) {
ArrayRef<TypeSetByHwMode> ChildTypes = Dst->getExtTypes();
if (ChildTypes.size() != 1)
return failedImport("Dst pattern child has multiple results");
Optional<LLTCodeGen> MaybeOpTy;
if (ChildTypes.front().isMachineValueType()) {
MaybeOpTy =
MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
}
if (!MaybeOpTy)
return failedImport("Dst operand has an unsupported type");
return *MaybeOpTy;
}
class GlobalISelEmitter {
public:
explicit GlobalISelEmitter(RecordKeeper &RK);
@ -4044,20 +4071,13 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderer(
}
if (DstChild->getOperator()->isSubClassOf("Instruction")) {
ArrayRef<TypeSetByHwMode> ChildTypes = DstChild->getExtTypes();
if (ChildTypes.size() != 1)
return failedImport("Dst pattern child has multiple results");
Optional<LLTCodeGen> OpTyOrNone = None;
if (ChildTypes.front().isMachineValueType())
OpTyOrNone =
MVTToLLT(ChildTypes.front().getMachineValueType().SimpleTy);
if (!OpTyOrNone)
return failedImport("Dst operand has an unsupported type");
auto OpTy = getInstResultType(DstChild);
if (!OpTy)
return OpTy.takeError();
unsigned TempRegID = Rule.allocateTempRegID();
InsertPt = Rule.insertAction<MakeTempRegisterAction>(
InsertPt, OpTyOrNone.getValue(), TempRegID);
InsertPt, *OpTy, TempRegID);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID);
auto InsertPtOrError = createAndImportSubInstructionRenderer(
@ -4307,33 +4327,51 @@ Expected<action_iterator> GlobalISelEmitter::importExplicitUseRenderers(
// EXTRACT_SUBREG needs to use a subregister COPY.
if (Name == "EXTRACT_SUBREG") {
if (!Dst->getChild(0)->isLeaf())
return failedImport("EXTRACT_SUBREG child #1 is not a leaf");
DefInit *SubRegInit = dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue());
if (!SubRegInit)
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
if (DefInit *SubRegInit =
dyn_cast<DefInit>(Dst->getChild(1)->getLeafValue())) {
Record *RCDef = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
if (!RCDef)
return failedImport("EXTRACT_SUBREG child #0 could not "
"be coerced to a register class");
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
TreePatternNode *ValChild = Dst->getChild(0);
if (!ValChild->isLeaf()) {
// We really have to handle the source instruction, and then insert a
// copy from the subregister.
auto ExtractSrcTy = getInstResultType(ValChild);
if (!ExtractSrcTy)
return ExtractSrcTy.takeError();
CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef);
CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef());
unsigned TempRegID = M.allocateTempRegID();
InsertPt = M.insertAction<MakeTempRegisterAction>(
InsertPt, *ExtractSrcTy, TempRegID);
const auto SrcRCDstRCPair =
RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
if (SrcRCDstRCPair.hasValue()) {
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
if (SrcRCDstRCPair->first != RC)
return failedImport("EXTRACT_SUBREG requires an additional COPY");
}
auto InsertPtOrError = createAndImportSubInstructionRenderer(
++InsertPt, M, ValChild, TempRegID);
if (auto Error = InsertPtOrError.takeError())
return std::move(Error);
DstMIBuilder.addRenderer<CopySubRegRenderer>(Dst->getChild(0)->getName(),
SubIdx);
DstMIBuilder.addRenderer<TempRegRenderer>(TempRegID, false, SubIdx);
return InsertPt;
}
return failedImport("EXTRACT_SUBREG child #1 is not a subreg index");
// If this is a source operand, this is just a subregister copy.
Record *RCDef = getInitValueAsRegClass(ValChild->getLeafValue());
if (!RCDef)
return failedImport("EXTRACT_SUBREG child #0 could not "
"be coerced to a register class");
CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef);
const auto SrcRCDstRCPair =
RC->getMatchingSubClassWithSubRegs(CGRegs, SubIdx);
if (SrcRCDstRCPair.hasValue()) {
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
if (SrcRCDstRCPair->first != RC)
return failedImport("EXTRACT_SUBREG requires an additional COPY");
}
DstMIBuilder.addRenderer<CopySubRegRenderer>(Dst->getChild(0)->getName(),
SubIdx);
return InsertPt;
}
if (Name == "REG_SEQUENCE") {
@ -4735,15 +4773,13 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
if (DstIOpRec == nullptr)
return failedImport("REG_SEQUENCE operand #0 isn't a register class");
} else if (DstIName == "EXTRACT_SUBREG") {
if (!Dst->getChild(0)->isLeaf())
return failedImport("EXTRACT_SUBREG operand #0 isn't a leaf");
auto InferredClass = inferRegClassFromPattern(Dst->getChild(0));
if (!InferredClass)
return failedImport("Could not infer class for EXTRACT_SUBREG operand #0");
// We can assume that a subregister is in the same bank as it's super
// register.
DstIOpRec = getInitValueAsRegClass(Dst->getChild(0)->getLeafValue());
if (DstIOpRec == nullptr)
return failedImport("EXTRACT_SUBREG operand #0 isn't a register class");
DstIOpRec = (*InferredClass)->getDef();
} else if (DstIName == "INSERT_SUBREG") {
auto MaybeSuperClass = inferSuperRegisterClassForNode(
VTy, Dst->getChild(0), Dst->getChild(2));
@ -4838,6 +4874,11 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
const auto SrcRCDstRCPair =
(*SuperClass)->getMatchingSubClassWithSubRegs(CGRegs, *SubIdx);
if (!SrcRCDstRCPair) {
return failedImport("subreg index is incompatible "
"with inferred reg class");
}
assert(SrcRCDstRCPair->second && "Couldn't find a matching subclass");
M.addAction<ConstrainOperandToRegClassAction>(0, 0, *SrcRCDstRCPair->second);
M.addAction<ConstrainOperandToRegClassAction>(0, 1, *SrcRCDstRCPair->first);