Files
intel-graphics-compiler/IGC/Compiler/CISACodeGen/LiveVars.cpp
Paige, Alexander 420b632df9 Update IGC code format
Update IGC code format
2025-07-20 06:20:11 +02:00

734 lines
24 KiB
C++

/*========================== begin_copyright_notice ============================
Copyright (C) 2017-2021 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
/*========================== begin_copyright_notice ============================
This file is distributed under the University of Illinois Open Source License.
See LICENSE.TXT for details.
============================= end_copyright_notice ===========================*/
//===------------ LiveVars.cpp - Live Variable Analysis ---------*- C++ -*-===//
//
// Intel extension to LLVM core
//
//===----------------------------------------------------------------------===//
//
// This file implements the LiveVariables analysis pass. It originates from
// the same function in llvm3.0/codegen, however works on llvm-ir instead of
// the code-gen-level ir.
//
// This class computes live variables using a sparse implementation based on
// the llvm-ir SSA form. This class uses the dominance properties of SSA form
// to efficiently compute live variables for virtual registers. Also Note that
// there is no physical register at llvm-ir level.
//
//===----------------------------------------------------------------------===//
#include "Compiler/CISACodeGen/LiveVars.hpp"
#include "Compiler/IGCPassSupport.h"
#include "common/debug/Debug.hpp"
#include "common/LLVMWarningsPush.hpp"
#include "llvmWrapper/IR/CFG.h"
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/Debug.h>
#include <llvm/ADT/DepthFirstIterator.h>
#include "common/LLVMWarningsPop.hpp"
#include <algorithm>
#include "Probe/Assertion.h"
#include "helper.h"
using namespace llvm;
using namespace IGC;
using namespace IGC::Debug;
Instruction *LiveVars::LVInfo::findKill(const BasicBlock *MBB) const {
for (unsigned i = 0, e = Kills.size(); i != e; ++i)
if (Kills[i]->getParent() == MBB)
return Kills[i];
return NULL;
}
void LiveVars::LVInfo::print(raw_ostream &OS) const {
OS << " Alive in blocks: ";
for (auto I = AliveBlocks.begin(), E = AliveBlocks.end(); I != E; ++I) {
(*I)->print(OS);
OS << ", ";
}
OS << "\n Killed by:";
if (Kills.empty())
OS << " No instructions.\n";
else {
for (unsigned i = 0, e = Kills.size(); i != e; ++i) {
OS << "\n " << ": " << *Kills[i];
}
OS << "\n";
}
}
void LiveVars::print(raw_ostream &OS, const Module *) const {
for (DenseMap<Value *, LiveVars::LVInfo *>::const_iterator I = VirtRegInfo.begin(), E = VirtRegInfo.end(); I != E;
++I) {
OS << "\n{";
I->first->print(OS);
I->second->print(OS);
OS << "}";
}
}
/// Destructor needs to release the allocated memory
LiveVars::~LiveVars() { releaseMemory(); }
void LiveVars::releaseMemory() {
// Free the LVInfo table
VirtRegInfo.clear();
PHIVarInfo.clear();
DistanceMap.clear();
}
void LiveVars::preAllocMemory(Function &F) {
// Pre-allocate enough memory to avoid many allocations
// Use the number of values (arg_size + the number of insts)
// as the amount for pre-allocation. This size is super set
// for both VirtRegInfo and DistanceMap. (This amount is about
// 3%-5% more than the real size of VirtRegInfo.)
size_t nVals = F.arg_size();
for (auto &BB : F) {
nVals += BB.size();
}
// Allocate a bit more than we need in case it needs grow.
// Note that as DenseMap will automatically allocate when
// the map is 3/4 full, so we take this into account.
uint32_t mapCap1 = int_cast<uint32_t>((size_t)(nVals * 1.40f));
// For PHIVarInfo, increase 10% only.
uint32_t mapCap2 = int_cast<uint32_t>((size_t)(F.size() * 1.10f));
DistanceMap.grow(mapCap1);
VirtRegInfo.grow(mapCap1);
PHIVarInfo.grow(mapCap2);
}
void LiveVars::dump() const { print(ods()); }
#if defined(_DEBUG)
void LiveVars::dump(Function *F) {
if (F->size() == 0) {
return;
}
if (BBIds.size() == 0) {
setupBBIds(F);
}
raw_ostream &OS = errs();
for (DenseMap<Value *, LiveVars::LVInfo *>::const_iterator I = VirtRegInfo.begin(), E = VirtRegInfo.end(); I != E;
++I) {
Value *V = I->first;
LVInfo *LVI = I->second;
OS << "\n{";
V->print(OS);
OS << "\n Alive in blocks: ";
for (auto I = LVI->AliveBlocks.begin(), E = LVI->AliveBlocks.end(); I != E; ++I) {
BasicBlock *BB = *I;
if (BBIds.count(BB) > 0) {
int id = BBIds[BB];
OS << id << ", ";
} else {
OS << "<unknown>, ";
}
}
OS << "\n Killed by:";
if (LVI->Kills.empty())
OS << " No instructions.\n";
else {
for (unsigned i = 0, e = LVI->Kills.size(); i != e; ++i) {
OS << "\n " << ": " << *LVI->Kills[i];
}
OS << "\n";
}
OS << "}";
}
}
void LiveVars::dump(int BBId) {
BasicBlock *BB = IdToBBs[BBId];
if (BB) {
BB->print(ods());
}
}
void LiveVars::setupBBIds(Function *F) {
if (F) {
int ix = 0;
for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
BasicBlock *BB = &*I;
BBIds.insert(std::make_pair(BB, ix));
IdToBBs.insert(std::make_pair(ix, BB));
++ix;
}
}
}
#endif
/// getLVInfo - Get (possibly creating) a LVInfo object for the given vreg.
LiveVars::LVInfo &LiveVars::getLVInfo(Value *LV) {
IGC_ASSERT(isa<Instruction>(LV) || isa<Argument>(LV));
DenseMap<Value *, LiveVars::LVInfo *>::const_iterator it = VirtRegInfo.find(LV);
if (it == VirtRegInfo.end()) {
LiveVars::LVInfo *lvInfo = new (Allocator.Allocate()) LiveVars::LVInfo();
lvInfo->uniform = (WIA && WIA->isUniform(LV));
VirtRegInfo.insert(std::pair<Value *, LVInfo *>(LV, lvInfo));
if (Instruction *inst = dyn_cast<Instruction>(LV)) {
// if the value is an instruction, default it to dead
lvInfo->Kills.push_back(inst);
}
return *(lvInfo);
}
return *(it->second);
}
void LiveVars::MarkVirtRegAliveInBlock(LiveVars::LVInfo &VRInfo, BasicBlock *DefBlock, BasicBlock *MBB,
std::vector<BasicBlock *> &WorkList) {
if (VRInfo.AliveBlocks.count(MBB))
return; // We already know the block is live
// Check to see if this basic block is one of the killing blocks. If so,
// remove it.
for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i)
if (VRInfo.Kills[i]->getParent() == MBB) {
VRInfo.Kills.erase(VRInfo.Kills.begin() + i); // Erase entry
break;
}
if (MBB == &(MF->getEntryBlock()) && DefBlock != nullptr)
return; // Only Arguments can be live-through entry block
if (MBB == DefBlock)
return; // Terminate recursion
// Mark the variable known alive in this bb
VRInfo.AliveBlocks.insert(MBB);
// Skip the simdPred if WIA is not available
if (!WIA) {
return;
}
bool hasNonUniformBranch = false;
bool hasLayoutPred = true;
for (pred_iterator PI = pred_begin(MBB), E = pred_end(MBB); PI != E; ++PI) {
BasicBlock *PredBlk = *PI;
// Before pushing check if the predecessor has already been marked
if (VRInfo.AliveBlocks.count(PredBlk))
continue; // We already know the block is live
WorkList.push_back(PredBlk);
// Check if we need to update liveness for uniform variable
// inside divergent control-flow
if (PredBlk == MBB->getPrevNode())
hasLayoutPred = false;
if (hasLayoutPred && VRInfo.uniform) {
Instruction *cbr = PredBlk->getTerminator();
if (cbr && !WIA->isUniform(cbr))
hasNonUniformBranch = true;
}
}
if (hasLayoutPred && hasNonUniformBranch && VRInfo.uniform) {
BasicBlock *simdPred = MBB->getPrevNode();
while (simdPred && simdPred != DefBlock) {
// check if it is marked live
if (!VRInfo.AliveBlocks.count(simdPred))
WorkList.push_back(simdPred);
simdPred = simdPred->getPrevNode();
}
}
}
void LiveVars::MarkVirtRegAliveInBlock(LiveVars::LVInfo &VRInfo, BasicBlock *DefBlock, BasicBlock *MBB) {
std::vector<BasicBlock *> WorkList;
MarkVirtRegAliveInBlock(VRInfo, DefBlock, MBB, WorkList);
while (!WorkList.empty()) {
BasicBlock *Pred = WorkList.back();
WorkList.pop_back();
MarkVirtRegAliveInBlock(VRInfo, DefBlock, Pred, WorkList);
}
}
void LiveVars::HandleVirtRegUse(Value *VL, BasicBlock *MBB, Instruction *MI, bool ScanAllKills, bool ScanBBTopDown) {
LiveVars::LVInfo &VRInfo = getLVInfo(VL);
VRInfo.NumUses++;
// Check to see if this basic block is already a kill block.
// - When we establish live-info for the first time, the uses are scanned in bottom-up fashion
// for every basic block, the kill for the current block is appended to
// the end of the kill-list, therefore we only need to check the last kill on the kill-list.
// - When we update the live-info later on in top-down fashion, for example, when coalescing InsertElements
// in DeSSA, the existing kill for this block may be anywhere on the list, then we need to
// scan all the kills in order to replace the right one.
if (ScanAllKills) {
for (unsigned i = 0, e = VRInfo.Kills.size(); i != e; ++i) {
if (VRInfo.Kills[i]->getParent() == MBB) {
Instruction *killInst = VRInfo.Kills[i];
IGC_ASSERT_MESSAGE(DistanceMap.count(killInst), "DistanceMap not set up yet.");
IGC_ASSERT_MESSAGE(DistanceMap.count(MI), "DistanceMap not set up yet.");
if (DistanceMap[killInst] < DistanceMap[MI]) {
VRInfo.Kills[i] = MI;
}
return;
}
}
} else {
if (!VRInfo.Kills.empty() && VRInfo.Kills.back()->getParent() == MBB) {
if (ScanBBTopDown) {
VRInfo.Kills.back() = MI;
} else {
// Initially the kill is the def itself.
// replace it with the kill, otherwise, just ignore the new use because it is not the last.
if (VRInfo.Kills.back() == VL) {
VRInfo.Kills.back() = MI;
}
}
return;
}
for (size_t i = 0, e = VRInfo.Kills.size(); i < e; ++i) {
IGC_ASSERT(nullptr != VRInfo.Kills[i]);
IGC_ASSERT_MESSAGE((VRInfo.Kills[i]->getParent() != MBB), "entry should be at end!");
}
}
// This situation can occur:
//
// ,------.
// | |
// | v
// | t2 = phi ... t1 ...
// | |
// | v
// | t1 = ...
// | ... = ... t1 ...
// | |
// `------'
//
// where there is a use in a PHI node that's a predecessor to the defining
// block. We don't want to mark all predecessors as having the value "alive"
// in this case.
if (isa<Instruction>(VL)) {
if (MBB == cast<Instruction>(VL)->getParent())
return;
}
// Add a new kill entry for this basic block. If this virtual register is
// already marked as alive in this basic block, that means it is alive in at
// least one of the successor blocks, it's not a kill.
if (!VRInfo.AliveBlocks.count(MBB))
VRInfo.Kills.push_back(MI);
if (MBB == &(MF->getEntryBlock()))
return;
if (!WIA)
return;
// Update all dominating blocks to mark them as "known live".
bool hasNonUniformBranch = false;
bool hasLayoutPred = true;
for (pred_iterator PI = pred_begin(MBB), E = pred_end(MBB); PI != E; ++PI) {
BasicBlock *DefBlk = (isa<Instruction>(VL)) ? cast<Instruction>(VL)->getParent() : NULL;
BasicBlock *PredBlk = *PI;
MarkVirtRegAliveInBlock(VRInfo, DefBlk, PredBlk);
Instruction *cbr = PredBlk->getTerminator();
if (cbr && !WIA->isUniform(cbr))
hasNonUniformBranch = true;
if (PredBlk == MBB->getPrevNode())
hasLayoutPred = false;
}
if (hasLayoutPred && hasNonUniformBranch && WIA->isUniform(VL)) {
BasicBlock *simdPred = MBB->getPrevNode();
BasicBlock *DefBlk = (isa<Instruction>(VL)) ? cast<Instruction>(VL)->getParent() : NULL;
while (simdPred && simdPred != DefBlk) {
MarkVirtRegAliveInBlock(VRInfo, DefBlk, simdPred);
simdPred = simdPred->getPrevNode();
}
}
}
void LiveVars::HandleVirtRegDef(Instruction *MI) {
LiveVars::LVInfo &VRInfo = getLVInfo(MI);
if (VRInfo.AliveBlocks.empty())
// If vr is not alive in any block, then defaults to dead.
VRInfo.Kills.push_back(MI);
}
void LiveVars::initDistance(Function &F) {
DistanceMap.clear();
for (auto &BB : F) {
unsigned Dist = 0;
for (auto &II : BB) {
Instruction *MI = &II;
if (isDbgIntrinsic(MI)) {
continue;
}
DistanceMap.insert(std::make_pair(MI, Dist++));
}
}
}
void LiveVars::ComputeLiveness(Function *mf, WIAnalysis *wia) {
releaseMemory();
MF = mf;
WIA = wia;
preAllocMemory(*MF);
// First, set up DistanceMap
// save distance map
initDistance(*MF);
analyzePHINodes(*mf);
BasicBlock *Entry = &(*MF->begin());
typedef df_iterator_default_set<BasicBlock *, 16> VisitedTy;
VisitedTy Visited;
for (df_ext_iterator<BasicBlock *, VisitedTy> DFI = df_ext_begin(Entry, Visited), E = df_ext_end(Entry, Visited);
DFI != E; ++DFI) {
BasicBlock *MBB = *DFI;
// Handle any virtual assignments from PHI nodes which might be at the
// bottom of this basic block. We check all of our successor blocks to see
// if they have PHI nodes, and if so, we simulate an assignment at the end
// of the current block.
auto it = PHIVarInfo.find(MBB);
if (it != PHIVarInfo.end()) {
SmallVector<Value *, 4> &VarInfoVec = it->second;
for (SmallVector<Value *, 4>::iterator I = VarInfoVec.begin(), E = VarInfoVec.end(); I != E; ++I) {
// Mark it alive only in the block we are representing.
Value *DefV = *I;
BasicBlock *DefBlk = (isa<Instruction>(DefV)) ? cast<Instruction>(DefV)->getParent() : NULL;
MarkVirtRegAliveInBlock(getLVInfo(DefV), DefBlk, MBB);
}
}
}
}
/// analyzePHINodes - Gather information about the PHI nodes in here. In
/// particular, we want to map the variable information of a virtual register
/// which is used in a PHI node. We map that to the BB the vreg is coming from.
///
void LiveVars::analyzePHINodes(const Function &Fn) {
for (Function::const_iterator I = Fn.begin(), E = Fn.end(); I != E; ++I) {
for (BasicBlock::const_iterator BBI = I->begin(), BBE = I->end(); BBI != BBE; ++BBI) {
const PHINode *phi = dyn_cast<PHINode>(BBI);
if (!phi)
break;
for (unsigned i = 0, e = phi->getNumOperands(); i != e; ++i) {
BasicBlock *PBB = phi->getIncomingBlock(i);
Value *VL = phi->getOperand(i);
if (isa<Instruction>(VL) || isa<Argument>(VL)) {
SmallVector<Value *, 4> &VV = PHIVarInfo[PBB];
VV.push_back(phi->getOperand(i));
}
}
}
}
}
bool LiveVars::LVInfo::isLiveIn(const BasicBlock &MBB, Value *VL) {
// Reg is live-through.
if (AliveBlocks.count((BasicBlock *)&MBB))
return true;
// Registers defined in MBB cannot be live in.
const Instruction *Def = dyn_cast<Instruction>(VL);
if (Def && Def->getParent() == &MBB)
return false;
// Reg was not defined in MBB, was it killed here?
if (findKill(&MBB))
return true;
return false;
}
bool LiveVars::isLiveAt(Value *VL, Instruction *MI) {
BasicBlock *MBB = MI->getParent();
LVInfo &info = getLVInfo(VL);
// Reg is live-through.
if (info.AliveBlocks.count(MBB))
return true;
// Registers defined in MBB cannot be live in.
const Instruction *Def = dyn_cast<Instruction>(VL);
if (Def && Def->getParent() == MBB) {
if (getDistance(Def) > getDistance(MI)) {
return false;
} else if (info.AliveBlocks.empty() && info.Kills.empty()) {
// handle that special case: def is the current block
// and phi in the immed-successor block is the last use
return true;
}
}
// Reg was not defined in MBB, was it killed here?
Instruction *kill = info.findKill(MBB);
if (kill) {
return getDistance(kill) > getDistance(MI);
}
if (isLiveOut(VL, *MBB)) {
return true;
}
return false;
}
bool LiveVars::isLiveOut(Value *VL, const BasicBlock &MBB) {
LiveVars::LVInfo &VI = getLVInfo(VL);
if (isa<Instruction>(VL) && VI.AliveBlocks.empty()) {
// a local value does not live out of any BB.
// (Originally, this function might be for checking non-local
// value. Adding this code to make it work for any value.)
Instruction *I = cast<Instruction>(VL);
if (VI.Kills.size() == 1) {
BasicBlock *killBB = VI.Kills[0]->getParent();
if (killBB == I->getParent()) {
return false;
}
}
}
// Loop over all of the successors of the basic block, checking to see if
// the value is either live in the block, or if it is killed in the block.
SmallVector<const BasicBlock *, 8> OpSuccBlocks;
for (IGCLLVM::const_succ_iterator SI = succ_begin(&MBB), E = succ_end(&MBB); SI != E; ++SI) {
const BasicBlock *SuccMBB = *SI;
// Is it alive in this successor?
if (VI.AliveBlocks.count((BasicBlock *)SuccMBB))
return true;
OpSuccBlocks.push_back(SuccMBB);
}
// Check to see if this value is live because there is a use in a successor
// that kills it.
switch (OpSuccBlocks.size()) {
case 1: {
const BasicBlock *SuccMBB = OpSuccBlocks[0];
for (unsigned i = 0, e = VI.Kills.size(); i != e; ++i)
if (VI.Kills[i]->getParent() == SuccMBB)
return true;
break;
}
case 2: {
const BasicBlock *SuccMBB1 = OpSuccBlocks[0], *SuccMBB2 = OpSuccBlocks[1];
for (unsigned i = 0, e = VI.Kills.size(); i != e; ++i)
if (VI.Kills[i]->getParent() == SuccMBB1 || VI.Kills[i]->getParent() == SuccMBB2)
return true;
break;
}
default:
std::sort(OpSuccBlocks.begin(), OpSuccBlocks.end());
for (unsigned i = 0, e = VI.Kills.size(); i != e; ++i)
if (std::binary_search(OpSuccBlocks.begin(), OpSuccBlocks.end(), VI.Kills[i]->getParent()))
return true;
}
return false;
}
void LiveVars::Calculate(Function *mf, WIAnalysis *wia) {
releaseMemory();
MF = mf;
WIA = wia;
preAllocMemory(*MF);
initDistance(*MF);
analyzePHINodes(*mf);
BasicBlock *Entry = &(*MF->begin());
typedef df_iterator_default_set<BasicBlock *, 16> VisitedTy;
VisitedTy Visited;
for (df_ext_iterator<BasicBlock *, VisitedTy> DFI = df_ext_begin(Entry, Visited), DFE = df_ext_end(Entry, Visited);
DFI != DFE; ++DFI) {
BasicBlock *MBB = *DFI;
// Loop over all of the instructions, processing them.
for (BasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E; ++I) {
Instruction *MI = &(*I);
// Unless it is a PHI node. In this case, ONLY process the DEF, not any
// of the uses. They will be handled in other basic blocks.
if (!isa<PHINode>(MI)) {
// Process all uses.
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
Value *V = MI->getOperand(i);
if (isa<Instruction>(V) || isa<Argument>(V)) {
HandleVirtRegUse(V, MBB, MI, false, true);
}
}
}
// Since we will handle a value only if it is used, no need to explicitly
// handle def here. And getLVInfo() will handle the def when handling its
// first use. So as a result commenting the following out, no LV is created
// for a dead instruction, which makes sense. Note that this is different
// from the llvm core, as llvm core getVarInfo is different from getLVInfo()!
#if 0
// Process all defs.
if (!MI->getType()->isVoidTy())
{
HandleVirtRegDef(MI);
}
#endif
}
// Handle any virtual assignments from PHI nodes which might be at the
// bottom of this basic block. We check all of our successor blocks to see
// if they have PHI nodes, and if so, we simulate an assignment at the end
// of the current block.
auto it = PHIVarInfo.find(MBB);
if (it != PHIVarInfo.end()) {
SmallVector<Value *, 4> &VarInfoVec = it->second;
for (SmallVector<Value *, 4>::iterator I = VarInfoVec.begin(), E = VarInfoVec.end(); I != E; ++I) {
// Mark it alive only in the block we are representing.
Value *DefV = *I;
BasicBlock *DefBlk = (isa<Instruction>(DefV)) ? cast<Instruction>(DefV)->getParent() : NULL;
MarkVirtRegAliveInBlock(getLVInfo(DefV), DefBlk, MBB);
#if VECTOR_COALESCING == 0
// special treatment for ExtractElement
Instruction *EEI = dyn_cast<ExtractElementInst>(DefV);
if (EEI) {
DefV = EEI->getOperand(0);
if (isa<Instruction>(DefV) || isa<Argument>(DefV)) {
DefBlk = (isa<Instruction>(DefV)) ? cast<Instruction>(DefV)->getParent() : NULL;
MarkVirtRegAliveInBlock(getLVInfo(DefV), DefBlk, MBB);
}
}
#endif
}
}
}
}
bool LiveVars::hasInterference(llvm::Value *V0, llvm::Value *V1) {
// Skip Constant
if (isa<Constant>(V0) || isa<Constant>(V1)) {
return false;
}
Instruction *I0 = dyn_cast<Instruction>(V0);
Instruction *I1 = dyn_cast<Instruction>(V1);
if (!I0 && !I1) {
return true;
}
if (!I0) {
// V0 must be argument. Use the first inst in Entry
I0 = MF->getEntryBlock().getFirstNonPHIOrDbg();
}
if (!I1) {
// V1 must be argument. Use the first inst in Entry
I1 = MF->getEntryBlock().getFirstNonPHIOrDbg();
}
if (isLiveAt(V0, I1) || isLiveAt(V1, I0)) {
return true;
}
return false;
}
// Merge LVInfo for "fromV" into V's.
//
// This function is used after LVInfo has been constructed already and
// we want to merge "fromV" into V. This function will have V's LVInfo
// updated to reflect such a merging.
void LiveVars::mergeUseFrom(Value *V, Value *fromV) {
// Normally, both VitrRegInfo.count(V) and VirtRegInfo.count(fromV) are
// non-zero, meaning their LVInfo have been constructed (they are not
// dead). However, we see inline asm case in which fromV is dead in term
// of llvm value usage and therefore no LVInfo (as inline asm call has
// side-effect, the inline asm is not dead). For this reason, we relax
// assertion to require at least one has LVInfo.
IGC_ASSERT_MESSAGE(VirtRegInfo.count(V) || VirtRegInfo.count(fromV),
"MergeUseFrom should be used after LVInfo have been constructed!");
LVInfo &LVI = getLVInfo(V);
LVInfo &fromLVI = getLVInfo(fromV);
uint32_t newNumUses = LVI.NumUses + fromLVI.NumUses;
IGC_ASSERT_MESSAGE(LVI.uniform == fromLVI.uniform, "ICE: cannot merge uniform with non-uniform values!");
// Use V's defining BB, not fromV's
Instruction *defInst = dyn_cast<Instruction>(V);
BasicBlock *defBB = defInst ? defInst->getParent() : nullptr;
// For each AliveBlock of fromV, add it to V's
for (auto I : fromLVI.AliveBlocks) {
BasicBlock *BB = I;
MarkVirtRegAliveInBlock(LVI, defBB, BB);
}
// For each kill, add it into V's LVInfo
for (auto KI : fromLVI.Kills) {
Instruction *inst = KI;
BasicBlock *instBB = inst->getParent();
// Must set ScanAllKills as we are doing updating.
HandleVirtRegUse(V, instBB, inst, true);
}
// Special case. fromV is used in the phi.
//
// If a value is defined in BB and its last use is in
// a PHI in succ(BB), both its AliveBlocks and Kills
// are empty (see LiveVars.hpp)
// For example:
// BB:
// fromV = bitcast V
// succ_BB:
// phi = fromV
//
// In this case, we will need to make sure BB is marked as alive.
if (Instruction *I = dyn_cast<Instruction>(fromV)) {
for (User *user : I->users()) {
if (dyn_cast<PHINode>(user)) {
BasicBlock *BB = I->getParent();
MarkVirtRegAliveInBlock(LVI, defBB, BB);
break;
}
}
}
LVI.NumUses = newNumUses;
}
IGC_INITIALIZE_PASS_BEGIN(LiveVarsAnalysis, "LiveVarsAnalysis", "LiveVarsAnalysis", false, true)
IGC_INITIALIZE_PASS_DEPENDENCY(MetaDataUtilsWrapper)
IGC_INITIALIZE_PASS_END(LiveVarsAnalysis, "LiveVarsAnalysis", "LiveVarsAnalysis", false, true)
char LiveVarsAnalysis::ID = 0;
LiveVarsAnalysis::LiveVarsAnalysis() : FunctionPass(ID) {
initializeLiveVarsAnalysisPass(*PassRegistry::getPassRegistry());
}
bool LiveVarsAnalysis::runOnFunction(Function &F) {
// WIAnalysis skips functions that are not recorded.
auto pMdUtils = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
if (pMdUtils->findFunctionsInfoItem(&F) == pMdUtils->end_FunctionsInfo()) {
return false;
}
auto WIA = getAnalysisIfAvailable<WIAnalysis>();
LV.ComputeLiveness(&F, WIA);
return false;
}