Index: llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h +++ llvm/include/llvm/CodeGen/GlobalISel/InstructionSelector.h @@ -293,6 +293,13 @@ /// - 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 Index: llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h =================================================================== --- llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h +++ llvm/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h @@ -859,16 +859,25 @@ 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; } Index: llvm/test/CodeGen/X86/GlobalISel/select-copy.mir =================================================================== --- llvm/test/CodeGen/X86/GlobalISel/select-copy.mir +++ llvm/test/CodeGen/X86/GlobalISel/select-copy.mir @@ -88,7 +88,8 @@ 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 @@ 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: '' } Index: llvm/test/CodeGen/X86/GlobalISel/select-ext.mir =================================================================== --- llvm/test/CodeGen/X86/GlobalISel/select-ext.mir +++ llvm/test/CodeGen/X86/GlobalISel/select-ext.mir @@ -374,8 +374,8 @@ 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 @@ - { 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 @@ 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 @@ - { 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 Index: llvm/test/CodeGen/X86/GlobalISel/shl-scalar-widening.ll =================================================================== --- llvm/test/CodeGen/X86/GlobalISel/shl-scalar-widening.ll +++ llvm/test/CodeGen/X86/GlobalISel/shl-scalar-widening.ll @@ -10,13 +10,13 @@ ; %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 Index: llvm/test/CodeGen/X86/GlobalISel/x86-select-sdiv.mir =================================================================== --- llvm/test/CodeGen/X86/GlobalISel/x86-select-sdiv.mir +++ llvm/test/CodeGen/X86/GlobalISel/x86-select-sdiv.mir @@ -40,14 +40,16 @@ ; 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) Index: llvm/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir =================================================================== --- llvm/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir +++ llvm/test/CodeGen/X86/GlobalISel/x86_64-select-zext.mir @@ -198,8 +198,10 @@ ; 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 Index: llvm/test/TableGen/GlobalISelEmitterSubreg.td =================================================================== --- llvm/test/TableGen/GlobalISelEmitterSubreg.td +++ llvm/test/TableGen/GlobalISelEmitterSubreg.td @@ -34,6 +34,7 @@ def DOP : RegisterOperand; 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 @@ // 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)>; Index: llvm/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -2585,26 +2585,37 @@ 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 @@ //===- GlobalISelEmitter class --------------------------------------------===// +static Expected getInstResultType(const TreePatternNode *Dst) { + ArrayRef ChildTypes = Dst->getExtTypes(); + if (ChildTypes.size() != 1) + return failedImport("Dst pattern child has multiple results"); + + Optional 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); @@ -4040,20 +4067,13 @@ } if (DstChild->getOperator()->isSubClassOf("Instruction")) { - ArrayRef ChildTypes = DstChild->getExtTypes(); - if (ChildTypes.size() != 1) - return failedImport("Dst pattern child has multiple results"); - - Optional 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( - InsertPt, OpTyOrNone.getValue(), TempRegID); + InsertPt, *OpTy, TempRegID); DstMIBuilder.addRenderer(TempRegID); auto InsertPtOrError = createAndImportSubInstructionRenderer( @@ -4303,33 +4323,51 @@ // 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"); - - if (DefInit *SubRegInit = - dyn_cast(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"); - - CodeGenRegisterClass *RC = CGRegs.getRegClass(RCDef); - CodeGenSubRegIndex *SubIdx = CGRegs.getSubRegIdx(SubRegInit->getDef()); - - 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"); - } + DefInit *SubRegInit = dyn_cast(Dst->getChild(1)->getLeafValue()); + if (!SubRegInit) + return failedImport("EXTRACT_SUBREG child #1 is not a subreg index"); + + 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(); - DstMIBuilder.addRenderer(Dst->getChild(0)->getName(), - SubIdx); + unsigned TempRegID = M.allocateTempRegID(); + InsertPt = M.insertAction( + InsertPt, *ExtractSrcTy, TempRegID); + + auto InsertPtOrError = createAndImportSubInstructionRenderer( + ++InsertPt, M, ValChild, TempRegID); + if (auto Error = InsertPtOrError.takeError()) + return std::move(Error); + + DstMIBuilder.addRenderer(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(Dst->getChild(0)->getName(), + SubIdx); + return InsertPt; } if (Name == "REG_SEQUENCE") { @@ -4731,15 +4769,13 @@ 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)); @@ -4834,6 +4870,11 @@ 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(0, 0, *SrcRCDstRCPair->second); M.addAction(0, 1, *SrcRCDstRCPair->first);