[LLVMdev] Make LoopBase inherit from "RegionBase"?

Jan Sjodin jan_sjodin at yahoo.com
Wed Jan 20 09:05:50 PST 2010

>>> bbs, to generate these edges. As we do not have to modify the CFG other
>>> passes like dominance information are still valid, and we do not have to
>>> create a lot of auxiliary bbs, to be able to detect all regions. This
>>> saves memory and runtime. In general it is probably not too easy to
>>> decide where to insert these bbs either:
>> The general rule is to split all blocks with multiple in-edges and multiple out-edges
>> into blocks with either multiple in-edges or multiple out-edges, but not both.
> This is not sufficient, as shown in the example below. It would allow
> only one region.

Yes, but with the insertion of merge-blocks it will allow more (see below).

>> One option is to keep this as an invariant throughout the compiler and make use
>> of the merge blocks (multiple in-edges) to contain only PHI-nodes, and all other code
>> in regular basic blocks. There are different variations on this that may or may not be
>> useful.
> This might be possible, however probably doubling the number of bbs.

I don't know if it will be double, but there will be more basic blocks for sure.

>>>> CFG:
>>>        0
>>>        |
>>>        1
>>>       / |
>>>      2   |
>>>     / \   3
>>>    4   5  |
>>>    |   |  |
>>>    6   7  8
>>>     \  | /
>>>      \ |/       region A: 1 -> 9 {1,2,3,4,5,6,7,8}
>>>        9        region B: 2 -> 9 {2,4,5,6,7}
>>> So we need one bb that joins 6 and 7 and one that joins the two regions
>>> CFG:    0
>>>        |
>>>        1
>>>       / |
>>>      2   |
>>>     / \   3
>>>    4   5  |
>>>    |   |  |
>>>    6   7  8
>>>     \  |  |
>>>      \ |  |     region A: (0,1) -> (9b,9)  {1,2,3,4,5,6,7,8,9a,9b}
>>>       9a  |     region B: (1,2) -> (9a,9b) {2,4,5,6,7,9a}
>>>        \ /
>>>         9b
>>>         |
>>>         9
>> It is fairly simple to use the information from the algorithm to decide
>> where those merges should be inserted to get the expected regions.
>> This may be needed in the cases where a sub-region is too complicated
>> to be represented and must be abstracted into a "black box".
> From which algorithm?  The program structure tree does not give this
> information, does it?

The algorithm that computes the SESE-regions can be used to determine
where the merge-nodes should be inserted. There are a couple of ways
of doing it, but if the bracket sets on two eges can be intersected to
match a third edge (which dominates the first two), you can insert a
merge block for the two edges. You don't have to compute the
dominators, but it helps to explain the problem that way.

>>>> My approach is comparable to this paper:
>>>> The Refined Process Structure Tree by JussiVanhatalo, Hagen Völzer,
>>>> Jana Koehler
>>> I was looking through some slides that described their algorithm. One case that
>>> seems to be legal is this:
>>>       |
>>>      Entry
>>>     /    \
>>>   R0      R1
>>>     \     /
>>>      Exit
>>>        |
>>> With two fragments: Entry->R0->Exit and Entry->R1->Exit, which means
>>> that a fragment cannot be identified using only the entry and exit blocks, but
>>> the internal blocks or edges will also need to be listed. I don't know if this is
>>> relevant to your implementation.
> No. The ideas are comparable, however I believe their implementation is
> a little complicated. ;-)

Do you have the same definition of a region and entry/exit blocks as they do?

> I would mark the regions as:
> Region A: R0 -> Exit, containing {R0}
> Region B: R1 -> Exit, containing {R1}

Is the entry always contained and is the exit never contained, or is that specified
per region? Depending on the restrictions of entry and exit blocks a loop with a single
basic block cannot be an entry or exit by itself. Example:

   /| _
  / |/ \
 B  R  |
  \ |\_/

If you only care about R in this case how is the region formed?

>>> The implementation however takes advantage of the existence of
>>> Dominance/PostDominance information. Therefore it is simpler and
>>> hopefully faster. At the moment run time is comparable to dominance tree
>>> calculation.
>> Both algorithms are linear so there is really no big difference in time imo.
> Sure. However in terms of maintainability it is nice to be able to reuse
> existing analysis instead of write another triconnected component
> analysis upfront.
>> I believe the biggest difference that you mention is that you can capture more
>> complicated regions without having to modify the CFG with the current
>> algorithm.
> Yes.
>>> If you want, have a look into some results I got with a pass extracting
>>> maximal non trivial regions that do not contain loops from libbz2:
>>> http://tobias.osaft.eu/llvm/region/bz2NoLoops/
>>> Interesting ones:
>>> regions_without_loops.BZ2_bzBuffToBuffCompress.dot.png
>>> has a lot of exit edges.
>> I think this example proves the strengths and weaknesses of both
>> approaches. Making that region into structured control flow would add a lot
>> of additional blocks. This will also happen after generating code
>> from the polyhedral model, so either way the cost is there if the optimization
>> is successful.
> Yes, but just in this case and not for regions where the model cannot be
> applied. If the regions pass is used for analysis purposes, nothing has
> to be touched.
>> The second  case is where the optimization fails (no profitable
>> transformation found) and the CFG can remain untouched. 
>> The third case is if one of those blocks contains something complicated.
>> I believe the current algorithm simply fails and cannot detect the region.
> Which algorithm? The one in Graphite? Or the region detection I wrote
> here? This is just plain region detection, that does not even look at
> the content but builds a region tree (program structure tree). It just
> detects every possible region.
> The selection would be a later pass.

My assumption was that there is a selection in there somewhere.
Do you plan to refine the regions in the selection phase in any way?

>> If the
>> CFG is modified this would allow an internal SESE-region to become a black box, and the
>> the outer regions could be optimized.
>This is an optimization, however I think it is orthogonal to the region
>detection problem. Say it works with any algorithm.

I believe that creating a black-box will map a lot more cleanly to an edge-based
region definition, since block-based may include multiple entry/exit sub-regions
that will not encapsulate control flow in a reasonable way.

>>> regions_without_loops.bzopen_or_bzdopen.dot.png
>>> the first region has two entry edges. One is the loop latch.
>>> (Keep in mind all regions have the same color, so if it seems there is
>>> an edge into a region, there are just two regions close by)
>>> Without a prepass that exposes the edges almost no region could be
>>> detected with the "standard" approach.
>> Indeed the CFG will have to be modified for these cases. I it seems to me that the trade-off
>> between the two approaches is that the algorithm that you currently have is a cheaper up
>> front, but may be less capable in some cases, while the "standard" algorithm will be more
>> expensive, but can handle problematic regions better. Would you agree?
> I agree that the algorithm I have is cheaper upfront, but I do not yet
> see a case where the algorithm is less capable. Would you mind to give
> an example or to highlight the relevant part of the discussion?

With the insertion of extra merge-blocks the code becomes more structured and the PST
can be refined further. A more fine-grained PST may allow more cases to be handled. 


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100120/6ce1a3c3/attachment.html>

More information about the llvm-dev mailing list