mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-27 13:30:05 +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,
|
bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
||||||
MachineInstr *CopyMI) {
|
MachineInstr *CopyMI) {
|
||||||
unsigned SrcReg = CP.isFlipped() ? CP.getDstReg() : CP.getSrcReg();
|
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 DstReg = CP.isFlipped() ? CP.getSrcReg() : CP.getDstReg();
|
||||||
|
unsigned DstIdx = CP.isFlipped() ? CP.getSrcIdx() : CP.getDstIdx();
|
||||||
if (TargetRegisterInfo::isPhysicalRegister(SrcReg))
|
if (TargetRegisterInfo::isPhysicalRegister(SrcReg))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -762,29 +764,38 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
|||||||
MachineOperand &DstOperand = CopyMI->getOperand(0);
|
MachineOperand &DstOperand = CopyMI->getOperand(0);
|
||||||
if (DstOperand.getSubReg() && !DstOperand.isUndef())
|
if (DstOperand.getSubReg() && !DstOperand.isUndef())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
const TargetRegisterClass *DefRC = TII->getRegClass(MCID, 0, TRI, *MF);
|
||||||
if (!DefMI->isImplicitDef()) {
|
if (!DefMI->isImplicitDef()) {
|
||||||
// Make sure the copy destination register class fits the instruction
|
if (TargetRegisterInfo::isPhysicalRegister(DstReg)) {
|
||||||
// definition register class. The mismatch can happen as a result of earlier
|
unsigned NewDstReg = DstReg;
|
||||||
// extract_subreg, insert_subreg, subreg_to_reg coalescing.
|
|
||||||
const TargetRegisterClass *RC = TII->getRegClass(MCID, 0, TRI, *MF);
|
unsigned NewDstIdx = TRI->composeSubRegIndices(CP.getSrcIdx(),
|
||||||
if (TargetRegisterInfo::isVirtualRegister(DstReg)) {
|
DefMI->getOperand(0).getSubReg());
|
||||||
if (!MRI->constrainRegClass(DstReg, RC))
|
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;
|
return false;
|
||||||
} else if (!RC->contains(DstReg))
|
} else {
|
||||||
return false;
|
// 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 *MBB = CopyMI->getParent();
|
||||||
MachineBasicBlock::iterator MII =
|
MachineBasicBlock::iterator MII =
|
||||||
llvm::next(MachineBasicBlock::iterator(CopyMI));
|
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);
|
MachineInstr *NewMI = prior(MII);
|
||||||
|
|
||||||
// The original DefMI may have been a subregister def, but the full register
|
LIS->ReplaceMachineInstrInMaps(CopyMI, NewMI);
|
||||||
// class of its destination matches the destination of CopyMI, and CopyMI is
|
CopyMI->eraseFromParent();
|
||||||
// either a full register def or is read-undef. Therefore we can clear the
|
ErasedInstrs.insert(CopyMI);
|
||||||
// subregister index on the rematerialized instruction.
|
|
||||||
NewMI->getOperand(0).setSubReg(0);
|
|
||||||
|
|
||||||
// NewMI may have dead implicit defs (E.g. EFLAGS for MOV<bits>r0 on X86).
|
// 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
|
// 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
|
// CopyMI may have implicit operands, transfer them over to the newly
|
||||||
// rematerialized instruction. And update implicit def interval valnos.
|
// rematerialized instruction. And update implicit def interval valnos.
|
||||||
for (unsigned i = CopyMI->getDesc().getNumOperands(),
|
for (unsigned i = CopyMI->getDesc().getNumOperands(),
|
||||||
@ -814,8 +865,6 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LIS->ReplaceMachineInstrInMaps(CopyMI, NewMI);
|
|
||||||
|
|
||||||
SlotIndex NewMIIdx = LIS->getInstructionIndex(NewMI);
|
SlotIndex NewMIIdx = LIS->getInstructionIndex(NewMI);
|
||||||
for (unsigned i = 0, e = NewMIImplDefs.size(); i != e; ++i) {
|
for (unsigned i = 0, e = NewMIImplDefs.size(); i != e; ++i) {
|
||||||
unsigned Reg = NewMIImplDefs[i];
|
unsigned Reg = NewMIImplDefs[i];
|
||||||
@ -824,8 +873,6 @@ bool RegisterCoalescer::reMaterializeTrivialDef(CoalescerPair &CP,
|
|||||||
LI->createDeadDef(NewMIIdx.getRegSlot(), LIS->getVNInfoAllocator());
|
LI->createDeadDef(NewMIIdx.getRegSlot(), LIS->getVNInfoAllocator());
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyMI->eraseFromParent();
|
|
||||||
ErasedInstrs.insert(CopyMI);
|
|
||||||
DEBUG(dbgs() << "Remat: " << *NewMI);
|
DEBUG(dbgs() << "Remat: " << *NewMI);
|
||||||
++NumReMats;
|
++NumReMats;
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ define void @indirect_tail() {
|
|||||||
%fptr = load void(i32)** @func
|
%fptr = load void(i32)** @func
|
||||||
tail call void %fptr(i32 42)
|
tail call void %fptr(i32 42)
|
||||||
ret void
|
ret void
|
||||||
; CHECK: movz w0, #42
|
|
||||||
; CHECK: ldr [[FPTR:x[1-9]+]], [{{x[0-9]+}}, #:lo12:func]
|
; CHECK: ldr [[FPTR:x[1-9]+]], [{{x[0-9]+}}, #:lo12:func]
|
||||||
|
; CHECK: movz w0, #42
|
||||||
; CHECK: br [[FPTR]]
|
; CHECK: br [[FPTR]]
|
||||||
}
|
}
|
||||||
|
@ -16,21 +16,21 @@
|
|||||||
; return 0;
|
; 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: main:
|
||||||
; CHECK: sub sp, sp, #448
|
; CHECK: sub sp, sp, #432
|
||||||
; CHECK: stp x29, x30, [sp, #432]
|
; CHECK: stp x29, x30, [sp, #416]
|
||||||
; CHECK: add x29, sp, #432
|
; CHECK: add x29, sp, #416
|
||||||
; CHECK: add {{x[0-9]+}}, sp, #12
|
; CHECK: add {{x[0-9]+}}, sp, #4
|
||||||
|
|
||||||
; Now check the debugging information reflects this:
|
; Now check the debugging information reflects this:
|
||||||
; CHECK: DW_TAG_variable
|
; CHECK: DW_TAG_variable
|
||||||
; CHECK-NEXT: .word .Linfo_string7
|
; 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: DW_AT_location
|
||||||
; CHECK-NEXT: .byte 145
|
; CHECK-NEXT: .byte 145
|
||||||
; CHECK-NEXT: .ascii "\334|"
|
; CHECK-NEXT: .ascii "\344|"
|
||||||
|
|
||||||
; CHECK: .Linfo_string7:
|
; CHECK: .Linfo_string7:
|
||||||
; CHECK-NEXT: main_arr
|
; CHECK-NEXT: main_arr
|
||||||
|
Loading…
Reference in New Issue
Block a user