const TargetInstrDesc &TID = MI->getDesc();
if (TID.isImplicitDef())
return true;
+
+ int FrameIdx = 0;
+ if (tii_->isLoadFromStackSlot(MI, FrameIdx) &&
+ mf_->getFrameInfo()->isImmutableObjectIndex(FrameIdx))
+ // FIXME: Let target specific isReallyTriviallyReMaterializable determines
+ // this but remember this is not safe to fold into a two-address
+ // instruction.
+ // This is a load from fixed stack slot. It can be rematerialized.
+ return true;
+
if (tii_->isTriviallyReMaterializable(MI)) {
isLoad = TID.isSimpleLoad();
unsigned UseIdx = getInstructionIndex(UseMI);
if (li.FindLiveRangeContaining(UseIdx)->valno != ValNo)
continue;
- if (!canFoldMemoryOperand(UseMI, li.reg) &&
- !isValNoAvailableAt(ImpLi, MI, UseIdx))
+ if (!isValNoAvailableAt(ImpLi, MI, UseIdx))
return false;
}
}
return true;
}
- int FrameIdx = 0;
- if (!tii_->isLoadFromStackSlot(MI, FrameIdx) ||
- !mf_->getFrameInfo()->isImmutableObjectIndex(FrameIdx))
- return false;
-
- // This is a load from fixed stack slot. It can be rematerialized unless it's
- // re-defined by a two-address instruction.
- isLoad = true;
- for (LiveInterval::const_vni_iterator i = li.vni_begin(), e = li.vni_end();
- i != e; ++i) {
- const VNInfo *VNI = *i;
- if (VNI == ValNo)
- continue;
- unsigned DefIdx = VNI->def;
- if (DefIdx == ~1U)
- continue; // Dead val#.
- MachineInstr *DefMI = (DefIdx == ~0u)
- ? NULL : getInstructionFromIndex(DefIdx);
- if (DefMI && DefMI->isRegReDefinedByTwoAddr(li.reg)) {
- isLoad = false;
- return false;
- }
- }
- return true;
+ return false;
}
/// isReMaterializable - Returns true if every definition of MI of every
return true;
}
-/// tryFoldMemoryOperand - Attempts to fold either a spill / restore from
-/// slot / to reg or any rematerialized load into ith operand of specified
-/// MI. If it is successul, MI is updated with the newly created MI and
-/// returns true.
-bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI,
- VirtRegMap &vrm, MachineInstr *DefMI,
- unsigned InstrIdx,
- SmallVector<unsigned, 2> &Ops,
- bool isSS, int Slot, unsigned Reg) {
- unsigned MRInfo = 0;
+/// FilterFoldedOps - Filter out two-address use operands. Return
+/// true if it finds any issue with the operands that ought to prevent
+/// folding.
+static bool FilterFoldedOps(MachineInstr *MI,
+ SmallVector<unsigned, 2> &Ops,
+ unsigned &MRInfo,
+ SmallVector<unsigned, 2> &FoldOps) {
const TargetInstrDesc &TID = MI->getDesc();
- // If it is an implicit def instruction, just delete it.
- if (TID.isImplicitDef()) {
- RemoveMachineInstrFromMaps(MI);
- vrm.RemoveMachineInstrFromMaps(MI);
- MI->eraseFromParent();
- ++numFolds;
- return true;
- }
- SmallVector<unsigned, 2> FoldOps;
+ MRInfo = 0;
for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
unsigned OpIdx = Ops[i];
MachineOperand &MO = MI->getOperand(OpIdx);
// FIXME: fold subreg use.
if (MO.getSubReg())
- return false;
+ return true;
if (MO.isDef())
MRInfo |= (unsigned)VirtRegMap::isMod;
else {
}
FoldOps.push_back(OpIdx);
}
+ return false;
+}
+
+
+/// tryFoldMemoryOperand - Attempts to fold either a spill / restore from
+/// slot / to reg or any rematerialized load into ith operand of specified
+/// MI. If it is successul, MI is updated with the newly created MI and
+/// returns true.
+bool LiveIntervals::tryFoldMemoryOperand(MachineInstr* &MI,
+ VirtRegMap &vrm, MachineInstr *DefMI,
+ unsigned InstrIdx,
+ SmallVector<unsigned, 2> &Ops,
+ bool isSS, int Slot, unsigned Reg) {
+ const TargetInstrDesc &TID = MI->getDesc();
+ // If it is an implicit def instruction, just delete it.
+ if (TID.isImplicitDef()) {
+ RemoveMachineInstrFromMaps(MI);
+ vrm.RemoveMachineInstrFromMaps(MI);
+ MI->eraseFromParent();
+ ++numFolds;
+ return true;
+ }
+
+ // Filter the list of operand indexes that are to be folded. Abort if
+ // any operand will prevent folding.
+ unsigned MRInfo = 0;
+ SmallVector<unsigned, 2> FoldOps;
+ if (FilterFoldedOps(MI, Ops, MRInfo, FoldOps))
+ return false;
+
+ // Can't fold a load from fixed stack slot into a two address instruction.
+ if (isSS && DefMI && (MRInfo & VirtRegMap::isMod))
+ return false;
MachineInstr *fmi = isSS ? tii_->foldMemoryOperand(*mf_, MI, FoldOps, Slot)
: tii_->foldMemoryOperand(*mf_, MI, FoldOps, DefMI);
if (fmi) {
+ // Remember this instruction uses the spill slot.
+ if (isSS) vrm.addSpillSlotUse(Slot, fmi);
+
// Attempt to fold the memory reference into the instruction. If
// we can do this, we don't need to insert spill code.
if (lv_)
/// canFoldMemoryOperand - Returns true if the specified load / store
/// folding is possible.
bool LiveIntervals::canFoldMemoryOperand(MachineInstr *MI,
- SmallVector<unsigned, 2> &Ops) const {
+ SmallVector<unsigned, 2> &Ops,
+ bool ReMatLoad) const {
+ // Filter the list of operand indexes that are to be folded. Abort if
+ // any operand will prevent folding.
+ unsigned MRInfo = 0;
SmallVector<unsigned, 2> FoldOps;
- for (unsigned i = 0, e = Ops.size(); i != e; ++i) {
- unsigned OpIdx = Ops[i];
- // FIXME: fold subreg use.
- if (MI->getOperand(OpIdx).getSubReg())
- return false;
- FoldOps.push_back(OpIdx);
- }
+ if (FilterFoldedOps(MI, Ops, MRInfo, FoldOps))
+ return false;
- return tii_->canFoldMemoryOperand(MI, FoldOps);
-}
+ // Can't fold a remat'ed load into a two address instruction.
+ if (ReMatLoad && (MRInfo & VirtRegMap::isMod))
+ return false;
-bool LiveIntervals::canFoldMemoryOperand(MachineInstr *MI, unsigned Reg) const {
- SmallVector<unsigned, 2> FoldOps;
- for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
- MachineOperand& mop = MI->getOperand(i);
- if (!mop.isRegister())
- continue;
- unsigned UseReg = mop.getReg();
- if (UseReg != Reg)
- continue;
- // FIXME: fold subreg use.
- if (mop.getSubReg())
- return false;
- FoldOps.push_back(i);
- }
return tii_->canFoldMemoryOperand(MI, FoldOps);
}
const TargetRegisterClass* rc,
SmallVector<int, 4> &ReMatIds,
const MachineLoopInfo *loopInfo,
- unsigned &NewVReg, bool &HasDef, bool &HasUse,
+ unsigned &NewVReg, unsigned ImpUse, bool &HasDef, bool &HasUse,
std::map<unsigned,unsigned> &MBBVRegsMap,
std::vector<LiveInterval*> &NewLIs) {
bool CanFold = false;
// spill weight of the register interval.
unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
LiveInterval &ImpLi = getInterval(ImpUse);
- ImpLi.weight -= getSpillWeight(false, true, loopDepth);
+ ImpLi.weight -=
+ getSpillWeight(false, true, loopDepth) / ImpLi.getSize();
}
RemoveMachineInstrFromMaps(MI);
vrm.RemoveMachineInstrFromMaps(MI);
goto RestartInstruction;
}
} else {
- CanFold = canFoldMemoryOperand(MI, Ops);
+ CanFold = canFoldMemoryOperand(MI, Ops, DefIsReMat && isLoad);
}
} else
CanFold = false;
if (CreatedNewVReg) {
if (DefIsReMat) {
- unsigned ImpUse = getReMatImplicitUse(li, ReMatDefMI);
- if (ImpUse) {
- // Re-matting an instruction with virtual register use. Add the
- // register as an implicit use on the use MI and update the register
- // interval's spill weight.
- unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
- LiveInterval &ImpLi = getInterval(ImpUse);
- ImpLi.weight += getSpillWeight(false, true, loopDepth);
- MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
- }
vrm.setVirtIsReMaterialized(NewVReg, ReMatDefMI/*, CanDelete*/);
if (ReMatIds[VNI->id] == VirtRegMap::MAX_STACK_SLOT) {
// Each valnum may have its own remat id.
vrm.assignVirt2StackSlot(NewVReg, Slot);
}
+ // Re-matting an instruction with virtual register use. Add the
+ // register as an implicit use on the use MI.
+ if (DefIsReMat && ImpUse)
+ MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
+
// create a new register interval for this spill / remat.
LiveInterval &nI = getOrCreateInterval(NewVReg);
if (CreatedNewVReg) {
}
std::sort(RewriteMIs.begin(), RewriteMIs.end(), RewriteInfoCompare());
+ unsigned ImpUse = DefIsReMat ? getReMatImplicitUse(li, ReMatDefMI) : 0;
// Now rewrite the defs and uses.
for (unsigned i = 0, e = RewriteMIs.size(); i != e; ) {
RewriteInfo &rwi = RewriteMIs[i];
MachineInstr *MI = rwi.MI;
// If MI def and/or use the same register multiple times, then there
// are multiple entries.
+ unsigned NumUses = MIHasUse;
while (i != e && RewriteMIs[i].MI == MI) {
assert(RewriteMIs[i].Index == index);
- MIHasUse |= RewriteMIs[i].HasUse;
+ bool isUse = RewriteMIs[i].HasUse;
+ if (isUse) ++NumUses;
+ MIHasUse |= isUse;
MIHasDef |= RewriteMIs[i].HasDef;
++i;
}
MachineBasicBlock *MBB = MI->getParent();
+
+ if (ImpUse && MI != ReMatDefMI) {
+ // Re-matting an instruction with virtual register use. Update the
+ // register interval's spill weight.
+ unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
+ LiveInterval &ImpLi = getInterval(ImpUse);
+ ImpLi.weight +=
+ getSpillWeight(false, true, loopDepth) * NumUses / ImpLi.getSize();
+ }
+
unsigned MBBId = MBB->getNumber();
unsigned ThisVReg = 0;
if (TrySplit) {
index, end, MI, ReMatOrigDefMI, ReMatDefMI,
Slot, LdSlot, isLoad, isLoadSS, DefIsReMat,
CanDelete, vrm, rc, ReMatIds, loopInfo, NewVReg,
- HasDef, HasUse, MBBVRegsMap, NewLIs);
+ ImpUse, HasDef, HasUse, MBBVRegsMap, NewLIs);
if (!HasDef && !HasUse)
continue;
// interval's spill weight.
unsigned loopDepth = loopInfo->getLoopDepth(MI->getParent());
LiveInterval &ImpLi = getInterval(ImpUse);
- ImpLi.weight += getSpillWeight(false, true, loopDepth);
+ ImpLi.weight +=
+ getSpillWeight(false, true, loopDepth) / ImpLi.getSize();
+
MI->addOperand(MachineOperand::CreateReg(ImpUse, false, true));
}
}