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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux