On Tue, 26 Nov 2024 at 16:15, Michael Matz <m...@suse.de> wrote:
>
> Hello,
>
> thanks for bearing with me :)
>
> On Tue, 26 Nov 2024, Jonathan Wakely wrote:
>
> > Being a member function makes no difference, but yes, I'm specifically
> > talking about the case of calling a constexpr function.
> >
> > constexpr int bla() { return 2; }
> > int foo (void) {
> >   const int x = bla();
> >   int y = bla();
> >   return x + y;
> > }
> >
> > At -O0 this is one instruction smaller due to the const. Adding const
> > to y removes another instruction.
>
> Hmm hmm.  But that is due to how x and y are used, not in how the RHS of
> their initializers is evaluated (in the above case both initializers are
> compile-time evaluated also at O0 in gcc).  I.e. on -O0 the same
> difference occurs for
>
>    const int x = 42;
>    int y = 42;
>    return x + y;
>
> ('y' but not 'x' will be stored and reloaded from stack on O0, that's the
> additional insn, which matches the abstract machine for non-const values).

Aha, thanks, that makes sense.

> But I was more interested in how the left hand side const qualifier
> changes semantics for the rhs side in initializers, not how it changes
> things in further uses of the initialized entity ...
>
> > Because in C++ when a const int is initialized by a constant
> > expression that const int becomes an integral constant:
>
> ... and I think that's the crucial thing I was missing: a const int X may
> or may not be an integral constant, depending on how it's initialized.
> So it's rather that the kind of the RHS initializer influences the kind of
> the LHS (as is proper), but only when that LHS is const.

Yes, that's a good way to look at it.

>  Okay, I can
> live with that :-)
>
> ... hmm ...
>
> But even then it only has observable effects when that X is used
> in contexts where an integral constant is required (which wasn't the case
> in the deque example, perhaps that confused me).

Ah, there's actually one other factor that affects it, which I forgot about.

Because C++98 doesn't have the 'constexpr' keyword, it means that the
bla() function can't be constexpr, so in C++98 we have:

#if __cplusplus >= 201103L
constexpr
#else
inline
#endif
int bla() { return 2; }

int foo (void) {
  const int x = bla();
  int y = bla();
  return x + y;
}

And now for -O0 it really does make a difference whether we have two
separate calls to bla() or if we call it once and store the result in
a local variable.

So the 'const int' doesn't really matter for any -On level, as you
say, but just avoiding two separate uses of the __deque_buf_size
function is worthwhile for -std=c++98 -O0

You were right to be triggered, I was wrong to say that making it a
constant expression mattered. For C++98 it's not a constant expression
(because the function is just 'inline' but not 'constexpr') and for
C++11 the fact it's 'constexpr' is enough for it to be constant-folded
whether the LHS is const or not.


> > In the bla() example above, the call bla() is a constant expression
> > when used to initialize a const int, so the compiler is required to
> > evaluate it at compile time.
>
> When used in contexts that doesn't require an integral constant I think a
> distinction between evaluating at compile time or at run time can't be
> observed.

Agreed.

> Obviously all required language rules, diagnostics and
> constraints have to be observed (and for that the compiler is required to
> look into the constexpr bla), but I think the ultimate
> formation of the constant '2' (in our bla() case) can be done arbitrarily
> complicated at run time, as long as '2' is the result and it's computed in
> constant time and space.  A long winded way of saying that I don't think
> you can observe a distiction between calling bla() as given or using a
> literal '2' in these contexts, no matter if x is const, constexpr, or
> nothing.  (let's ignore observation by assembly inspection :) )
>
> > In pure C++11 code I'd make it more explicit and write:
> >
> > constexpr int x = blah();
>
> I think I would have been less confused then, but still would have
> wondered, as 'x' wasn't used in a constexpr-requiring context.  I probably
> would have thought "ahh, someone wanted to make really sure that 'blah'
> will never be unnoticably rewritten to not be constant-evaluable anymore",
> not "meh, a optimization hint that shouldn't rightfully be there for
> a good compiler".
>
> Of course, with c++98 using 'const' here seems best now, so
> thanks for the gcc-help@ lesson!  ;-)

Reply via email to