#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
continue;
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
LiveInterval &LI = LIS.getInterval(Reg);
- // TODO: handle subranges instead of dropping them
- LI.clearSubRanges();
- updateRange(LI, Reg);
+ if (LI.hasSubRanges()) {
+ unsigned SubReg = MO->getSubReg();
+ unsigned LaneMask = TRI.getSubRegIndexLaneMask(SubReg);
+ for (LiveInterval::subrange_iterator S = LI.subrange_begin(),
+ SE = LI.subrange_end(); S != SE; ++S) {
+ if ((S->LaneMask & LaneMask) == 0)
+ continue;
+ updateRange(*S, Reg, S->LaneMask);
+ }
+ }
+ updateRange(LI, Reg, 0);
continue;
}
// precomputed live range.
for (MCRegUnitIterator Units(Reg, &TRI); Units.isValid(); ++Units)
if (LiveRange *LR = getRegUnitLI(*Units))
- updateRange(*LR, *Units);
+ updateRange(*LR, *Units, 0);
}
if (hasRegMask)
updateRegMaskSlots();
private:
/// Update a single live range, assuming an instruction has been moved from
/// OldIdx to NewIdx.
- void updateRange(LiveRange &LR, unsigned Reg) {
+ void updateRange(LiveRange &LR, unsigned Reg, unsigned LaneMask) {
if (!Updated.insert(&LR).second)
return;
DEBUG({
dbgs() << " ";
- if (TargetRegisterInfo::isVirtualRegister(Reg))
+ if (TargetRegisterInfo::isVirtualRegister(Reg)) {
dbgs() << PrintReg(Reg);
- else
+ if (LaneMask != 0)
+ dbgs() << format(" L%04X", LaneMask);
+ } else {
dbgs() << PrintRegUnit(Reg, &TRI);
+ }
dbgs() << ":\t" << LR << '\n';
});
if (SlotIndex::isEarlierInstr(OldIdx, NewIdx))
handleMoveDown(LR);
else
- handleMoveUp(LR, Reg);
+ handleMoveUp(LR, Reg, LaneMask);
DEBUG(dbgs() << " -->\t" << LR << '\n');
LR.verify();
}
/// Hoist kill to NewIdx, then scan for last kill between NewIdx and
/// OldIdx.
///
- void handleMoveUp(LiveRange &LR, unsigned Reg) {
+ void handleMoveUp(LiveRange &LR, unsigned Reg, unsigned LaneMask) {
// First look for a kill at OldIdx.
LiveRange::iterator I = LR.find(OldIdx.getBaseIndex());
LiveRange::iterator E = LR.end();
if (I == E || !SlotIndex::isSameInstr(I->start, OldIdx)) {
// No def, search for the new kill.
// This can never be an early clobber kill since there is no def.
- std::prev(I)->end = findLastUseBefore(Reg).getRegSlot();
+ std::prev(I)->end = findLastUseBefore(Reg, LaneMask).getRegSlot();
return;
}
}
}
// Return the last use of reg between NewIdx and OldIdx.
- SlotIndex findLastUseBefore(unsigned Reg) {
+ SlotIndex findLastUseBefore(unsigned Reg, unsigned LaneMask) {
if (TargetRegisterInfo::isVirtualRegister(Reg)) {
SlotIndex LastUse = NewIdx;
- for (MachineRegisterInfo::use_instr_nodbg_iterator
- UI = MRI.use_instr_nodbg_begin(Reg),
- UE = MRI.use_instr_nodbg_end();
- UI != UE; ++UI) {
- const MachineInstr* MI = &*UI;
+ for (MachineOperand &MO : MRI.use_nodbg_operands(Reg)) {
+ unsigned SubReg = MO.getSubReg();
+ if (SubReg != 0 && LaneMask != 0
+ && (TRI.getSubRegIndexLaneMask(SubReg) & LaneMask) == 0)
+ continue;
+
+ const MachineInstr *MI = MO.getParent();
SlotIndex InstSlot = LIS.getSlotIndexes()->getInstructionIndex(MI);
if (InstSlot > LastUse && InstSlot < OldIdx)
LastUse = InstSlot;
HME.updateAllRanges(MI);
}
+void LiveIntervals::repairOldRegInRange(const MachineBasicBlock::iterator Begin,
+ const MachineBasicBlock::iterator End,
+ const SlotIndex endIdx,
+ LiveRange &LR, const unsigned Reg,
+ const unsigned LaneMask) {
+ LiveInterval::iterator LII = LR.find(endIdx);
+ SlotIndex lastUseIdx;
+ if (LII != LR.end() && LII->start < endIdx)
+ lastUseIdx = LII->end;
+ else
+ --LII;
+
+ for (MachineBasicBlock::iterator I = End; I != Begin;) {
+ --I;
+ MachineInstr *MI = I;
+ if (MI->isDebugValue())
+ continue;
+
+ SlotIndex instrIdx = getInstructionIndex(MI);
+ bool isStartValid = getInstructionFromIndex(LII->start);
+ bool isEndValid = getInstructionFromIndex(LII->end);
+
+ // FIXME: This doesn't currently handle early-clobber or multiple removed
+ // defs inside of the region to repair.
+ for (MachineInstr::mop_iterator OI = MI->operands_begin(),
+ OE = MI->operands_end(); OI != OE; ++OI) {
+ const MachineOperand &MO = *OI;
+ if (!MO.isReg() || MO.getReg() != Reg)
+ continue;
+
+ unsigned SubReg = MO.getSubReg();
+ unsigned Mask = TRI->getSubRegIndexLaneMask(SubReg);
+ if ((Mask & LaneMask) == 0)
+ continue;
+
+ if (MO.isDef()) {
+ if (!isStartValid) {
+ if (LII->end.isDead()) {
+ SlotIndex prevStart;
+ if (LII != LR.begin())
+ prevStart = std::prev(LII)->start;
+
+ // FIXME: This could be more efficient if there was a
+ // removeSegment method that returned an iterator.
+ LR.removeSegment(*LII, true);
+ if (prevStart.isValid())
+ LII = LR.find(prevStart);
+ else
+ LII = LR.begin();
+ } else {
+ LII->start = instrIdx.getRegSlot();
+ LII->valno->def = instrIdx.getRegSlot();
+ if (MO.getSubReg() && !MO.isUndef())
+ lastUseIdx = instrIdx.getRegSlot();
+ else
+ lastUseIdx = SlotIndex();
+ continue;
+ }
+ }
+
+ if (!lastUseIdx.isValid()) {
+ VNInfo *VNI = LR.getNextValue(instrIdx.getRegSlot(), VNInfoAllocator);
+ LiveRange::Segment S(instrIdx.getRegSlot(),
+ instrIdx.getDeadSlot(), VNI);
+ LII = LR.addSegment(S);
+ } else if (LII->start != instrIdx.getRegSlot()) {
+ VNInfo *VNI = LR.getNextValue(instrIdx.getRegSlot(), VNInfoAllocator);
+ LiveRange::Segment S(instrIdx.getRegSlot(), lastUseIdx, VNI);
+ LII = LR.addSegment(S);
+ }
+
+ if (MO.getSubReg() && !MO.isUndef())
+ lastUseIdx = instrIdx.getRegSlot();
+ else
+ lastUseIdx = SlotIndex();
+ } else if (MO.isUse()) {
+ // FIXME: This should probably be handled outside of this branch,
+ // either as part of the def case (for defs inside of the region) or
+ // after the loop over the region.
+ if (!isEndValid && !LII->end.isBlock())
+ LII->end = instrIdx.getRegSlot();
+ if (!lastUseIdx.isValid())
+ lastUseIdx = instrIdx.getRegSlot();
+ }
+ }
+ }
+}
+
void
LiveIntervals::repairIntervalsInRange(MachineBasicBlock *MBB,
MachineBasicBlock::iterator Begin,
if (!LI.hasAtLeastOneValue())
continue;
- LiveInterval::iterator LII = LI.find(endIdx);
- SlotIndex lastUseIdx;
- if (LII != LI.end() && LII->start < endIdx)
- lastUseIdx = LII->end;
- else
- --LII;
-
- for (MachineBasicBlock::iterator I = End; I != Begin;) {
- --I;
- MachineInstr *MI = I;
- if (MI->isDebugValue())
- continue;
-
- SlotIndex instrIdx = getInstructionIndex(MI);
- bool isStartValid = getInstructionFromIndex(LII->start);
- bool isEndValid = getInstructionFromIndex(LII->end);
-
- // FIXME: This doesn't currently handle early-clobber or multiple removed
- // defs inside of the region to repair.
- for (MachineInstr::mop_iterator OI = MI->operands_begin(),
- OE = MI->operands_end(); OI != OE; ++OI) {
- const MachineOperand &MO = *OI;
- if (!MO.isReg() || MO.getReg() != Reg)
- continue;
-
- if (MO.isDef()) {
- if (!isStartValid) {
- if (LII->end.isDead()) {
- SlotIndex prevStart;
- if (LII != LI.begin())
- prevStart = std::prev(LII)->start;
-
- // FIXME: This could be more efficient if there was a
- // removeSegment method that returned an iterator.
- LI.removeSegment(*LII, true);
- if (prevStart.isValid())
- LII = LI.find(prevStart);
- else
- LII = LI.begin();
- } else {
- LII->start = instrIdx.getRegSlot();
- LII->valno->def = instrIdx.getRegSlot();
- if (MO.getSubReg() && !MO.isUndef())
- lastUseIdx = instrIdx.getRegSlot();
- else
- lastUseIdx = SlotIndex();
- continue;
- }
- }
-
- if (!lastUseIdx.isValid()) {
- VNInfo *VNI = LI.getNextValue(instrIdx.getRegSlot(),
- VNInfoAllocator);
- LiveRange::Segment S(instrIdx.getRegSlot(),
- instrIdx.getDeadSlot(), VNI);
- LII = LI.addSegment(S);
- } else if (LII->start != instrIdx.getRegSlot()) {
- VNInfo *VNI = LI.getNextValue(instrIdx.getRegSlot(),
- VNInfoAllocator);
- LiveRange::Segment S(instrIdx.getRegSlot(), lastUseIdx, VNI);
- LII = LI.addSegment(S);
- }
-
- if (MO.getSubReg() && !MO.isUndef())
- lastUseIdx = instrIdx.getRegSlot();
- else
- lastUseIdx = SlotIndex();
- } else if (MO.isUse()) {
- // FIXME: This should probably be handled outside of this branch,
- // either as part of the def case (for defs inside of the region) or
- // after the loop over the region.
- if (!isEndValid && !LII->end.isBlock())
- LII->end = instrIdx.getRegSlot();
- if (!lastUseIdx.isValid())
- lastUseIdx = instrIdx.getRegSlot();
- }
- }
+ for (LiveInterval::subrange_iterator S = LI.subrange_begin(),
+ SE = LI.subrange_end(); S != SE; ++S) {
+ repairOldRegInRange(Begin, End, endIdx, *S, Reg, S->LaneMask);
}
+ repairOldRegInRange(Begin, End, endIdx, LI, Reg);
}
}