mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
Teach ReMaterialization to be more cunning about subregisters
This allows rematerialization during register coalescing to handle more cases involving operations like SUBREG_TO_REG which might need to be rematerialized using sub-register indices. For example, code like: v1(GPR64):sub_32 = MOVZ something v2(GPR64) = COPY v1(GPR64) should be convertable to: v2(GPR64):sub_32 = MOVZ something but previously we just gave up in places like this git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182872 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
88c744083d
commit
aae0fa998a
@ -733,7 +733,9 @@ bool RegisterCoalescer::removeCopyByCommutingDef(const CoalescerPair &CP,
|
||||
bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||
MachineInstr *CopyMI) {
|
||||
unsigned SrcReg = CP.isFlipped() ? CP.getDstReg() : CP.getSrcReg();
|
||||
unsigned SrcIdx = CP.isFlipped() ? CP.getDstIdx() : CP.getSrcIdx();
|
||||
unsigned DstReg = CP.isFlipped() ? CP.getSrcReg() : CP.getDstReg();
|
||||
unsigned DstIdx = CP.isFlipped() ? CP.getSrcIdx() : CP.getDstIdx();
|
||||
if (TargetRegisterInfo::isPhysicalRegister(SrcReg))
|
||||
return false;
|
||||
|
||||
@ -762,29 +764,38 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||
MachineOperand &DstOperand = CopyMI->getOperand(0);
|
||||
if (DstOperand.getSubReg() && !DstOperand.isUndef())
|
||||
return false;
|
||||
|
||||
const TargetRegisterClass *DefRC = TII->getRegClass(MCID, 0, TRI, *MF);
|
||||
if (!DefMI->isImplicitDef()) {
|
||||
// Make sure the copy destination register class fits the instruction
|
||||
// definition register class. The mismatch can happen as a result of earlier
|
||||
// extract_subreg, insert_subreg, subreg_to_reg coalescing.
|
||||
const TargetRegisterClass *RC = TII->getRegClass(MCID, 0, TRI, *MF);
|
||||
if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
|
||||
if (!MRI->constrainRegClass(DstReg, RC))
|
||||
if (TargetRegisterInfo::isPhysicalRegister(DstReg)) {
|
||||
unsigned NewDstReg = DstReg;
|
||||
|
||||
unsigned NewDstIdx = TRI->composeSubRegIndices(CP.getSrcIdx(),
|
||||
DefMI->getOperand(0).getSubReg());
|
||||
if (NewDstIdx)
|
||||
NewDstReg = TRI->getSubReg(DstReg, NewDstIdx);
|
||||
|
||||
// Finally, make sure that the physical subregister that will be
|
||||
// constructed later is permitted for the instruction.
|
||||
if (!DefRC->contains(NewDstReg))
|
||||
return false;
|
||||
} else if (!RC->contains(DstReg))
|
||||
return false;
|
||||
} else {
|
||||
// Theoretically, some stack frame reference could exist. Just make sure
|
||||
// it hasn't actually happened.
|
||||
assert(TargetRegisterInfo::isVirtualRegister(DstReg) &&
|
||||
"Only expect to deal with virtual or physical registers");
|
||||
}
|
||||
}
|
||||
|
||||
MachineBasicBlock *MBB = CopyMI->getParent();
|
||||
MachineBasicBlock::iterator MII =
|
||||
llvm::next(MachineBasicBlock::iterator(CopyMI));
|
||||
TII->reMaterialize(*MBB, MII, DstReg, 0, DefMI, *TRI);
|
||||
TII->reMaterialize(*MBB, MII, DstReg, SrcIdx, DefMI, *TRI);
|
||||
MachineInstr *NewMI = prior(MII);
|
||||
|
||||
// The original DefMI may have been a subregister def, but the full register
|
||||
// class of its destination matches the destination of CopyMI, and CopyMI is
|
||||
// either a full register def or is read-undef. Therefore we can clear the
|
||||
// subregister index on the rematerialized instruction.
|
||||
NewMI->getOperand(0).setSubReg(0);
|
||||
LIS->ReplaceMachineInstrInMaps(CopyMI, NewMI);
|
||||
CopyMI->eraseFromParent();
|
||||
ErasedInstrs.insert(CopyMI);
|
||||
|
||||
// NewMI may have dead implicit defs (E.g. EFLAGS for MOV<bits>r0 on X86).
|
||||
// We need to remember these so we can add intervals once we insert
|
||||
@ -800,6 +811,46 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||
}
|
||||
}
|
||||
|
||||
if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
|
||||
unsigned NewIdx = NewMI->getOperand(0).getSubReg();
|
||||
const TargetRegisterClass *RCForInst;
|
||||
if (NewIdx)
|
||||
RCForInst = TRI->getMatchingSuperRegClass(MRI->getRegClass(DstReg), DefRC,
|
||||
NewIdx);
|
||||
|
||||
if (MRI->constrainRegClass(DstReg, DefRC)) {
|
||||
// The materialized instruction is quite capable of setting DstReg
|
||||
// directly, but it may still have a now-trivial subregister index which
|
||||
// we should clear.
|
||||
NewMI->getOperand(0).setSubReg(0);
|
||||
} else if (NewIdx && RCForInst) {
|
||||
// The subreg index on NewMI is essential; we still have to make sure
|
||||
// DstReg:idx is in a class that NewMI can use.
|
||||
MRI->constrainRegClass(DstReg, RCForInst);
|
||||
} else {
|
||||
// DstReg is actually incompatible with NewMI, we have to move to a
|
||||
// super-reg's class. This could come from a sequence like:
|
||||
// GR32 = MOV32r0
|
||||
// GR8 = COPY GR32:sub_8
|
||||
MRI->setRegClass(DstReg, CP.getNewRC());
|
||||
updateRegDefsUses(DstReg, DstReg, DstIdx);
|
||||
NewMI->getOperand(0).setSubReg(
|
||||
TRI->composeSubRegIndices(SrcIdx, DefMI->getOperand(0).getSubReg()));
|
||||
}
|
||||
} else if (NewMI->getOperand(0).getReg() != DstReg) {
|
||||
// The New instruction may be defining a sub-register of what's actually
|
||||
// been asked for. If so it must implicitly define the whole thing.
|
||||
assert(TargetRegisterInfo::isPhysicalRegister(DstReg) &&
|
||||
"Only expect virtual or physical registers in remat");
|
||||
NewMI->addOperand(MachineOperand::CreateReg(DstReg,
|
||||
true /*IsDef*/,
|
||||
true /*IsImp*/,
|
||||
false /*IsKill*/));
|
||||
}
|
||||
|
||||
if (NewMI->getOperand(0).getSubReg())
|
||||
NewMI->getOperand(0).setIsUndef();
|
||||
|
||||
// CopyMI may have implicit operands, transfer them over to the newly
|
||||
// rematerialized instruction. And update implicit def interval valnos.
|
||||
for (unsigned i = CopyMI->getDesc().getNumOperands(),
|
||||
@ -814,8 +865,6 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||
}
|
||||
}
|
||||
|
||||
LIS->ReplaceMachineInstrInMaps(CopyMI, NewMI);
|
||||
|
||||
SlotIndex NewMIIdx = LIS->getInstructionIndex(NewMI);
|
||||
for (unsigned i = 0, e = NewMIImplDefs.size(); i != e; ++i) {
|
||||
unsigned Reg = NewMIImplDefs[i];
|
||||
@ -824,8 +873,6 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||
LI->createDeadDef(NewMIIdx.getRegSlot(), LIS->getVNInfoAllocator());
|
||||
}
|
||||
|
||||
CopyMI->eraseFromParent();
|
||||
ErasedInstrs.insert(CopyMI);
|
||||
DEBUG(dbgs() << "Remat: " << *NewMI);
|
||||
++NumReMats;
|
||||
|
||||
|
@ -91,7 +91,7 @@ define void @indirect_tail() {
|
||||
%fptr = load void(i32)** @func
|
||||
tail call void %fptr(i32 42)
|
||||
ret void
|
||||
; CHECK: movz w0, #42
|
||||
; CHECK: ldr [[FPTR:x[1-9]+]], [{{x[0-9]+}}, #:lo12:func]
|
||||
; CHECK: movz w0, #42
|
||||
; CHECK: br [[FPTR]]
|
||||
}
|
||||
}
|
||||
|
@ -16,21 +16,21 @@
|
||||
; return 0;
|
||||
; }
|
||||
|
||||
; First make sure main_arr is where we expect it: sp + 12 == x29 - 420:
|
||||
; First make sure main_arr is where we expect it: sp + 4 == x29 - 412:
|
||||
; CHECK: main:
|
||||
; CHECK: sub sp, sp, #448
|
||||
; CHECK: stp x29, x30, [sp, #432]
|
||||
; CHECK: add x29, sp, #432
|
||||
; CHECK: add {{x[0-9]+}}, sp, #12
|
||||
; CHECK: sub sp, sp, #432
|
||||
; CHECK: stp x29, x30, [sp, #416]
|
||||
; CHECK: add x29, sp, #416
|
||||
; CHECK: add {{x[0-9]+}}, sp, #4
|
||||
|
||||
; Now check the debugging information reflects this:
|
||||
; CHECK: DW_TAG_variable
|
||||
; CHECK-NEXT: .word .Linfo_string7
|
||||
|
||||
; Rather hard-coded, but 145 => DW_OP_fbreg and the .ascii is LEB128 encoded -420.
|
||||
; Rather hard-coded, but 145 => DW_OP_fbreg and the .ascii is LEB128 encoded -412.
|
||||
; CHECK: DW_AT_location
|
||||
; CHECK-NEXT: .byte 145
|
||||
; CHECK-NEXT: .ascii "\334|"
|
||||
; CHECK-NEXT: .ascii "\344|"
|
||||
|
||||
; CHECK: .Linfo_string7:
|
||||
; CHECK-NEXT: main_arr
|
||||
|
Loading…
Reference in New Issue
Block a user