Thread overview
Re: pragma attribute syntax
Jun 04, 2012
Iain Buclaw
Jun 04, 2012
Artur Skawina
Jun 04, 2012
Iain Buclaw
Jun 04, 2012
Artur Skawina
Jun 06, 2012
Iain Buclaw
Jun 06, 2012
Artur Skawina
Jun 06, 2012
Artur Skawina
Jun 06, 2012
Iain Buclaw
Jun 06, 2012
Artur Skawina
Jun 06, 2012
Iain Buclaw
June 04, 2012
On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
> Would it be possible to allow give the gcc attribute as a string?
> So that it would be possible to express 'pragma(attribute, align(8))' etc
>
> Because right now you can not do this:
>
>   pragma(attribute, pure)
>   pragma(attribute, const)
>
> And I just realized that i need these attributes. :)
>
> Something like
>
>   pragma(attribute, gcc("pure"))
>
> maybe?
>
> artur


You can use underscores as alternate syntax:

pragma(attribute, __pure__)
pragma(attribute, __const__)


Regards
-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
June 04, 2012
On 06/04/12 21:48, Iain Buclaw wrote:
> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>> Would it be possible to allow give the gcc attribute as a string?
>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>
>> Because right now you can not do this:
>>
>>   pragma(attribute, pure)
>>   pragma(attribute, const)

> You can use underscores as alternate syntax:
> 
> pragma(attribute, __pure__)
> pragma(attribute, __const__)
> 

Works, thank you.

And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.

Thanks,

artur
June 04, 2012
On 4 June 2012 21:53, Artur Skawina <art.08.09@gmail.com> wrote:
> On 06/04/12 21:48, Iain Buclaw wrote:
>> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>>> Would it be possible to allow give the gcc attribute as a string?
>>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>>
>>> Because right now you can not do this:
>>>
>>>   pragma(attribute, pure)
>>>   pragma(attribute, const)
>
>> You can use underscores as alternate syntax:
>>
>> pragma(attribute, __pure__)
>> pragma(attribute, __const__)
>>
>
> Works, thank you.
>
> And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.
>

To get the equivalent of "pure", you need to mark the function as pure nothrow in D.  There is no equivalent of "const" yet, but we can discuss ways to go about defining that. :)



-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
June 04, 2012
On 06/04/12 23:49, Iain Buclaw wrote:
> On 4 June 2012 21:53, Artur Skawina <art.08.09@gmail.com> wrote:
>> On 06/04/12 21:48, Iain Buclaw wrote:
>>> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>>>> Would it be possible to allow give the gcc attribute as a string?
>>>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>>>
>>>> Because right now you can not do this:
>>>>
>>>>   pragma(attribute, pure)
>>>>   pragma(attribute, const)
>>
>>> You can use underscores as alternate syntax:
>>>
>>> pragma(attribute, __pure__)
>>> pragma(attribute, __const__)
>>>
>>
>> Works, thank you.
>>
>> And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.

I should probably add that, unlike the D "pure" attribute, GCC will assume that you know what you're doing, so it's possible to wrongly tag a function as pure using this pragma.

> To get the equivalent of "pure", you need to mark the function as pure nothrow in D.  There is no equivalent of "const" yet, but we can discuss ways to go about defining that. :)

No, "pure nothrow" is unfortunately not enough; the only case where it works as one might expect if the function takes any pointer/ref arguments, is when these args are immutable.

D's pure functions that do not have pointer/ref inputs should map pretty well do GCC "const", but from the little testing I did today, it seems this already works reasonably well, so the "const" attribute may not be needed, the compiler manages to eliminate redundant calls already.

The problematic case is something like this:

   struct S {
      int a,b;
      int[64] c;
      pragma(attribute, noinline, __pure__) bool f() const pure nothrow {
         return a||b;
      }
   }

Without the pragma the compiler will call f() twice when evaluating

   S s; auto r = s.f()+s.f(); /*...use r...*/

I'm told this is by design, which, if true, would prevent a lot of valid optimizations.

The (long) story: http://d.puremagic.com/issues/show_bug.cgi?id=8185

The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.

artur
June 06, 2012
On 5 June 2012 00:24, Artur Skawina <art.08.09@gmail.com> wrote:
> On 06/04/12 23:49, Iain Buclaw wrote:
>> On 4 June 2012 21:53, Artur Skawina <art.08.09@gmail.com> wrote:
>>> On 06/04/12 21:48, Iain Buclaw wrote:
>>>> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>>>>> Would it be possible to allow give the gcc attribute as a string?
>>>>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>>>>
>>>>> Because right now you can not do this:
>>>>>
>>>>>   pragma(attribute, pure)
>>>>>   pragma(attribute, const)
>>>
>>>> You can use underscores as alternate syntax:
>>>>
>>>> pragma(attribute, __pure__)
>>>> pragma(attribute, __const__)
>>>>
>>>
>>> Works, thank you.
>>>
>>> And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.
>
> I should probably add that, unlike the D "pure" attribute, GCC will assume that you know what you're doing, so it's possible to wrongly tag a function as pure using this pragma.
>
>> To get the equivalent of "pure", you need to mark the function as pure nothrow in D.  There is no equivalent of "const" yet, but we can discuss ways to go about defining that. :)
>
> No, "pure nothrow" is unfortunately not enough; the only case where it works as one might expect if the function takes any pointer/ref arguments, is when these args are immutable.
>
> D's pure functions that do not have pointer/ref inputs should map pretty well do GCC "const", but from the little testing I did today, it seems this already works reasonably well, so the "const" attribute may not be needed, the compiler manages to eliminate redundant calls already.
>

With help of the hints passed to the backend, it should be able to determine that functions  a) with no side effects and b) who's return value is ignored - should safely discarded.


> The problematic case is something like this:
>
>   struct S {
>      int a,b;
>      int[64] c;
>      pragma(attribute, noinline, __pure__) bool f() const pure nothrow {
>         return a||b;
>      }
>   }
>
> Without the pragma the compiler will call f() twice when evaluating
>
>   S s; auto r = s.f()+s.f(); /*...use r...*/
>
> I'm told this is by design, which, if true, would prevent a lot of valid optimizations.
>
> The (long) story: http://d.puremagic.com/issues/show_bug.cgi?id=8185
>

I've just added a change which should give it a better mapping from keyword to gcc attribute equivalents.

D keyword -> D frontend representation (depends on function contents however) -> gcc matched attribute

pure                -> PUREweak   -> no vops
pure const       -> PUREconst   -> const
pure nothrow    -> PUREstrong  -> pure


This means that any pure functions should be guaranteed to be
evaluated once in the use case s.f()+s.f(); - will have a play around
with it though to check for safety / correctness.

> The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.
>

This is an optimisation I pulled from ISO C++ into gdc - that all member functions defined within the body of a class (and in D, this includes structs too) are to be marked inline.

However, this does not currently work with members outside the current module we are compiling for.  So the next step is to get cross-module inlining working.


Regards
-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
June 06, 2012
On 06/06/12 12:14, Iain Buclaw wrote:
> On 5 June 2012 00:24, Artur Skawina <art.08.09@gmail.com> wrote:
>> On 06/04/12 23:49, Iain Buclaw wrote:
>>> On 4 June 2012 21:53, Artur Skawina <art.08.09@gmail.com> wrote:
>>>> On 06/04/12 21:48, Iain Buclaw wrote:
>>>>> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>>>>>> Would it be possible to allow give the gcc attribute as a string?
>>>>>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>>>>>
>>>>>> Because right now you can not do this:
>>>>>>
>>>>>>   pragma(attribute, pure)
>>>>>>   pragma(attribute, const)
>>>>
>>>>> You can use underscores as alternate syntax:
>>>>>
>>>>> pragma(attribute, __pure__)
>>>>> pragma(attribute, __const__)
>>>>>
>>>>
>>>> Works, thank you.
>>>>
>>>> And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.
>>
>> I should probably add that, unlike the D "pure" attribute, GCC will assume that you know what you're doing, so it's possible to wrongly tag a function as pure using this pragma.
>>
>>> To get the equivalent of "pure", you need to mark the function as pure nothrow in D.  There is no equivalent of "const" yet, but we can discuss ways to go about defining that. :)
>>
>> No, "pure nothrow" is unfortunately not enough; the only case where it works as one might expect if the function takes any pointer/ref arguments, is when these args are immutable.
>>
>> D's pure functions that do not have pointer/ref inputs should map pretty well do GCC "const", but from the little testing I did today, it seems this already works reasonably well, so the "const" attribute may not be needed, the compiler manages to eliminate redundant calls already.
>>
> 
> With help of the hints passed to the backend, it should be able to determine that functions  a) with no side effects and b) who's return value is ignored - should safely discarded.

It should also improve CSE, hoisting out loop invariants etc.

>> The problematic case is something like this:
>>
>>   struct S {
>>      int a,b;
>>      int[64] c;
>>      pragma(attribute, noinline, __pure__) bool f() const pure nothrow {
>>         return a||b;
>>      }
>>   }
>>
>> Without the pragma the compiler will call f() twice when evaluating
>>
>>   S s; auto r = s.f()+s.f(); /*...use r...*/
>>
>> I'm told this is by design, which, if true, would prevent a lot of valid optimizations.
>>
>> The (long) story: http://d.puremagic.com/issues/show_bug.cgi?id=8185
>>
> 
> I've just added a change which should give it a better mapping from keyword to gcc attribute equivalents.
> 
> D keyword -> D frontend representation (depends on function contents however) -> gcc matched attribute
> 
> pure                -> PUREweak   -> no vops
> pure const       -> PUREconst   -> const
> pure nothrow    -> PUREstrong  -> pure
> 
> 
> This means that any pure functions should be guaranteed to be
> evaluated once in the use case s.f()+s.f(); - will have a play around
> with it though to check for safety / correctness.

Hmm, is there a way to see the purity level determined by the frontend, w/o doing any compiler modifications?


>> The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.
> 
> This is an optimisation I pulled from ISO C++ into gdc - that all member functions defined within the body of a class (and in D, this includes structs too) are to be marked inline.

I know. What I'm saying is that omitting the "noinline" attribute causes the "pure" function, like s.f() above, to be called twice. Add the "noinline" back, with no other changes - and it gets called only once. This happens both for "strongly pure" D functions and gcc-pure-tagged functions. It seems that either the optimizer (CSE?) gets confused by the inlining or it treats the case when the function body is available differently.

> However, this does not currently work with members outside the current module we are compiling for.  So the next step is to get cross-module inlining working.

That would be great, then i could stop writing code like
  int f(INLINE=this)(...) {...}
:)

artur
June 06, 2012
On 06/06/12 17:03, Artur Skawina wrote:
> I know. What I'm saying is that omitting the "noinline" attribute causes the "pure" function, like s.f() above, to be called twice. Add the "noinline" back, with no other changes - and it gets called only once.

What i mean by "called" in this case is of course that the code runs twice when inlined. I was testing with impure bodies, did another test right now, and it seems that it may only happen in that case. But it's hard to tell, as the compiler manages to optimize the really pure inlined parts well. It's just surprising that program behavior changes depending on the availability of function bodies. If this only happens for "illegal" code it's of course not a problem. It does mean that things like debug output change based on inlining decisions though.

artur
June 06, 2012
On 6 June 2012 16:03, Artur Skawina <art.08.09@gmail.com> wrote:
> On 06/06/12 12:14, Iain Buclaw wrote:
>> On 5 June 2012 00:24, Artur Skawina <art.08.09@gmail.com> wrote:
>>> On 06/04/12 23:49, Iain Buclaw wrote:
>>>> On 4 June 2012 21:53, Artur Skawina <art.08.09@gmail.com> wrote:
>>>>> On 06/04/12 21:48, Iain Buclaw wrote:
>>>>>> On 4 June 2012 19:49, Artur Skawina <art.08.09@gmail.com> wrote:
>>>>>>> Would it be possible to allow give the gcc attribute as a string?
>>>>>>> So that it would be possible to express 'pragma(attribute, align(8))' etc
>>>>>>>
>>>>>>> Because right now you can not do this:
>>>>>>>
>>>>>>>   pragma(attribute, pure)
>>>>>>>   pragma(attribute, const)
>>>>>
>>>>>> You can use underscores as alternate syntax:
>>>>>>
>>>>>> pragma(attribute, __pure__)
>>>>>> pragma(attribute, __const__)
>>>>>>
>>>>>
>>>>> Works, thank you.
>>>>>
>>>>> And it even does the right thing - makes the compiler correctly optimize away calls to pure functions that take const ref/pointer args, which D's "pure" does not handle yet.
>>>
>>> I should probably add that, unlike the D "pure" attribute, GCC will assume that you know what you're doing, so it's possible to wrongly tag a function as pure using this pragma.
>>>
>>>> To get the equivalent of "pure", you need to mark the function as pure nothrow in D.  There is no equivalent of "const" yet, but we can discuss ways to go about defining that. :)
>>>
>>> No, "pure nothrow" is unfortunately not enough; the only case where it works as one might expect if the function takes any pointer/ref arguments, is when these args are immutable.
>>>
>>> D's pure functions that do not have pointer/ref inputs should map pretty well do GCC "const", but from the little testing I did today, it seems this already works reasonably well, so the "const" attribute may not be needed, the compiler manages to eliminate redundant calls already.
>>>
>>
>> With help of the hints passed to the backend, it should be able to determine that functions  a) with no side effects and b) who's return value is ignored - should safely discarded.
>
> It should also improve CSE, hoisting out loop invariants etc.
>
>>> The problematic case is something like this:
>>>
>>>   struct S {
>>>      int a,b;
>>>      int[64] c;
>>>      pragma(attribute, noinline, __pure__) bool f() const pure nothrow {
>>>         return a||b;
>>>      }
>>>   }
>>>
>>> Without the pragma the compiler will call f() twice when evaluating
>>>
>>>   S s; auto r = s.f()+s.f(); /*...use r...*/
>>>
>>> I'm told this is by design, which, if true, would prevent a lot of valid optimizations.
>>>
>>> The (long) story: http://d.puremagic.com/issues/show_bug.cgi?id=8185
>>>
>>
>> I've just added a change which should give it a better mapping from keyword to gcc attribute equivalents.
>>
>> D keyword -> D frontend representation (depends on function contents however) -> gcc matched attribute
>>
>> pure                -> PUREweak   -> no vops
>> pure const       -> PUREconst   -> const
>> pure nothrow    -> PUREstrong  -> pure
>>
>>
>> This means that any pure functions should be guaranteed to be
>> evaluated once in the use case s.f()+s.f(); - will have a play around
>> with it though to check for safety / correctness.
>
> Hmm, is there a way to see the purity level determined by the frontend, w/o doing any compiler modifications?
>
>

Unfortunately not.  I can tell you that the modification would be to
d-decls.cc:(FuncDeclaration::toSymbol) - adding a fprintf(stderr) with
the purity value - hint, it's an enum.


>>> The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.
>>
>> This is an optimisation I pulled from ISO C++ into gdc - that all member functions defined within the body of a class (and in D, this includes structs too) are to be marked inline.
>
> I know. What I'm saying is that omitting the "noinline" attribute causes the "pure" function, like s.f() above, to be called twice. Add the "noinline" back, with no other changes - and it gets called only once. This happens both for "strongly pure" D functions and gcc-pure-tagged functions. It seems that either the optimizer (CSE?) gets confused by the inlining or it treats the case when the function body is available differently.
>

Could you provide some examples?

I can only think of this occurring for functions that have arbituary side effects.  ie: if you insert debug printf statements into pure functions.


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
June 06, 2012
On 06/06/12 18:02, Iain Buclaw wrote:
> On 6 June 2012 16:03, Artur Skawina <art.08.09@gmail.com> wrote:
>> Hmm, is there a way to see the purity level determined by the frontend, w/o doing any compiler modifications?
> 
> Unfortunately not.  I can tell you that the modification would be to
> d-decls.cc:(FuncDeclaration::toSymbol) - adding a fprintf(stderr) with
> the purity value - hint, it's an enum.

Thanks. So far, i've been trying not to look inside the compiler at all. ;)


>>>> The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.
>>>
>>> This is an optimisation I pulled from ISO C++ into gdc - that all member functions defined within the body of a class (and in D, this includes structs too) are to be marked inline.
>>
>> I know. What I'm saying is that omitting the "noinline" attribute causes the "pure" function, like s.f() above, to be called twice. Add the "noinline" back, with no other changes - and it gets called only once. This happens both for "strongly pure" D functions and gcc-pure-tagged functions. It seems that either the optimizer (CSE?) gets confused by the inlining or it treats the case when the function body is available differently.
>>
> 
> Could you provide some examples?
> 
> I can only think of this occurring for functions that have arbituary side effects.  ie: if you insert debug printf statements into pure functions.

Yes, this was exactly what i was testing with, so that i wouldn't have to look at the generated code each time.

Doing things like logging every call to a function, while still wanting
it to be treated as pure for optimization purposes can sometimes make
sense; it was surprising that program behavior (ie whether the impure
logging functions were called or not) depended on inlining decisions.
I can't right now think of a test case that does not embed non-pure code
inside pure; the truly pure portions could be optimized _after_ the
inlining happens, so it is hard to tell if the pure-based CSE worked
or not; since in my tests the impure portions remained, I was assuming
it did not.

If I wanted to try your changes I would need to use the gcc4.8 based tree, right?

artur
June 06, 2012
On 6 June 2012 17:43, Artur Skawina <art.08.09@gmail.com> wrote:
> On 06/06/12 18:02, Iain Buclaw wrote:
>> On 6 June 2012 16:03, Artur Skawina <art.08.09@gmail.com> wrote:
>>> Hmm, is there a way to see the purity level determined by the frontend, w/o doing any compiler modifications?
>>
>> Unfortunately not.  I can tell you that the modification would be to
>> d-decls.cc:(FuncDeclaration::toSymbol) - adding a fprintf(stderr) with
>> the purity value - hint, it's an enum.
>
> Thanks. So far, i've been trying not to look inside the compiler at all. ;)
>
>
>>>>> The "noinline", BTW, is for some reason required in both the D-pure and GCC-pure cases for the optimization to work.
>>>>
>>>> This is an optimisation I pulled from ISO C++ into gdc - that all member functions defined within the body of a class (and in D, this includes structs too) are to be marked inline.
>>>
>>> I know. What I'm saying is that omitting the "noinline" attribute causes the "pure" function, like s.f() above, to be called twice. Add the "noinline" back, with no other changes - and it gets called only once. This happens both for "strongly pure" D functions and gcc-pure-tagged functions. It seems that either the optimizer (CSE?) gets confused by the inlining or it treats the case when the function body is available differently.
>>>
>>
>> Could you provide some examples?
>>
>> I can only think of this occurring for functions that have arbituary side effects.  ie: if you insert debug printf statements into pure functions.
>
> Yes, this was exactly what i was testing with, so that i wouldn't have to look at the generated code each time.
>
> Doing things like logging every call to a function, while still wanting
> it to be treated as pure for optimization purposes can sometimes make
> sense; it was surprising that program behavior (ie whether the impure
> logging functions were called or not) depended on inlining decisions.
> I can't right now think of a test case that does not embed non-pure code
> inside pure; the truly pure portions could be optimized _after_ the
> inlining happens, so it is hard to tell if the pure-based CSE worked
> or not; since in my tests the impure portions remained, I was assuming
> it did not.
>
> If I wanted to try your changes I would need to use the gcc4.8 based tree, right?
>
> artur

Yeah, I go off snapshots rather than getting the source off svn or git
(takes far too long).

ie: ftp://ftp.mirrorservice.org/sites/sourceware.org/pub/gcc/snapshots/LATEST-4.8/


-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';