//===- RegionSimplify.cpp -------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file converts refined regions detected by the RegionInfo analysis // into simple regions. // //===----------------------------------------------------------------------===// #include "polly/LinkAllPasses.h" #include "llvm/Instructions.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/Dominators.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/RegionPass.h" #include "llvm/Analysis/RegionInfo.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #define DEBUG_TYPE "region-simplify" #include "llvm/Support/Debug.h" using namespace llvm; STATISTIC(NumEntries, "The # of created entry edges"); STATISTIC(NumExits, "The # of created exit edges"); namespace { class RegionSimplify: public RegionPass { // Remember the modified region. Region *r; void createSingleEntryEdge(Region *R); void createSingleExitEdge(Region *R); public: static char ID; explicit RegionSimplify() : RegionPass(ID), r(0) {} virtual void print(raw_ostream &O, const Module *M) const; virtual bool runOnRegion(Region *R, RGPassManager &RGM); virtual void getAnalysisUsage(AnalysisUsage &AU) const; }; } char RegionSimplify::ID = 0; INITIALIZE_PASS_BEGIN(RegionSimplify, "polly-region-simplify", "Transform refined regions into simple regions", false, false) INITIALIZE_PASS_DEPENDENCY(RegionInfo) INITIALIZE_PASS_END(RegionSimplify, "polly-region-simplify", "Transform refined regions into simple regions", false, false) namespace polly { Pass *createRegionSimplifyPass() { return new RegionSimplify(); } } void RegionSimplify::print(raw_ostream &O, const Module *M) const { if (r == 0) return; BasicBlock *enteringBlock = r->getEnteringBlock(); BasicBlock *exitingBlock = r->getExitingBlock(); O << "Region: " << r->getNameStr() << " Edges:\t"; if (enteringBlock) O << "Entering: [" << enteringBlock->getName() << " -> " << r->getEntry()->getName() << "], "; if (exitingBlock) { O << "Exiting: [" << exitingBlock->getName() << " -> "; if (r->getExit()) O << r->getExit()->getName(); else O << ""; O << "]"; } O << "\n"; } void RegionSimplify::getAnalysisUsage(AnalysisUsage &AU) const { // Function SplitBlockPredecessors currently updates/preserves AliasAnalysis, /// DominatorTree, LoopInfo, and LCCSA but no other analyses. //AU.addPreserved(); Break SCEV-AA AU.addPreserved (); AU.addPreserved(); AU.addPreservedID(LCSSAID); AU.addPreserved (); AU.addRequired (); } // createSingleEntryEdge - Split the entry basic block of the given // region after the last PHINode to form a single entry edge. void RegionSimplify::createSingleEntryEdge(Region *R) { BasicBlock *oldEntry = R->getEntry(); SmallVector Preds; for (pred_iterator PI = pred_begin(oldEntry), PE = pred_end(oldEntry); PI != PE; ++PI) if (!R->contains(*PI)) Preds.push_back(*PI); assert(Preds.size() && "This region has already a single entry edge"); BasicBlock *newEntry = SplitBlockPredecessors(oldEntry, Preds, ".single_entry", this); RegionInfo *RI = &getAnalysis (); // We do not update entry node for children of this region. // This make it easier to extract children regions because they do not share // the entry node with their parents. // all parent regions whose entry is oldEntry are updated with newEntry Region *r = R->getParent(); // Put the new entry to R's parent. RI->setRegionFor(newEntry,r); while (r->getEntry() == oldEntry && !r->isTopLevelRegion()) { r->replaceEntry(newEntry); r = r->getParent(); } // We do not update exit node for children of this region for the same reason // of not updating entry node. // All other regions whose exit is oldEntry are updated with new exit node r = RI->getTopLevelRegion(); std::vector RQ; RQ.push_back(r); while (!RQ.empty()){ r = RQ.back(); RQ.pop_back(); for (Region::const_iterator RI = r->begin(), RE = r->end(); RI!=RE; ++RI) RQ.push_back(*RI); if (r->getExit() == oldEntry && !R->contains(r)) r->replaceExit(newEntry); } } // createSingleExitEdge - Split the exit basic of the given region // to form a single exit edge. void RegionSimplify::createSingleExitEdge(Region *R) { BasicBlock *oldExit = R->getExit(); SmallVector Preds; for (pred_iterator PI = pred_begin(oldExit), PE = pred_end(oldExit); PI != PE; ++PI) if (R->contains(*PI)) Preds.push_back(*PI); DEBUG(dbgs() << "Going to create single exit for:\n"); DEBUG(R->print(dbgs(), true, 0, Region::PrintRN)); BasicBlock *newExit = SplitBlockPredecessors(oldExit, Preds, ".single_exit", this); RegionInfo *RI = &getAnalysis(); // We do not need to update entry nodes because this split happens inside // this region and it affects only this region and all of its children. // The new split node belongs to this region RI->setRegionFor(newExit,R); DEBUG(dbgs() << "Adding new exiting block: " << newExit->getName() << '\n'); // all children of this region whose exit is oldExit is changed to newExit std::vector RQ; for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE; ++RI) RQ.push_back(*RI); while (!RQ.empty()){ R = RQ.back(); RQ.pop_back(); if (R->getExit() != oldExit) continue; for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE; ++RI) RQ.push_back(*RI); R->replaceExit(newExit); DEBUG(dbgs() << "Replacing exit for:\n"); DEBUG(R->print(dbgs(), true, 0, Region::PrintRN)); } DEBUG(dbgs() << "After split exit:\n"); DEBUG(R->print(dbgs(), true, 0, Region::PrintRN)); } bool RegionSimplify::runOnRegion(Region *R, RGPassManager &RGM) { r = 0; if (!R->isTopLevelRegion()) { // split entry node if the region has multiple entry edges if (!(R->getEnteringBlock()) && (pred_begin(R->getEntry()) != pred_end(R->getEntry()))) { createSingleEntryEdge(R); r = R; ++NumEntries; } // split exit node if the region has multiple exit edges if (!(R->getExitingBlock())) { createSingleExitEdge(R); r = R; ++NumExits; } } return r != 0; }