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:
parent
a3296c73e9
commit
653b9c5a80
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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: '' }
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)>;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user