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:
Tobias Grosser 2015-10-24 17:41:29 +00:00
parent 34d40434a7
commit 27d742da59
2 changed files with 60 additions and 16 deletions

View File

@ -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

View File

@ -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());
}