Giving hints to the compiler/optimizer (#pragma hint ...)

U.Mutlu um@mutluit.com
Tue Jun 26 00:53:00 GMT 2018


Martin Sebor wrote on 06/26/2018 01:44 AM:
> On 06/22/2018 12:32 AM, U.Mutlu wrote:
>> Hi,
>> it would be nice to have a mechanism to let the programmer give hints to
>> the compiler/optimizer.
>>
>> Example:
>>
>> for (size_t i = 1; i < vec.size(); ++i)
>>   ...
>>
>> If the size of vec cannot change while in this code block, then one
>> better would do this instead:
>>
>> {
>> const size_t vec_sz = vec.size();
>> for (size_t i = 1; i < vec_sz; ++i)
>>   ...
>> }
>>
>>
>> But, IMO it would be much better if one could just give a hint to the
>> compiler/optimizer instead:
>>
>> #pragma hint const vec.size()
>> for (size_t i = 1; i < vec.size(); ++i)
>>   ...
>>
>> Then the compiler/optimizer could cache the vec.size(), ie. fill a const
>> (register) variable just once and use that instead, like in the previous
>> manual version.
>> (The manual version has of course the disadvantage that user has to
>> define an additional variable and because of that, put the code in its
>> own scope...)
>>
>> So, passing such hints to the compiler/optimizer is IMO a good general way.
>> Would be nice if the gcc developers would implement such a mechanism.
>>
>> Technically: such a "#pragma hint ..." would apply just to the next line
>> of code, ie. automatically 'unhinting'.
>
> Unfortunately, const alone isn't always sufficient because programs
> can add constness to references and pointers and then cast it away,
> and because internally GCC doesn't rely on constness as much as it
> could.

Hmm. using dirty/illegal tricks?
More below.

> For instance in this example, f() can cast the constness of its
> argument away and change it.  If the reference is bound to a non-
> const object the program is valid:
>
>    void f (const std::vector<int>&);
>
>    void g (const std::vector<int> &v)
>    {
>      int n = v.size ();
>
>      f (v);
>
>      if (v.size () != n)
>        __builtin_abort ();
>    }
>
> When the reference passed to f() is bound to an object that's
> defined const GCC could assume that the call to f() doesn't
> change it and emit better code but, unfortunately, it does not.
> As a result, even though GCC could avoid the test below, it
> emits it.
>
>    void g (void)
>    {
>      const std::vector<int> v;
>
>      int n = v.size ();
>
>      f (v);
>
>      if (v.size () != n)
>        __builtin_abort ();
>    }
>
> GCC does eliminate such tests in the simple cases when v is
> a fundamental type like int, but not when it's a struct (even
> a trivial one containing just an int).

Hmm. if that is really true then I would be negatively surprised.
I just tested it with the the latest g++ (v9) and it gives a compile error
if one tries to modify the vector inside f().
And that is the expected behaviour, so I wonder which compiler & version you mean?


> But adding a #pragma isn't a solution to the problem.  Both C
> and to a slightly lesser extent also C++(*) have the necessary
> mechanisms to let compilers emit efficient code.  GCC just needs
> to take better advantage of them.

I'm now using this helper struct for/in for-loops:

struct forVars    // user can use this verbatim, or derive from this to add 
more vars...
   {
     const size_t sz;
     size_t i;
     constexpr forVars(const size_t Asz, const size_t Astart = 0) noexcept : 
sz(Asz), i(Astart) {}
     ~forVars() noexcept = default;
     forVars(const forVars&) noexcept = delete;
     forVars& operator=(const forVars&) noexcept = delete;
   };

and in application, for example here starting at i=1:

for (forVars S(vec.size(), 1); S.i < S.sz; ++S.i)   // S.sz is const
   ...


> Martin
>
> [*] C++ doesn't have the restrict keyword so it cannot express
> all the same constraints as C can.

The alternative in g++ is __restrict__ :
https://en.wikipedia.org/wiki/Restrict



More information about the Gcc-help mailing list