#include "llvm/CodeGen/LiveRangeCalc.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/LiveInterval.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <tuple>
#include <utility>
using namespace llvm;
#define DEBUG_TYPE "regalloc"
static VNInfo UndefVNI(0xbad, SlotIndex());
void LiveRangeCalc::resetLiveOutMap() {
unsigned NumBlocks = MF->getNumBlockIDs();
Seen.clear();
Seen.resize(NumBlocks);
EntryInfos.clear();
Map.resize(NumBlocks);
}
void LiveRangeCalc::reset(const MachineFunction *mf,
SlotIndexes *SI,
MachineDominatorTree *MDT,
VNInfo::Allocator *VNIA) {
MF = mf;
MRI = &MF->getRegInfo();
Indexes = SI;
DomTree = MDT;
Alloc = VNIA;
resetLiveOutMap();
LiveIn.clear();
}
void LiveRangeCalc::updateFromLiveIns() {
LiveRangeUpdater Updater;
for (const LiveInBlock &I : LiveIn) {
if (!I.DomNode)
continue;
MachineBasicBlock *MBB = I.DomNode->getBlock();
assert(I.Value && "No live-in value found");
SlotIndex Start, End;
std::tie(Start, End) = Indexes->getMBBRange(MBB);
if (I.Kill.isValid())
End = I.Kill;
else {
assert(Seen.test(MBB->getNumber()));
Map[MBB] = LiveOutPair(I.Value, nullptr);
}
Updater.setDest(&I.LR);
Updater.add(Start, End, I.Value);
}
LiveIn.clear();
}
void LiveRangeCalc::extend(LiveRange &LR, SlotIndex Use, unsigned PhysReg,
ArrayRef<SlotIndex> Undefs) {
assert(Use.isValid() && "Invalid SlotIndex");
assert(Indexes && "Missing SlotIndexes");
assert(DomTree && "Missing dominator tree");
MachineBasicBlock *UseMBB = Indexes->getMBBFromIndex(Use.getPrevSlot());
assert(UseMBB && "No MBB at Use");
auto EP = LR.extendInBlock(Undefs, Indexes->getMBBStartIdx(UseMBB), Use);
if (EP.first != nullptr || EP.second)
return;
if (findReachingDefs(LR, *UseMBB, Use, PhysReg, Undefs))
return;
calculateValues();
}
void LiveRangeCalc::calculateValues() {
assert(Indexes && "Missing SlotIndexes");
assert(DomTree && "Missing dominator tree");
updateSSA();
updateFromLiveIns();
}
bool LiveRangeCalc::isDefOnEntry(LiveRange &LR, ArrayRef<SlotIndex> Undefs,
MachineBasicBlock &MBB, BitVector &DefOnEntry,
BitVector &UndefOnEntry) {
unsigned BN = MBB.getNumber();
if (DefOnEntry[BN])
return true;
if (UndefOnEntry[BN])
return false;
auto MarkDefined = [BN, &DefOnEntry](MachineBasicBlock &B) -> bool {
for (MachineBasicBlock *S : B.successors())
DefOnEntry[S->getNumber()] = true;
DefOnEntry[BN] = true;
return true;
};
SetVector<unsigned> WorkList;
for (MachineBasicBlock *P : MBB.predecessors())
WorkList.insert(P->getNumber());
for (unsigned i = 0; i != WorkList.size(); ++i) {
unsigned N = WorkList[i];
MachineBasicBlock &B = *MF->getBlockNumbered(N);
if (Seen[N]) {
const LiveOutPair &LOB = Map[&B];
if (LOB.first != nullptr && LOB.first != &UndefVNI)
return MarkDefined(B);
}
SlotIndex Begin, End;
std::tie(Begin, End) = Indexes->getMBBRange(&B);
LiveRange::iterator UB = upper_bound(LR, End.getPrevSlot());
if (UB != LR.begin()) {
LiveRange::Segment &Seg = *std::prev(UB);
if (Seg.end > Begin) {
if (LR.isUndefIn(Undefs, Seg.end, End))
continue;
return MarkDefined(B);
}
}
if (UndefOnEntry[N] || LR.isUndefIn(Undefs, Begin, End)) {
UndefOnEntry[N] = true;
continue;
}
if (DefOnEntry[N])
return MarkDefined(B);
for (MachineBasicBlock *P : B.predecessors())
WorkList.insert(P->getNumber());
}
UndefOnEntry[BN] = true;
return false;
}
bool LiveRangeCalc::findReachingDefs(LiveRange &LR, MachineBasicBlock &UseMBB,
SlotIndex Use, unsigned PhysReg,
ArrayRef<SlotIndex> Undefs) {
unsigned UseMBBNum = UseMBB.getNumber();
SmallVector<unsigned, 16> WorkList(1, UseMBBNum);
bool UniqueVNI = true;
VNInfo *TheVNI = nullptr;
bool FoundUndef = false;
for (unsigned i = 0; i != WorkList.size(); ++i) {
MachineBasicBlock *MBB = MF->getBlockNumbered(WorkList[i]);
#ifndef NDEBUG
if (MBB->pred_empty()) {
MBB->getParent()->verify();
errs() << "Use of " << printReg(PhysReg, MRI->getTargetRegisterInfo())
<< " does not have a corresponding definition on every path:\n";
const MachineInstr *MI = Indexes->getInstructionFromIndex(Use);
if (MI != nullptr)
errs() << Use << " " << *MI;
report_fatal_error("Use not jointly dominated by defs.");
}
if (Register::isPhysicalRegister(PhysReg) && !MBB->isLiveIn(PhysReg)) {
MBB->getParent()->verify();
const TargetRegisterInfo *TRI = MRI->getTargetRegisterInfo();
errs() << "The register " << printReg(PhysReg, TRI)
<< " needs to be live in to " << printMBBReference(*MBB)
<< ", but is missing from the live-in list.\n";
report_fatal_error("Invalid global physical register");
}
#endif
FoundUndef |= MBB->pred_empty();
for (MachineBasicBlock *Pred : MBB->predecessors()) {
if (Seen.test(Pred->getNumber())) {
if (VNInfo *VNI = Map[Pred].first) {
if (TheVNI && TheVNI != VNI)
UniqueVNI = false;
TheVNI = VNI;
}
continue;
}
SlotIndex Start, End;
std::tie(Start, End) = Indexes->getMBBRange(Pred);
auto EP = LR.extendInBlock(Undefs, Start, End);
VNInfo *VNI = EP.first;
FoundUndef |= EP.second;
setLiveOutValue(Pred, EP.second ? &UndefVNI : VNI);
if (VNI) {
if (TheVNI && TheVNI != VNI)
UniqueVNI = false;
TheVNI = VNI;
}
if (VNI || EP.second)
continue;
if (Pred != &UseMBB)
WorkList.push_back(Pred->getNumber());
else
Use = SlotIndex();
}
}
LiveIn.clear();
FoundUndef |= (TheVNI == nullptr || TheVNI == &UndefVNI);
if (!Undefs.empty() && FoundUndef)
UniqueVNI = false;
if (WorkList.size() > 4)
array_pod_sort(WorkList.begin(), WorkList.end());
if (UniqueVNI) {
assert(TheVNI != nullptr && TheVNI != &UndefVNI);
LiveRangeUpdater Updater(&LR);
for (unsigned BN : WorkList) {
SlotIndex Start, End;
std::tie(Start, End) = Indexes->getMBBRange(BN);
if (BN == UseMBBNum && Use.isValid())
End = Use;
else
Map[MF->getBlockNumbered(BN)] = LiveOutPair(TheVNI, nullptr);
Updater.add(Start, End, TheVNI);
}
return true;
}
EntryInfoMap::iterator Entry;
bool DidInsert;
std::tie(Entry, DidInsert) = EntryInfos.insert(
std::make_pair(&LR, std::make_pair(BitVector(), BitVector())));
if (DidInsert) {
unsigned N = MF->getNumBlockIDs();
Entry->second.first.resize(N);
Entry->second.second.resize(N);
}
BitVector &DefOnEntry = Entry->second.first;
BitVector &UndefOnEntry = Entry->second.second;
LiveIn.reserve(WorkList.size());
for (unsigned BN : WorkList) {
MachineBasicBlock *MBB = MF->getBlockNumbered(BN);
if (!Undefs.empty() &&
!isDefOnEntry(LR, Undefs, *MBB, DefOnEntry, UndefOnEntry))
continue;
addLiveInBlock(LR, DomTree->getNode(MBB));
if (MBB == &UseMBB)
LiveIn.back().Kill = Use;
}
return false;
}
void LiveRangeCalc::updateSSA() {
assert(Indexes && "Missing SlotIndexes");
assert(DomTree && "Missing dominator tree");
bool Changed;
do {
Changed = false;
for (LiveInBlock &I : LiveIn) {
MachineDomTreeNode *Node = I.DomNode;
if (!Node)
continue;
MachineBasicBlock *MBB = Node->getBlock();
MachineDomTreeNode *IDom = Node->getIDom();
LiveOutPair IDomValue;
bool needPHI = !IDom || !Seen.test(IDom->getBlock()->getNumber());
if (!needPHI) {
IDomValue = Map[IDom->getBlock()];
if (IDomValue.first && IDomValue.first != &UndefVNI &&
!IDomValue.second) {
Map[IDom->getBlock()].second = IDomValue.second =
DomTree->getNode(Indexes->getMBBFromIndex(IDomValue.first->def));
}
for (MachineBasicBlock *Pred : MBB->predecessors()) {
LiveOutPair &Value = Map[Pred];
if (!Value.first || Value.first == IDomValue.first)
continue;
if (Value.first == &UndefVNI) {
needPHI = true;
break;
}
if (!Value.second)
Value.second =
DomTree->getNode(Indexes->getMBBFromIndex(Value.first->def));
if (DomTree->dominates(IDom, Value.second)) {
needPHI = true;
break;
}
}
}
LiveOutPair &LOP = Map[MBB];
if (needPHI) {
Changed = true;
assert(Alloc && "Need VNInfo allocator to create PHI-defs");
SlotIndex Start, End;
std::tie(Start, End) = Indexes->getMBBRange(MBB);
LiveRange &LR = I.LR;
VNInfo *VNI = LR.getNextValue(Start, *Alloc);
I.Value = VNI;
I.DomNode = nullptr;
if (I.Kill.isValid()) {
if (VNI)
LR.addSegment(LiveInterval::Segment(Start, I.Kill, VNI));
} else {
if (VNI)
LR.addSegment(LiveInterval::Segment(Start, End, VNI));
LOP = LiveOutPair(VNI, Node);
}
} else if (IDomValue.first && IDomValue.first != &UndefVNI) {
I.Value = IDomValue.first;
if (I.Kill.isValid())
continue;
if (LOP.first == IDomValue.first)
continue;
Changed = true;
LOP = IDomValue;
}
}
} while (Changed);
}
bool LiveRangeCalc::isJointlyDominated(const MachineBasicBlock *MBB,
ArrayRef<SlotIndex> Defs,
const SlotIndexes &Indexes) {
const MachineFunction &MF = *MBB->getParent();
BitVector DefBlocks(MF.getNumBlockIDs());
for (SlotIndex I : Defs)
DefBlocks.set(Indexes.getMBBFromIndex(I)->getNumber());
SetVector<unsigned> PredQueue;
PredQueue.insert(MBB->getNumber());
for (unsigned i = 0; i != PredQueue.size(); ++i) {
unsigned BN = PredQueue[i];
if (DefBlocks[BN])
return true;
const MachineBasicBlock *B = MF.getBlockNumbered(BN);
for (const MachineBasicBlock *P : B->predecessors())
PredQueue.insert(P->getNumber());
}
return false;
}