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

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


U.Mutlu wrote on 06/26/2018 02:53 AM:
> 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?

Ok, you mean this:
   if (v.size () != n)
     __builtin_abort ();

But the compliler cannot know that size() returns a vector-internal value,
ie. it could also be an external value, therefore it can't optimize it away, IMO.

>> 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