public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug web/96996] New: Missed optimzation for constant members of non-constant objects
@ 2020-09-09 12:12 matthijs at stdin dot nl
  2020-09-09 13:05 ` [Bug c++/96996] " redi at gcc dot gnu.org
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: matthijs at stdin dot nl @ 2020-09-09 12:12 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

            Bug ID: 96996
           Summary: Missed optimzation for constant members of
                    non-constant objects
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: web
          Assignee: unassigned at gcc dot gnu.org
          Reporter: matthijs at stdin dot nl
  Target Milestone: ---

When a global class instance is const and initialized using constant arguments
to a constexpr constructor, any member references are optimized away (using the
constant value rather than a lookup). However, when the object is *not* const,
but does have const members, such optimization does not happen.

$ cat test2.cpp; gcc -O3 -S -Wall -Wextra -fdump-tree-optimized=/dev/stdout
test2.cpp
constexpr int v = 1;

struct Test {
  constexpr Test(int v, const int *p) : v(v), p(p) { }
  int const v;
  const int * const p;
};

const Test constant_test(v, &v);
Test non_constant_test(v, &v);

int constant_ref() {
    return constant_test.v + *constant_test.p;
}

int non_constant_ref() {
    return non_constant_test.v + *non_constant_test.p;
}

;; Function constant_ref (_Z12constant_refv, funcdef_no=3, decl_uid=2360,
cgraph_uid=4, symbol_order=6)

constant_ref ()
{
  <bb 2> [local count: 1073741824]:
  return 2;

}



;; Function non_constant_ref (_Z16non_constant_refv, funcdef_no=4,
decl_uid=2362, cgraph_uid=5, symbol_order=7)

non_constant_ref ()
{
  int _1;
  const int * _2;
  int _3;
  int _5;

  <bb 2> [local count: 1073741824]:
  _1 = non_constant_test.v;
  _2 = non_constant_test.p;
  _3 = *_2;
  _5 = _1 + _3;
  return _5;

}


In the constant_f() case, the values are completely optimized and the return
value is determined at compiletime. In the non_constant_f() case, the values
are retrieved at runtime.

However, AFAICS there should be no way that these values can be modified at
runtime, even when the object itself is not const, since the members are const.
So AFAICS, it shoul be possible to evaluation non_constant_f() at compiletime
as well.

Looking at the C++ spec (I'm quoting from the C++14 draft here), this would
seem to be possible as well.

[basic.type.qualifier] says "A const object is an object of type const T or a
non-mutable subobject of such an object."

If I read [intro.object] correctly, subobjects (such as non-static member
variables) are also objects, so a non-static member variable declared const
would be a "const object".

[dcl.type.cv] says "Except that any class member declared mutable (7.1.1) can
be modified, any attempt to modify a const object during its lifetime (3.8)
results in undefined behavior."

So, one can assume that the const member variable is not modified, because if
it was, that would be undefined behavior.

There is still the caveat of "during its lifetime", IOW, what if you would
destroy the object and create a new one it is place. However, see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80794#c5 for a discussion of this
case. In short, replacing non_constant_test with a new object is possible, but
only when it "does not contain any non-static data member whose type is
const-qualified or a reference type", which does not hold for this object. This
sounds like this provision was made for pretty much this case, even.

I suspect that reason that it works for the const object now, is because of the
rules for constant expressions. [expr.const] defines rules for constant
exprssions and seems to only allow using(through lvalue-to-rvalue conversion)
objects of non-integral types when they are constexpr. I can imagine that gcc
derives that constant_test might be effectively constexpr, making any
expressions that use it also effectively constant expressions. This same
derivation probably does not happen for subobjects (I guess "constexpr" is not
actually a concept that applies to subobjects at all). However, I think this
does not mean this optimization would be invalid, just that it would happen on
different grounds than the current optimization.


This issue is also related to
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80794, but AFAICS that is more
about partial compilation and making assumptions about what an external
function can or cannot do, while this issue is primarily about link-time
(though maybe they are more similar internally, I don't exactly know).

I believe that this optimization would be quite significant to make, since it
allows better abstraction and separation of concerns (i.e. it allows writing a
class to be generic, using constructor-supplied parameters, but if you pass
constants for these parameters and have just a single instance of such a class,
or when methods are inlined or constprop'd, there could be zero runtime
overhead for this extra abstraction). Currently, I believe that you either have
to accept runtime overhead, or resort to using template argument for such
parameters (which significantly complicates everything, and takes away freedom
from the compiler to decide when to resolve things at compiletime or runtime).

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
@ 2020-09-09 13:05 ` redi at gcc dot gnu.org
  2020-09-09 13:10 ` matthijs at stdin dot nl
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: redi at gcc dot gnu.org @ 2020-09-09 13:05 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|web                         |c++
           Keywords|                            |missed-optimization

--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Matthijs Kooijman from comment #0)
> There is still the caveat of "during its lifetime", IOW, what if you would
> destroy the object and create a new one it is place. However, see
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80794#c5 for a discussion of
> this case. In short, replacing non_constant_test with a new object is
> possible, but only when it "does not contain any non-static data member
> whose type is const-qualified or a reference type", which does not hold for
> this object.

That's not quite accurate. Replacing non_constant_test with a new object is
possible, and allowed. But the name "non_constant_test" cannot be used to refer
to the new object, so any calls to non_constant_ref() after the object was
replaced would have undefined behaviour. Which means the compiler can assume
there are no such calls.

I'm not saying the optimization would be invalid, just clarifying what the
related discussion says.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
  2020-09-09 13:05 ` [Bug c++/96996] " redi at gcc dot gnu.org
@ 2020-09-09 13:10 ` matthijs at stdin dot nl
  2020-09-09 14:18 ` redi at gcc dot gnu.org
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: matthijs at stdin dot nl @ 2020-09-09 13:10 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

--- Comment #2 from Matthijs Kooijman <matthijs at stdin dot nl> ---
> Replacing non_constant_test with a new object is possible, and allowed. But the name "non_constant_test" cannot be used to refer to the new object, so any calls to non_constant_ref() after the object was replaced would have undefined behaviour. Which means the compiler can assume there are no such calls.

Thanks for clarifying. But then I could reason that *if* "non_constant_test" is
replaced, then accessing it through the old name is undefined behavior, so that
would make any value for the constant member variables (such as the original
values before replacement) acceptable, right? Hence that does not conflict with
applying this optimzation, I'd think.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
  2020-09-09 13:05 ` [Bug c++/96996] " redi at gcc dot gnu.org
  2020-09-09 13:10 ` matthijs at stdin dot nl
@ 2020-09-09 14:18 ` redi at gcc dot gnu.org
  2020-09-10  7:23 ` rguenth at gcc dot gnu.org
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: redi at gcc dot gnu.org @ 2020-09-09 14:18 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Yes, that's what I said:

> I'm not saying the optimization would be invalid

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
                   ` (2 preceding siblings ...)
  2020-09-09 14:18 ` redi at gcc dot gnu.org
@ 2020-09-10  7:23 ` rguenth at gcc dot gnu.org
  2020-09-10  7:43 ` matthijs at stdin dot nl
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: rguenth at gcc dot gnu.org @ 2020-09-10  7:23 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> ---
But isn't there const_cast<> to change the value of p?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
                   ` (3 preceding siblings ...)
  2020-09-10  7:23 ` rguenth at gcc dot gnu.org
@ 2020-09-10  7:43 ` matthijs at stdin dot nl
  2020-09-10  8:46 ` redi at gcc dot gnu.org
  2020-09-14 15:18 ` [Bug tree-optimization/96996] " msebor at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: matthijs at stdin dot nl @ 2020-09-10  7:43 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

--- Comment #5 from Matthijs Kooijman <matthijs at stdin dot nl> ---
> But isn't there const_cast<> to change the value of p?

Yes, that makes it possible to write to a const object, but actually doing so
is undefined behavior (see [dcl.type.cv] I quoted above).

The spec even makes this explicit about const_cast, [expr.const.cast] says:

> [ Note: Depending on the type of the object, a write operation through
> the pointer, lvalue or pointer to data member resulting from a
> const_cast that casts away a const-qualifier may produce undefined
> behavior (7.1.6.1). — end note ]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug c++/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
                   ` (4 preceding siblings ...)
  2020-09-10  7:43 ` matthijs at stdin dot nl
@ 2020-09-10  8:46 ` redi at gcc dot gnu.org
  2020-09-14 15:18 ` [Bug tree-optimization/96996] " msebor at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: redi at gcc dot gnu.org @ 2020-09-10  8:46 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
const_cast lets you add/remove cv-qualifiers from pointers and references, but
that doesn't make it OK to write to an object that was originally defined as
const. Similar to how reinterpret_cast from int* to float* doesn't make it OK
to violate TBAA rules. You can change the type, but that doesn't mean it's safe
to use.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Bug tree-optimization/96996] Missed optimzation for constant members of non-constant objects
  2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
                   ` (5 preceding siblings ...)
  2020-09-10  8:46 ` redi at gcc dot gnu.org
@ 2020-09-14 15:18 ` msebor at gcc dot gnu.org
  6 siblings, 0 replies; 8+ messages in thread
From: msebor at gcc dot gnu.org @ 2020-09-14 15:18 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96996

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |RESOLVED
         Resolution|---                         |DUPLICATE
                 CC|                            |msebor at gcc dot gnu.org
          Component|c++                         |tree-optimization
           See Also|                            |https://gcc.gnu.org/bugzill
                   |                            |a/show_bug.cgi?id=86318

--- Comment #7 from Martin Sebor <msebor at gcc dot gnu.org> ---
Let me confirm this as a potential generic optimization.  In fact, I believe
it's a duplicate of pr80794.  The related pr86318, when implemented, should
extend this optimization to non-const locals as well.

*** This bug has been marked as a duplicate of bug 80794 ***

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-09-14 15:18 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-09 12:12 [Bug web/96996] New: Missed optimzation for constant members of non-constant objects matthijs at stdin dot nl
2020-09-09 13:05 ` [Bug c++/96996] " redi at gcc dot gnu.org
2020-09-09 13:10 ` matthijs at stdin dot nl
2020-09-09 14:18 ` redi at gcc dot gnu.org
2020-09-10  7:23 ` rguenth at gcc dot gnu.org
2020-09-10  7:43 ` matthijs at stdin dot nl
2020-09-10  8:46 ` redi at gcc dot gnu.org
2020-09-14 15:18 ` [Bug tree-optimization/96996] " msebor at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).