On 10/12/20 8:39 AM, Martin Liška wrote:
On 10/6/20 4:12 PM, Jakub Jelinek wrote:
On Tue, Oct 06, 2020 at 03:48:38PM +0200, Martin Liška wrote:
On 10/6/20 9:47 AM, Richard Biener wrote:
But is it really extensible with the current implementation?  I doubt so.

I must agree with the statement. So let's make the pass properly.
I would need a help with the algorithm where I'm planning to do the following
steps:

1) for each BB ending with a gcond, parse index variable and it's VR;
    I'll support:
    a) index == 123 ([123, 123])
    b) 1 <= index && index <= 9 ([1, 9])
    c) index == 123 || index == 12345 ([123, 123] [12345, 12345])
    d) index != 1 ([1, 1])
    e) index != 1 && index != 5 ([1, 1] [5, 5])

The fold_range_test created cases are essential to support, so
f) index - 123U < 456U ([123, 456+123])
g) (unsigned) index - 123U < 456U (ditto)
but the discovery should actually recurse on all of those forms, so it will
handle
(unsigned) index - 123U < 456U || (unsigned) index - 16384U <= 32711U
etc.
You can see what reassoc init_range_entry does and do something similar?

All right, I started to use init_range_entry in combination with linearize_expr_tree. One thing I have problem with is that linearize_expr_tree doesn't properly mark
all statements as visited for cases like:

  <bb 4> :
  index2.1_1 = (unsigned int) index2_16(D);
  _2 = index2.1_1 + 4294967196;
  _3 = _2 <= 100;
  _5 = index2.1_1 + 4294966996;
  _6 = _5 <= 33;
  _7 = _3 | _6;
  if (_7 != 0)
    goto <bb 5>; [INV]
  else
    goto <bb 6>; [INV]

As seen, all statements in this BB are used by the final _7 != 0 and it would
be handy for me to identify all statements that should be hoisted.

The ranger infrastructure includes definition chains for what can potentially have a range calculated on an outgoing edge.  It contains all the ssa-names defined in the block for which we have range-ops entries that allow us to potentially wind back thru a calculation.   ie, any name which is defined in the block whose value can be changed based on which edge is taken...


I created:

foo (int index)
{
 if (index - 123U < 456U || index - 16384U <= 32711U )
    foo (42);
}

the exports range list contains
 =========== BB 2 ============
index_9(D)      int VARYING
    <bb 2> :
    index.0_1 = (unsigned int) index_9(D);
    _2 = index.0_1 + 4294967173;
    _3 = _2 <= 455;
    _5 = index.0_1 + 4294950912;
    _6 = _5 <= 32711;
    _7 = _3 | _6;
    if (_7 != 0)
      goto <bb 3>; [INV]
    else
      goto <bb 4>; [INV]

2->3  (T) index.0_1 :   unsigned int [123, 578][16384, 49095]
2->3  (T) _7 :  _Bool [1, 1]
2->3  (T) index_9(D) :  int [123, 578][16384, 49095]
2->4  (F) index.0_1 :   unsigned int [0, 122][579, 16383][49096, +INF]
2->4  (F) _2 :  unsigned int [456, +INF]
2->4  (F) _3 :  _Bool [0, 0]
2->4  (F) _5 :  unsigned int [32712, +INF]
2->4  (F) _6 :  _Bool [0, 0]
2->4  (F) _7 :  _Bool [0, 0]
2->4  (F) index_9(D) :  int [-INF, 122][579, 16383][49096, +INF]

and importantly, the defchain structure which lists names which are used to define this name  looks like:

DUMPING GORI MAP
bb2    index.0_1 : index_9(D)
       _2 : index.0_1  index_9(D)
       _3 : index.0_1  _2  index_9(D)
       _5 : index.0_1  index_9(D)
       _6 : index.0_1  _5  index_9(D)
       _7 : index.0_1  _2  _3  _5  _6  index_9(D)
       exports: index.0_1  _2  _3  _5  _6  _7  index_9(D)


This indicates that if you are using _7 as the control name of the branch,

_7 : index.0_1  _2  _3  _5  _6  index_9(D)

is the list of names that _7 uses in its definition chain...and we can calculate ranges for.      index_9 is not defined in this BB, so it is considered an import.  you'd probably be looking for all the names in this list whose SSA_NAME_DEF_STMT is in this block.. That looks a lot like the list of statements you want to hoist.

Caveats are that
  1)  this is currently only used internally by the ranger, so there are some  minor warts that may currently limit its usefulness elsewhere   2) its is limited to only processing statements for which we have range-ops understanding.    which means we know how to calculate ranges for the statement.  Perhaps this is also not an issue since if there are statements we cant generate a range for, perhaps you dont care.

This might be more ionfo than  you need, but also

  3) before the enxt stage 1 I plan to rework the GORI component, and I plan to split this into additional "parts"  in particualr, this entire export list will still exist, but there will be 3 subcomponents which form it:        a)  control names :   These are booleans which contribute to the TRUE/FALSEness of the edge        b) direct exports  : These are ssanames which are directly affected by relations on the edge.. Ie, the edge gives them a range        c) calculable exports  : These are other ssa_names which can be calculated based on the direct exports. Ie, the direct export is used in calculating this value
for the above block,
  control names :  _7, _6 and _3
  direct exports : _5 and _2
  calculable exports : index.0_1 index_9(D)


I bring it up because as IM reworking those bits, we can take into account other requirements that might be needed that can make it useful other places. And by anaylzing the names that are common between any direct exports, you may find useful information.

Currently, the exports list is not exported from the ranger, nor is the gori map,  but that would be trivial to do.   You basically get a bitmap back..

The classes are not dependant on the ranger either, so you can roll your own if you wanted to experiment.  Since they are internal  they are currently located in  gimple-range-gori.cc.. its basically the gori_map class which tracks all this and uses the range_def_chain class to manage the definition chains.  I threw a number fo comments in there already.   Its lazily evaluated as queries are made.

If you think there is something useful, we can move those classes into the gimple-range-gori.h header file and adjust the APIs as needed.





Thoughts how can I achieve that?
Thanks,
Martin


Reply via email to