[llvm-commits] Patch for simplifying regions
Vu Le
vmle at ucdavis.edu
Wed Mar 2 12:08:33 PST 2011
Add more test cases.
Vu
On Tue, Mar 1, 2011 at 12:15 PM, Vu Le <vmle at ucdavis.edu> wrote:
>
>
> On Tue, Mar 1, 2011 at 12:12 PM, Vu Le <vmle at ucdavis.edu> wrote:
>
>> Hi Tobias,
>> Thanks for the feedback.
>>
>> On Tue, Mar 1, 2011 at 5:49 AM, Tobias Grosser <grosser at fim.uni-passau.de
>> > wrote:
>>
>>> On 02/28/2011 02:52 PM, Vu Le wrote:
>>>
>>>> Hi Tobias,
>>>>
>>>> I did make some changes to use splitBlockPredecessors in splitting
>>>> entry nodes.
>>>>
>>>
>>> Thanks for your fast reaction. The patch looks very nice. Though I have
>>> some comments that we need to fix before committing it.
>>>
>>> Thank you.
>>
>>>
>>> I tested it with coreutils and MySQL together with region-extractor
>>>> pass.
>>>>
>>> Nice.
>>>
>>>
>>> If you're still interested in region-extractor pass, I'll make a patch.
>>>>
>>> Yes. I am extremely interested.
>>>
>>> diff --git a/include/llvm/InitializePasses.h
>>>> b/include/llvm/InitializePasses.h
>>>> index 02dbfbd..0591845 100644
>>>> --- a/include/llvm/InitializePasses.h
>>>> +++ b/include/llvm/InitializePasses.h
>>>> @@ -192,6 +192,7 @@ void initializeRegionInfoPass(PassRegistry&);
>>>> void initializeRegionOnlyPrinterPass(PassRegistry&);
>>>> void initializeRegionOnlyViewerPass(PassRegistry&);
>>>> void initializeRegionPrinterPass(PassRegistry&);
>>>> +void initializeRegionSimplifyPass(PassRegistry&);
>>>> void initializeRegionViewerPass(PassRegistry&);
>>>> void initializeRegisterCoalescerAnalysisGroup(PassRegistry&);
>>>> void initializeRenderMachineFunctionPass(PassRegistry&);
>>>> diff --git a/include/llvm/LinkAllPasses.h b/include/llvm/LinkAllPasses.h
>>>> index 69e1bd9..ea1faec 100644
>>>> --- a/include/llvm/LinkAllPasses.h
>>>> +++ b/include/llvm/LinkAllPasses.h
>>>> @@ -114,7 +114,8 @@ namespace {
>>>> (void) llvm::createRegionInfoPass();
>>>> (void) llvm::createRegionOnlyPrinterPass();
>>>> (void) llvm::createRegionOnlyViewerPass();
>>>> - (void) llvm::createRegionPrinterPass();
>>>> + (void) llvm::createRegionPrinterPass();
>>>>
>>> This change does not seem to be needed. Please remove it.
>>>
>>> OK
>>
>>> + (void) llvm::createRegionSimplifyPass();
>>>> (void) llvm::createRegionViewerPass();
>>>> (void) llvm::createSCCPPass();
>>>> (void) llvm::createScalarReplAggregatesPass();
>>>> diff --git a/include/llvm/Transforms/Scalar.h
>>>> b/include/llvm/Transforms/Scalar.h
>>>> index 6f2a38e..e3ca06a 100644
>>>> --- a/include/llvm/Transforms/Scalar.h
>>>> +++ b/include/llvm/Transforms/Scalar.h
>>>> @@ -349,6 +349,12 @@ Pass *createCorrelatedValuePropagationPass();
>>>> FunctionPass *createInstructionSimplifierPass();
>>>> extern char&InstructionSimplifierID;
>>>>
>>>>
>>>> +//===----------------------------------------------------------------------===//
>>>> +//
>>>> +// RegionSimplify - Simplify refined regions, if possible.
>>>>
>>> Are there cases when it is not possible? Would be interesting to mention
>>> those.
>>>
>>> It is when a region has function entry as its entry and a single edge
>> exit.
>> But then it is a simple region, I suppose.
>> I'll remove the "if possible" part.
>>
>> +Pass *createRegionSimplifyPass();
>>>> +
>>>> } // End llvm namespace
>>>>
>>>> #endif
>>>> diff --git a/lib/Transforms/Scalar/CMakeLists.txt
>>>> b/lib/Transforms/Scalar/CMakeLists.txt
>>>> index 106fb8f..53fcf69 100644
>>>> --- a/lib/Transforms/Scalar/CMakeLists.txt
>>>> +++ b/lib/Transforms/Scalar/CMakeLists.txt
>>>> @@ -23,6 +23,7 @@ add_llvm_library(LLVMScalarOpts
>>>> MemCpyOptimizer.cpp
>>>> Reassociate.cpp
>>>> Reg2Mem.cpp
>>>> + RegionSimplify.cpp
>>>> SCCP.cpp
>>>> Scalar.cpp
>>>> ScalarReplAggregates.cpp
>>>> diff --git a/lib/Transforms/Scalar/RegionSimplify.cpp
>>>> b/lib/Transforms/Scalar/RegionSimplify.cpp
>>>> new file mode 100644
>>>> index 0000000..65e4d5c
>>>> --- /dev/null
>>>> +++ b/lib/Transforms/Scalar/RegionSimplify.cpp
>>>> @@ -0,0 +1,185 @@
>>>> +//===- SeSeRegionInfo.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 "llvm/Instructions.h"
>>>> +#include "llvm/ADT/Statistic.h"
>>>> +#include "llvm/Analysis/Dominators.h"
>>>> +#include "llvm/Analysis/RegionPass.h"
>>>> +#include "llvm/Analysis/RegionInfo.h"
>>>> +#include "llvm/Transforms/Utils/BasicBlockUtils.h"
>>>> +
>>>> +#define DEBUG_TYPE "regionsimplify"
>>>>
>>> Can we call the pass "region-simplify"? Like "loop-simplify" (The name
>>> was recently changed)
>>>
>>> Sure
>>
>>> +using namespace llvm;
>>>> +
>>>> +STATISTIC(NumEntries, "The # of created entry edges");
>>>> +STATISTIC(NumExits, "The # of created exit edges");
>>>> +
>>>> +namespace {
>>>> +class RegionSimplify: public RegionPass {
>>>> + bool modified;
>>>> + Region *CR;
>>>> + void createSingleEntryEdge(Region *R);
>>>> + void createSingleExitEdge(Region *R);
>>>> +public:
>>>> + static char ID;
>>>> + explicit RegionSimplify() :
>>>> + RegionPass(ID) {
>>>> + initializeRegionSimplifyPass(*PassRegistry::getPassRegistry());
>>>> + }
>>>> +
>>>> + virtual void print(raw_ostream&O, const Module *M) const;
>>>> +
>>>> + virtual bool runOnRegion(Region *R, RGPassManager&RGM);
>>>> + virtual void getAnalysisUsage(AnalysisUsage&AU) const;
>>>> +};
>>>> +}
>>>> +
>>>> +INITIALIZE_PASS(RegionSimplify, "regionsimplify",
>>>>
>>> "regionsimplify" -> "region-simplify"
>>>
>> OK
>>
>>>
>>> + "Transform refined regions into simple regions", false, false)
>>>> +
>>>> +char RegionSimplify::ID = 0;
>>>> +namespace llvm {
>>>> +Pass *createRegionSimplifyPass() {
>>>> + return new RegionSimplify();
>>>> +}
>>>> +}
>>>> +
>>>> +void RegionSimplify::print(raw_ostream&O, const Module *M) const {
>>>>
>>>> + if (!modified)
>>>> + return;
>>>> +
>>>> + BasicBlock *enteringBlock = CR->getEnteringBlock();
>>>> + BasicBlock *exitingBlock = CR->getExitingBlock();
>>>> +
>>>> + O<< "\nRegion: ["<< CR->getNameStr()<< "] Edges:\n";
>>>> + if (enteringBlock)
>>>> + O<< " Entry: ]"<< enteringBlock->getNameStr()<< " => "
>>>> +<< enteringBlock->getNameStr()<< "]\n";
>>>> + if (exitingBlock)
>>>> + O<< " Exit: ["<< exitingBlock->getNameStr()<< " => "
>>>> +<< exitingBlock->getNameStr()<< "[\n";
>>>> +
>>>> + O<< "\n";
>>>> +}
>>>> +
>>>> +void RegionSimplify::getAnalysisUsage(AnalysisUsage&AU) const {
>>>> + AU.addPreserved<DominatorTree> ();
>>>> + AU.addPreserved<RegionInfo> ();
>>>> + AU.addRequired<RegionInfo> ();
>>>> +}
>>>> +
>>>> +// 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<BasicBlock*, 4> Preds;
>>>>
>>>> + for (pred_iterator PI = pred_begin(oldEntry), PE =
>>>> pred_end(oldEntry);
>>>> + PI != PE; ++PI)
>>>> + if (!R->contains(*PI))
>>>> + Preds.push_back(*PI);
>>>> +
>>>> + if (Preds.size()==0)
>>>> + return;
>>>>
>>> Can we change this to an assert?
>>>
>>> assert(Preds.size() && "This region has already a single entry edge");
>>>
>>
>> Then we have to make sure that R's entry is not the function entry.
>> In runOnRegion
>> if (!(R->getEnteringBlock())
>> && (pred_begin(R->getEntry()) != pred_end(R->getEntry()))) {
>> createSingleEntryEdge(R);
>> ...
>>
>>
>>
>>> +
>>>> + BasicBlock *newEntry = SplitBlockPredecessors(oldEntry,
>>>> + Preds.data(),
>>>> Preds.size(),
>>>> + ".single_entry", this);
>>>> +
>>>> + RegionInfo *RI =&getAnalysis<RegionInfo> ();
>>>> + // 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();
>>>> + 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();
>>>>
>>> r = r->getParent() should be enough?
>>>
>>
>> I don't think so. We want to find ALL other regions, not just the regions
>> starting from
>> parent of R. We must start from the top.
>>
>>>
>>> + std::deque<Region *> RQ;
>>>>
>>> std::vector is probably simpler
>>>
>>> + RQ.push_back(r);
>>>> + while (!RQ.empty()){
>>>> + r = RQ.front();
>>>> + 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);
>>>> + RQ.pop_front();
>>>> + }
>>>>
>>> I need to think about this part (Will send feedback later).
>>>
>> This is not clean. Here is a cleaner version
>> r = RI->getTopLevelRegion();
>> std::vector<Region *> RQ;
>>
>> RQ.push_back(r);
>>
>> while (!RQ.empty()){
>> r = RQ.back();
>> RQ.pop_back();
>>
>> if (r->getExit() != oldEntry || R->contains(r))
>> continue;
>>
>> r->replaceExit(newEntry);
>>
>>
>> for (Region::const_iterator RI = r->begin(), RE = r->end(); RI!=RE;
>> ++RI)
>> RQ.push_back(*RI);
>> }
>>
> Please ignore this code fragment. It should be like this:
>
> r = RI->getTopLevelRegion();
> std::vector<Region *> 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);
> }
>
>
>
>> We cannot make sure that those regions whose exit is OldEntry belong to
>> any
>>
>> particular subregions. That's why we have to iterate over all the regions
>> in the
>> tree.
>>
>>>
>>> +
>>>> + modified |= true;
>>>>
>>> I do not believe this is part of creating the edges. 'modified' is part
>>> of the status tracking of the pass and should probably be put into
>>> runOnRegion().
>>>
>>> + ++NumEntries;
>>>>
>>> Dito. Please put in runOnRegion().
>>>
>> Sure.
>>
>>>
>>> +}
>>>> +
>>>> +// 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<BasicBlock*, 4> Preds;
>>>> + for (pred_iterator PI = pred_begin(oldExit), PE = pred_end(oldExit);
>>>>
>>>> + PI != PE; ++PI)
>>>> + if (R->contains(*PI))
>>>> + Preds.push_back(*PI);
>>>> +
>>>> + BasicBlock *newExit = SplitBlockPredecessors(oldExit,
>>>> + Preds.data(),
>>>> Preds.size(),
>>>> + ".single_exit", this);
>>>> + RegionInfo *RI =&getAnalysis<RegionInfo> ();
>>>> +
>>>> + // 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);
>>>> +
>>>> + // all children of this region whose exit is oldExit is changed to
>>>> newExit
>>>> + std::deque<Region *> RQ;
>>>> + for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE;
>>>> ++RI)
>>>> + RQ.push_back(*RI);
>>>> + while (!RQ.empty()){
>>>> + R = RQ.front();
>>>> + for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE;
>>>> ++RI)
>>>> + RQ.push_back(*RI);
>>>> +
>>>> + if (R->getExit() == oldExit)
>>>> + R->replaceExit(newExit);
>>>> + RQ.pop_front();
>>>> + }
>>>>
>>>
>>> A vector is probably simpler. We also do not need to add child regions
>>> for regions that do not have an exit matching oldExit. What about this code?
>>>
>> I'm not sure about this.
>> A child might not share the exit with its parent.
>> I think we still need to check.
>>
>>>
>>> std::vector<Region *> RQ;
>>>
>>> while (!RQ.empty()){
>>> R = RQ.back();
>>> RQ.pop_back();
>>>
>>> if (R->getExit() != oldExit)
>>> continue;
>>>
>>> R->replaceExit(newExit);
>>>
>>> for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE;
>>> ++RI)
>>> RQ.push_back(*RI);
>>>
>>> }
>>>
>>> std::vector<Region *> 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();
>>
>>
>> for (Region::const_iterator RI = R->begin(), RE = R->end(); RI!=RE;
>> ++RI)
>> RQ.push_back(*RI);
>>
>> if (R->getExit() == oldExit)
>> R->replaceExit(newExit);
>> }
>>
>>
>>>
>>> +
>>>> + modified |= true;
>>>>
>>> This function always modifies the CFG. So no need to put additional logic
>>> here.
>>>
>>> + ++NumExits;
>>>>
>>> Dito.
>>>
>>> +}
>>>>
>>>> +
>>>> +bool RegionSimplify::runOnRegion(Region *R, RGPassManager&RGM) {
>>>> + modified = false;
>>>> +
>>>> + CR = R;
>>>> + if (!R->isTopLevelRegion()) {
>>>> +
>>>> + if (!(R->getEnteringBlock())) {
>>>> + createSingleEntryEdge(R);
>>>> + }
>>>>
>>>
>>> if (!(R->getEnteringBlock())) {
>>> createSingleEntryEdge(R);
>>> ++NumEntries;
>>> modified = true.
>>> }
>>>
>> We need to add additional check for the special case where R does not have
>> any predecessor.
>>
>> if (!(R->getEnteringBlock())
>> && (pred_begin(R->getEntry()) != pred_end(R->getEntry()))) {
>> createSingleEntryEdge(R);
>> modified = true;
>> ++NumEntries;
>> }
>>
>>>
>>> +
>>>> + if (!(R->getExitingBlock())) {
>>>> + modified |= createSingleExitEdge(R);
>>>>
>>>
>>> if (!(R->getExitingBlock())) {
>>> createSingleExitEdge(R);
>>> ++NumExits;
>>> modified = true;
>>> }
>>>
>>> + }
>>>> + }
>>>> +
>>>> + return modified;
>>>> +}
>>>> diff --git a/lib/Transforms/Scalar/Scalar.cpp
>>>> b/lib/Transforms/Scalar/Scalar.cpp
>>>> index bf9ca6d..5d18f22 100644
>>>> --- a/lib/Transforms/Scalar/Scalar.cpp
>>>> +++ b/lib/Transforms/Scalar/Scalar.cpp
>>>> @@ -51,6 +51,7 @@ void llvm::initializeScalarOpts(PassRegistry&Registry)
>>>> {
>>>> initializeMemCpyOptPass(Registry);
>>>> initializeReassociatePass(Registry);
>>>> initializeRegToMemPass(Registry);
>>>> + initializeRegionSimplifyPass(Registry);
>>>> initializeSCCPPass(Registry);
>>>> initializeIPSCCPPass(Registry);
>>>> initializeSROA_DTPass(Registry);
>>>> diff --git a/test/Transforms/RegionSimplify/dg.exp
>>>> b/test/Transforms/RegionSimplify/dg.exp
>>>> new file mode 100644
>>>> index 0000000..f200589
>>>> --- /dev/null
>>>> +++ b/test/Transforms/RegionSimplify/dg.exp
>>>> @@ -0,0 +1,3 @@
>>>> +load_lib llvm.exp
>>>> +
>>>> +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
>>>> diff --git a/test/Transforms/RegionSimplify/multi_exits.ll
>>>> b/test/Transforms/RegionSimplify/multi_exits.ll
>>>> new file mode 100644
>>>> index 0000000..024971c
>>>> --- /dev/null
>>>> +++ b/test/Transforms/RegionSimplify/multi_exits.ll
>>>> @@ -0,0 +1,15 @@
>>>> +; RUN: opt -regionsimplify
>>>>
>>>
>>> Did you test this test case. I believe you should use a line like:
>>>
>>> ; RUN: opt -regionsimplify %s
>>>
>>> Furthermore, we should also check the generated output.
>>>
>>> ; RUN: opt -regionsimplify %s | FileCheck %s
>>>
>>> +define void @f() nounwind {
>>>>
>>> ; CHECK: @f()
>>> ; CHECK: br label %"1"
>>> ...
>>>
>>> Add after the CHECK lines the output you expect.
>>>
>>> The same comments apply to the other test files. I would also be
>>> interested to have some test files that include PHI-Nodes.
>>>
>>> Can you send out an updated patch?
>>>
>>> I'll look at FileCheck and create additional tests.
>> Thank you again for your help ;).
>>
>>
>>> Thanks a lot
>>> Tobi
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20110302/b2568b44/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: regionsimplify3.patch
Type: text/x-patch
Size: 14879 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20110302/b2568b44/attachment.bin>
More information about the llvm-commits
mailing list