源码解读---mem2reg源码(3)
2021/8/6 9:06:02
本文主要是介绍源码解读---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。
这篇关于源码解读---mem2reg源码(3)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南