forked from OSchip/llvm-project
BlockGenerator: Directly handle multi-exit PHI nodes
This change adds code to directly code-generate multi-exit PHI nodes, instead of trying to reuse the EscapeMap infrastructure for this. Using escape maps adds a level of indirection that is hard to understand and - more importantly - breaks in certain cases. Specifically, the original code relied on simplifyRegion() to split the original PHI node in two PHI nodes, one merging the values coming from within the scop and a second that merges the first PHI node with the values that come from outside the scop. To generate code the first PHI node is then just handled like any other in-scop value that is used somewhere outside the scop. This fails for the case where all values from inside the scop are identical, as the first PHI node is in such cases automatically simplified and eliminated by LLVM right at construction. As a result, there is no instruction that can be pass to the EscapeMap handling, which means the references in the second PHI node are not updated and may still reference values from within the original scop that do not dominate it. Our new code iterates directly over all modeled ScopArrayInfo objects that represent multi-exit PHI nodes and generates code for them without relying on the EscapeMap infrastructure. Hence, it works also for the case where the first PHI node is eliminated. llvm-svn: 251191
This commit is contained in:
parent
34d40434a7
commit
27d742da59
|
@ -396,6 +396,22 @@ protected:
|
|||
/// @param S The scop for which to generate the scalar initializers.
|
||||
void createScalarInitialization(Scop &S);
|
||||
|
||||
/// @brief Create exit PHI node merges for PHI nodes with more than two edges
|
||||
/// from inside the scop.
|
||||
///
|
||||
/// For scops which have a PHI node in the exit block that has more than two
|
||||
/// incoming edges from inside the scop region, we require some special
|
||||
/// handling to understand which of the possible values will be passed to the
|
||||
/// PHI node from inside the optimized version of the scop. To do so ScopInfo
|
||||
/// models the possible incoming values as write accesses of the ScopStmts.
|
||||
///
|
||||
/// This function creates corresponding code to reload the computed outgoing
|
||||
/// value from the stack slot it has been stored into and to pass it on to the
|
||||
/// PHI node in the original exit block.
|
||||
///
|
||||
/// @param S The scop for which to generate the exiting PHI nodes.
|
||||
void createExitPHINodeMerges(Scop &S);
|
||||
|
||||
/// @brief Promote the values of demoted scalars after the SCoP.
|
||||
///
|
||||
/// If a scalar value was used outside the SCoP we need to promote the value
|
||||
|
|
|
@ -568,22 +568,6 @@ void BlockGenerator::createScalarFinalization(Region &R) {
|
|||
|
||||
void BlockGenerator::findOutsideUsers(Scop &S) {
|
||||
auto &R = S.getRegion();
|
||||
|
||||
// Handle PHI nodes that were in the original exit and are now
|
||||
// moved into the region exiting block.
|
||||
if (!S.hasSingleExitEdge()) {
|
||||
for (Instruction &I : *S.getRegion().getExitingBlock()) {
|
||||
PHINode *PHI = dyn_cast<PHINode>(&I);
|
||||
if (!PHI)
|
||||
break;
|
||||
|
||||
assert(PHI->getNumUses() == 1);
|
||||
assert(ScalarMap.count(PHI->user_back()));
|
||||
|
||||
handleOutsideUsers(S.getRegion(), PHI, ScalarMap[PHI->user_back()]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &Pair : S.arrays()) {
|
||||
auto &Array = Pair.second;
|
||||
|
||||
|
@ -608,9 +592,53 @@ void BlockGenerator::findOutsideUsers(Scop &S) {
|
|||
}
|
||||
}
|
||||
|
||||
void BlockGenerator::createExitPHINodeMerges(Scop &S) {
|
||||
if (S.hasSingleExitEdge())
|
||||
return;
|
||||
|
||||
Region &R = S.getRegion();
|
||||
|
||||
auto *ExitBB = R.getExitingBlock();
|
||||
auto *MergeBB = R.getExit();
|
||||
auto *AfterMergeBB = MergeBB->getSingleSuccessor();
|
||||
BasicBlock *OptExitBB = *(pred_begin(MergeBB));
|
||||
if (OptExitBB == ExitBB)
|
||||
OptExitBB = *(++pred_begin(MergeBB));
|
||||
|
||||
Builder.SetInsertPoint(OptExitBB->getTerminator());
|
||||
|
||||
for (auto &Pair : S.arrays()) {
|
||||
auto &SAI = Pair.second;
|
||||
auto *Val = SAI->getBasePtr();
|
||||
|
||||
PHINode *PHI = dyn_cast<PHINode>(Val);
|
||||
if (!PHI)
|
||||
continue;
|
||||
|
||||
if (PHI->getParent() != AfterMergeBB) {
|
||||
assert(R.contains(PHI) &&
|
||||
"Modeled PHI nodes are expected to be in the region");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string Name = PHI->getName();
|
||||
Value *ScalarAddr = getOrCreateScalarAlloca(PHI);
|
||||
Value *Reload = Builder.CreateLoad(ScalarAddr, Name + ".ph.final_reload");
|
||||
Reload = Builder.CreateBitOrPointerCast(Reload, PHI->getType());
|
||||
Value *OriginalValue = PHI->getIncomingValueForBlock(MergeBB);
|
||||
auto *MergePHI = PHINode::Create(PHI->getType(), 2, Name + ".ph.merge");
|
||||
MergePHI->insertBefore(MergeBB->getFirstInsertionPt());
|
||||
MergePHI->addIncoming(Reload, OptExitBB);
|
||||
MergePHI->addIncoming(OriginalValue, ExitBB);
|
||||
int Idx = PHI->getBasicBlockIndex(MergeBB);
|
||||
PHI->setIncomingValue(Idx, MergePHI);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockGenerator::finalizeSCoP(Scop &S) {
|
||||
findOutsideUsers(S);
|
||||
createScalarInitialization(S);
|
||||
createExitPHINodeMerges(S);
|
||||
createScalarFinalization(S.getRegion());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue