Hi all,
Consider part of an example(figure 20) from doc P0190R4(
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0190r4.pdf) shown
below:

1.  void thread1 (void)
2.  {
3.    int * volatile p;
4.    p = rcu_dereference(gip);
5.    if (p)
6.    assert(*(p+p[0]) == 42);
7.  }
The .gimple code produced is :

1.  thread1 ()
2.  {
3.   atomic int * D.1992;
4.    int * volatile p;
5.  {
6.    atomic int * * __atomic_load_ptr;
7.   atomic int * __atomic_load_tmp;
8.    try
9.     {
10.        __atomic_load_ptr = &gip;
11.        _1 = __atomic_load_8 (__atomic_load_ptr, 1);
12.        _2 = (atomic int *) _1;
13.        __atomic_load_tmp = _2;
14.        D.1992 = __atomic_load_tmp;
15.     }
16.    finally
17.      {
18.        __atomic_load_tmp = {CLOBBER};
19.      }
20.  }
21.   p = D.1992;
22.   p.2_3 = p;
23.  if (p.2_3 != 0B) goto <D.1994>; else goto <D.1995>;
24.  <D.1994>:
25.   p.3_4 = p;
26.  p.4_5 = p;
27.   _6 = *p.4_5;
28.  _7 = (long unsigned int) _6;
29.  _8 = _7 * 4;
30.  _9 = p.3_4 + _8;
31.  _10 = *_9;
32.  _11 = _10 == 42;
33.  _12 = (int) _11;
34.  assert (_12);
35.  <D.1995>:
36. }

assert at line 34 in .gimple code still breaks the dependency given by the
user. I believe, there should be some ssa defined variable of p or p itself
in assert. This is happening when I am considering pointer as volatile
qualified. If I consider it as _Dependent_ptr qualified then it surely
produces the broken dependency code. Let me know, if I wrong somewhere.

-Akshat




On Wed, Jul 17, 2019 at 4:23 PM Akshat Garg <xks...@gmail.com> wrote:

> On Tue, Jul 2, 2019 at 9:06 PM Jason Merrill <ja...@redhat.com> wrote:
>
>> On Mon, Jul 1, 2019 at 8:59 PM Paul E. McKenney <paul...@linux.ibm.com>
>> wrote:
>> >
>> > On Tue, Jul 02, 2019 at 05:58:48AM +0530, Akshat Garg wrote:
>> > > On Tue, Jun 25, 2019 at 9:49 PM Akshat Garg <xks...@gmail.com> wrote:
>> > >
>> > > > On Tue, Jun 25, 2019 at 4:04 PM Ramana Radhakrishnan <
>> > > > ramana....@googlemail.com> wrote:
>> > > >
>> > > >> On Tue, Jun 25, 2019 at 11:03 AM Akshat Garg <xks...@gmail.com>
>> wrote:
>> > > >> >
>> > > >> > As we have some working front-end code for _Dependent_ptr, What
>> should
>> > > >> we do next? What I understand, we can start adding the library for
>> > > >> dependent_ptr and its functions for C corresponding to the ones we
>> created
>> > > >> as C++ template library. Then, after that, we can move on to
>> generating the
>> > > >> assembly code part.
>> > > >> >
>> > > >>
>> > > >>
>> > > >> I think the next step is figuring out how to model the Dependent
>> > > >> pointer information in the IR and figuring out what optimizations
>> to
>> > > >> allow or not with that information. At this point , I suspect we
>> need
>> > > >> a plan on record and have the conversation upstream on the lists.
>> > > >>
>> > > >> I think we need to put down a plan on record.
>> > > >>
>> > > >> Ramana
>> > > >
>> > > > [CCing gcc mailing list]
>> > > >
>> > > > So, shall I start looking over the pointer optimizations only and
>> see what
>> > > > information we may be needed on the same examples in the IR itself?
>> > > >
>> > > > - Akshat
>> > > >
>> > > I have coded an example where equality comparison kills dependency
>> from the
>> > > document P0190R4 as shown below :
>> > >
>> > > 1. struct rcutest rt = {1, 2, 3};
>> > > 2. void thread0 ()
>> > > 3. {
>> > > 4.     rt.a = -42;
>> > > 5.     rt.b = -43;
>> > > 6.     rt.c = -44;
>> > > 7.     rcu_assign_pointer(gp, &rt);
>> > > 8. }
>> > > 9.
>> > > 10. void thread1 ()
>> > > 11. {
>> > > 12.    int i = -1;
>> > > 13.    int j = -1;
>> > > 14.    _Dependent_ptr struct rcutest *p;
>> > > 15.
>> > > 16.    p = rcu_dereference(gp);
>> > > 17.    j = p->a;
>> > > 18.   if (p == &rt)
>> > > 19.        i = p->b;  /*Dependency breaking point*/
>> > > 20.   else if(p)
>> > > 21.       i = p->c;
>> > > 22.   assert(i<0);
>> > > 23.   assert(j<0);
>> > > 24. }
>> > > The gimple unoptimized code produced for lines 17-24 is shown below
>> > >
>> > > 1. if (p_16 == &rt)
>> > > 2.     goto <bb 3>; [INV]
>> > > 3.   else
>> > > 4.    goto <bb 4>; [INV]
>> > > 5.
>> > > 6.  <bb 3> :
>> > > 7.  i_19 = p_16->b;
>> > > 8.  goto <bb 6>; [INV]
>> > > 9.
>> > > 10.  <bb 4> :
>> > > 11.  if (p_16 != 0B)
>> > > 12.    goto <bb 5>; [INV]
>> > > 13.  else
>> > > 14.    goto <bb 6>; [INV]
>> > > 15.
>> > > 16.  <bb 5> :
>> > > 17.  i_18 = p_16->c;
>> > > 18.
>> > > 19.  <bb 6> :
>> > > 20.  # i_7 = PHI <i_19(3), i_8(4), i_18(5)>
>> > > 21.  _3 = i_7 < 0;
>> > > 22.  _4 = (int) _3;
>> > > 23.  assert (_4);
>> > > 24.  _5 = j_17 < 0;
>> > > 25.  _6 = (int) _5;
>> > > 26.  assert (_6);
>> > > 27.  return;
>> > >
>> > > The optimized code after -O1 is applied for the same lines is hown
>> below :
>> > >
>> > > 1. if (_2 == &rt)
>> > > 2.    goto <bb 3>; [30.00%]
>> > > 3. else
>> > > 4.    goto <bb 4>; [70.00%]
>> > > 5.
>> > > 6.  <bb 3> [local count: 322122547]:
>> > > 7.   i_12 = rt.b;
>> > > 8.   goto <bb 6>; [100.00%]
>> > > 9.
>> > > 10.  <bb 4> [local count: 751619277]:
>> > > 11.   if (_1 != 0)
>> > > 12.   goto <bb 5>; [50.00%]
>> > > 13.   else
>> > > 14.    goto <bb 6>; [50.00%]
>> > > 15.
>> > > 16.  <bb 5> [local count: 375809638]:
>> > > 17.   i_11 = MEM[(dependent_ptr struct rcutest *)_2].c;
>> > > 18.
>> > > 19.   <bb 6> [local count: 1073741824]:
>> > > 20.  # i_7 = PHI <i_12(3), i_11(5), -1(4)>
>> > > 21.   _3 = i_7 < 0;
>> > > 22.   _4 = (int) _3;
>> > > 23.   assert (_4);
>> > > 24.  _5 = j_10 < 0;
>> > > 25.  _6 = (int) _5;
>> > > 26.   assert (_6);
>> > > 27.   return;
>> >
>> > Good show on tracing this through!
>> >
>> > > Statement 19 in the program gets converted from  i_19 = p_16->b; in
>> line 7
>> > > in unoptimized code to i_12 = rt.b; in line 7 in optimized code which
>> > > breaks the dependency chain. We need to figure out the pass that does
>> that
>> > > and put some handling code in there for the _dependent_ptr qualified
>> > > pointers. Passing simply -fipa-pure-const, -fguess-branch-probability
>> or
>> > > any other option alone does not produce the optimized code that
>> breaks the
>> > > dependency. But applying -O1, i.e., allowing all the optimizations
>> does so.
>> > > As passes are applied in a certain order, we need to figure out up to
>> what
>> > > passes, the code remains same and after what pass the dependency does
>> not
>> > > holds. So, we need to check the translated code after every pass.
>> > >
>> > > Does this sounds like a workable plan for ? Let me know your
>> thoughts. If
>> > > this sounds good then, we can do this for all the optimizations that
>> may
>> > > kill the dependencies at somepoint.
>> >
>> > I don't know of a better plan.
>> >
>> > My usual question...  Is there some way to script the checking of the
>> > translated code at the end of each pass?
>>
>> The usual way to check the output of an optimization pass is by
>> dumping the intermediate code at that point and matching the dump
>> against a regexp, as in the tree-ssa directories in the testsuite.
>> -fdump-tree-all will dump after all the gimple optimization passes,
>> and you can look through them until you find the breakage.
>>
>> Jason
>>
> Thanks Jason for the advice, I followed it.
>
> I coded an example shown in figure 26 from here (
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0190r4.pdf).
> The example:
> https://github.com/AKG001/test/blob/master/dependency_breaking.c
> The .objsz1 code:
> https://github.com/AKG001/test/blob/master/dependency_breaking.c.027t.objsz1
> The .ccp1 code:
> https://github.com/AKG001/test/blob/master/dependency_breaking.c.028t.ccp1
> The .sra code:
> https://github.com/AKG001/test/blob/master/dependency_breaking.c.114t.sra
> The .dom2 code:
> https://github.com/AKG001/test/blob/master/dependency_breaking.c.116t.dom2
>
> Comparing the .objsz1 and .ccp1 file, the "struct p" gets removed after
> constant copy propagation (ccp) pass(
> https://github.com/gcc-mirror/gcc/blob/master/gcc/passes.def#L77). In
> .objsz1 file at line 53, the dependencies start with
> p_16 = _14;
> .......
> i_19 = p_16->b;
> ......
> as user specified and after that all the references are made through
> struct p or its variants. But in .ccp1 file at line 41, the "struct p" is
> replaced with variable _2, now, variable _2 starts the dependencies as we
> can see.
> _2 = (atomic struct rcutest *) _1;
> ...........
> i_19 = MEM[(struct rcutest *)_2].b;
> ..........
> I don't know whether it is okay to say at this point, the dependencies are
> still maintained or not. Or we have to pass the dependent pointer
> qualification to new variables that replaces them. Hoping someone could
> clarify.
>
> Also, In .sra file at line 43 in thread1(), the statement is:
>     i_12 = MEM[(struct rcutest *)_2].b;
> In .dom2 file at line 61, the above statement gets converted to:
>     i_12 = rt.b;
> So, I believe that sure does breaks the dependency specified by the user.
> For this, we need to do some modifications in tree-ssa-dom.c file. Hope
> this makes sense.
>
> Thanks,
> Akshat
>

Reply via email to