源码解读---mem2reg源码(3)
作者:互联网
这篇文章接着之前写的。。
源码解读—mem2reg源码(1)
源码解读—mem2reg源码(2)
本文主要介绍在插入phi节点后的重命名。
重命名中第一个核心函数是RenamePass这个函数,看注释:
/// Recursively traverse the CFG of the function, renaming loads and
/// stores to the allocas which we are promoting.
///
/// IncomingVals indicates what value each Alloca contains on exit from the
/// predecessor block Pred.
void PromoteMem2Reg::RenamePass(BasicBlock *BB, BasicBlock *Pred,
RenamePassData::ValVector &IncomingVals,
RenamePassData::LocationVector &IncomingLocs,
std::vector<RenamePassData> &Worklist) {
NextIteration:
// If we are inserting any phi nodes into this BB, they will already be in the
// block.
if (PHINode *APN = dyn_cast<PHINode>(BB->begin())) {
// If we have PHI nodes to update, compute the number of edges from Pred to
// BB.
if (PhiToAllocaMap.count(APN)) {
// We want to be able to distinguish between PHI nodes being inserted by
// this invocation of mem2reg from those phi nodes that already existed in
// the IR before mem2reg was run. We determine that APN is being inserted
// because it is missing incoming edges. All other PHI nodes being
// inserted by this pass of mem2reg will have the same number of incoming
// operands so far. Remember this count.
// 这一堆文字说的是,我们的PHI节点可能源程序就有,所以为了区别源程序中的PHI节点和我们添加的PHI节点,
// 我们获取它的操作数,我们添加的PHI节点的操作数一定相等,且初始值为0,即没有操作数。
unsigned NewPHINumOperands = APN->getNumOperands();
unsigned NumEdges = std::count(succ_begin(Pred), succ_end(Pred), BB);
assert(NumEdges && "Must be at least one edge from Pred to BB!");
// Add entries for all the phis.
BasicBlock::iterator PNI = BB->begin();
do {
unsigned AllocaNo = PhiToAllocaMap[APN];
// Update the location of the phi node.
updateForIncomingValueLocation(APN, IncomingLocs[AllocaNo],
APN->getNumIncomingValues() > 0);
// Add N incoming values to the PHI node.
// 为PHI节点添加操作数
for (unsigned i = 0; i != NumEdges; ++i)
APN->addIncoming(IncomingVals[AllocaNo], Pred); <---------- (1)
// The currently active variable for this block is now the PHI.
IncomingVals[AllocaNo] = APN;
for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[AllocaNo])
ConvertDebugDeclareToDebugValue(DII, APN, DIB);
// Get the next phi node.
++PNI;
APN = dyn_cast<PHINode>(PNI);
if (!APN)
break;
// Verify that it is missing entries. If not, it is not being inserted
// by this mem2reg invocation so we want to ignore it.
} while (APN->getNumOperands() == NewPHINumOperands);
}
}
// Don't revisit blocks.
if (!Visited.insert(BB).second)
return;
// 下面的for循环是在做替换。
// 比如 %a = alloca i32
// %0 = load i32 %a
// store i32 5, i32* %0
// store i32* %0, i32* %1
// 那么就会变成:
// store i32 5, i32* %1
// else分支中的store同上,昨晚这一切之后,删除相对应的load和store
for (BasicBlock::iterator II = BB->begin(); !II->isTerminator();) {
Instruction *I = &*II++; // get the instruction, increment iterator
if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
AllocaInst *Src = dyn_cast<AllocaInst>(LI->getPointerOperand());
if (!Src)
continue;
DenseMap<AllocaInst *, unsigned>::iterator AI = AllocaLookup.find(Src);
if (AI == AllocaLookup.end())
continue;
Value *V = IncomingVals[AI->second];
// If the load was marked as nonnull we don't want to lose
// that information when we erase this Load. So we preserve
// it with an assume.
if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
!isKnownNonZero(V, SQ.DL, 0, AC, LI, &DT))
addAssumeNonNull(AC, LI);
// Anything using the load now uses the current value.
LI->replaceAllUsesWith(V);
BB->getInstList().erase(LI);
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
// Delete this instruction and mark the name as the current holder of the
// value
AllocaInst *Dest = dyn_cast<AllocaInst>(SI->getPointerOperand());
if (!Dest)
continue;
DenseMap<AllocaInst *, unsigned>::iterator ai = AllocaLookup.find(Dest);
if (ai == AllocaLookup.end())
continue;
// what value were we writing?
unsigned AllocaNo = ai->second;
IncomingVals[AllocaNo] = SI->getOperand(0);
// Record debuginfo for the store before removing it.
IncomingLocs[AllocaNo] = SI->getDebugLoc();
for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[ai->second])
ConvertDebugDeclareToDebugValue(DII, SI, DIB);
BB->getInstList().erase(SI);
}
}
// 'Recurse' to our successors.
succ_iterator I = succ_begin(BB), E = succ_end(BB);
if (I == E)
return;
// Keep track of the successors so we don't visit the same successor twice
SmallPtrSet<BasicBlock *, 8> VisitedSuccs;
// Handle the first successor without using the worklist.
VisitedSuccs.insert(*I);
Pred = BB;
BB = *I;
++I;
for (; I != E; ++I)
if (VisitedSuccs.insert(*I).second)
Worklist.emplace_back(*I, Pred, IncomingVals, IncomingLocs);
goto NextIteration;
}
第一个箭头处代码的意思是,我们为PHI 节点加上入口边。什么意思?还记得我们在上篇文章说了,上篇文章放置PHI节点的时候,只是放了一个PHI节点的空壳,还没有数据,这里就是给PHI节点放数据的。比如上篇文章的PHI节点是:
%1 = PHI i32
箭头处加完数据后:
%1 = PHI i32 10, i32* %0
后面一段代码就是做一些代码收尾工作,清除无用的alloca代码。
// Remove the allocas themselves from the function.
for (Instruction *A : Allocas) {
// If there are any uses of the alloca instructions left, they must be in
// unreachable basic blocks that were not processed by walking the dominator
// tree. Just delete the users now.
if (!A->use_empty())
A->replaceAllUsesWith(UndefValue::get(A->getType()));
A->eraseFromParent();
}
// Remove alloca's dbg.declare instrinsics from the function.
for (auto &Declares : AllocaDbgDeclares)
for (auto *DII : Declares)
DII->eraseFromParent();
// Loop over all of the PHI nodes and see if there are any that we can get
// rid of because they merge all of the same incoming values. This can
// happen due to undef values coming into the PHI nodes. This process is
// iterative, because eliminating one PHI node can cause others to be removed.
bool EliminatedAPHI = true;
while (EliminatedAPHI) {
EliminatedAPHI = false;
// Iterating over NewPhiNodes is deterministic, so it is safe to try to
// simplify and RAUW them as we go. If it was not, we could add uses to
// the values we replace with in a non-deterministic order, thus creating
// non-deterministic def->use chains.
for (DenseMap<std::pair<unsigned, unsigned>, PHINode *>::iterator
I = NewPhiNodes.begin(),
E = NewPhiNodes.end();
I != E;) {
PHINode *PN = I->second;
// If this PHI node merges one value and/or undefs, get the value.
if (Value *V = SimplifyInstruction(PN, SQ)) { <-----------
PN->replaceAllUsesWith(V);
PN->eraseFromParent();
NewPhiNodes.erase(I++);
EliminatedAPHI = true;
continue;
}
++I;
}
}
箭头处的代码比较有意思,是看我们插入的PHI节点能不能被简化,这部分代码比较长,建议感兴趣自己去看看。其实影响不会很大。
最后一段代码就不放了,主要就是处理那些不能被遍历到的基本块。基本就是做些收尾工作。
到这里,整个mem2reg的代码分析完成了,其实并不难,难得是要想清楚整个过程,难的是写出健壮、鲁棒性高的代码。。
好了,就这样。。
后面有空会分析其他pass。
标签:PHI,BB,i32,mem2reg,---,源码,APN,Pred,节点 来源: https://blog.csdn.net/a173373310/article/details/119442823