LLVM Bugzilla is read-only and represents the historical archive of all LLVM issues filled before November 26, 2021. Use github to submit LLVM bugs

Bug 18538 - non-conforming optimization -fmerge-all-constants is enabled by default
Summary: non-conforming optimization -fmerge-all-constants is enabled by default
Status: RESOLVED FIXED
Alias: None
Product: clang
Classification: Unclassified
Component: -New Bugs (show other bugs)
Version: trunk
Hardware: PC Windows NT
: P normal
Assignee: Manoj Gupta
URL:
Keywords:
: 18557 19070 25955 27443 (view as bug list)
Depends on:
Blocks: release-6.0.1
  Show dependency tree
 
Reported: 2014-01-19 00:05 PST by Kazutoshi SATODA
Modified: 2018-06-11 15:49 PDT (History)
17 users (show)

See Also:
Fixed By Commit(s): r329300 r333564


Attachments
Bitcode of the compiled program (3.37 KB, text/plain)
2014-01-19 02:31 PST, jonathan.sauer
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Kazutoshi SATODA 2014-01-19 00:05:45 PST
The assertion in the following program should never fail because
variables with automatic storage duration in a function should be
created for each recursive invocation, and such distinct objects'
address should not compare equal.

  #include <assert.h>
  #include <stdio.h>
  int f(const int* p)
  {
    const int c[] = {12345,56789};
    assert(p != c);
    if (p == 0) { return f(c); }
    puts("Done.");
    return 0;
  }
  int main()
  {
    f(0);
  }

Clang 3.3 seems violating the rule and causes an assertion failure.
http://melpon.org/wandbox/permlink/tYmnEVjMNP33nYHr
> prog.exe: prog.c:6: int f(const int *): Assertion `p != c' failed.

I'm referring WG14 N1570.
http://www.open-std.org/jtc1/sc22/wg14/www/standards.html

From 6.2.4 p6:
> For such an object that does not have a variable length array type, its
> lifetime extends from entry into the block with which it is associated
> until execution of that block ends in any way. (Entering an enclosed
> block or calling a function suspends, but does not end, execution of the
> current block.) If the block is entered recursively, a new instance of
> the object is created each time.

6.5.9 p6
> Two pointers compare equal if and only if both are null pointers, both
> are pointers to the same object ...

If the variable is not an array, there seems no problem.
http://melpon.org/wandbox/permlink/uYeR8GbRvuQN3CMC
Comment 1 jonathan.sauer 2014-01-19 02:31:36 PST
Created attachment 11891 [details]
Bitcode of the compiled program

Still happens with clang r199081. Going by the bitcode (attached) clang transforms the

  const int c[] = {12345,56789};

into

  static const int c[] = {12345,56789};

as its contents is constant at compile-time and thus doesn't need to be created on the stack each time <f> is called (except of course when its address is compared).
Comment 2 jonathan.sauer 2014-01-20 04:36:07 PST
*** Bug 18557 has been marked as a duplicate of this bug. ***
Comment 3 Richard Smith 2014-01-21 15:04:37 PST
This is a (non-conforming) optimization, and can be disabled with -fno-merge-all-constants. I'm not sure why our default mode is non-conforming; possibly this optimization is very important on some code at -O0.
Comment 4 jonathan.sauer 2014-03-06 14:58:07 PST
*** Bug 19070 has been marked as a duplicate of this bug. ***
Comment 5 Matthew Dempsky 2014-03-06 15:18:45 PST
Any update on this?  The workaround isn't difficult, but I would think that Clang by default would try to be standards conforming, and any non-standard behavior would need to be explicitly opted into by the user.

Does Clang enable any other non-standards-conforming optimizations by default?
Comment 6 Richard Smith 2014-03-06 16:15:58 PST
This is the only case I can think of (off the top of my head) where clang deliberately does not conform to the standard by default, and has a flag to make it conform. There are a few other places where we deliberately don't conform because we think the standard is wrong (and generally we try to get the standard fixed in those cases).
Comment 7 John McCall 2014-03-06 17:23:49 PST
As long as we emit a code pattern that LLVM can easily turn back into the static equivalent, I think being standards-compliant
Comment 8 John McCall 2014-03-06 17:25:08 PST
(Sigh.)

As long as we emit a code pattern that LLVM can easily turn back into the static equivalent, I think being standards-compliant by default is the right thing to do.

I'm pretty sure that Chris wrote this particular code; CC'ing him for his input.
Comment 9 Chris Lattner 2014-03-06 17:27:36 PST
I'm not morally invested in this optimization, but I have to ask: why do you guys care about this?  Is it actually causing a problem in practice?  Is it causing a failure on some standards test suite, or something else?
Comment 10 Kazutoshi SATODA 2014-03-10 12:26:01 PDT
No problem in practice, at least for me.

I've learned that the lack of the static specifier causes unwanted stack
usage and repeated initialization in practice, and that are mandated by
the standard over a few decades. Then I used to be, and encourage others
to be, careful not to forget the static specifier. I noticed this issue
as going against my (and probably some others') observance.

Additionally, I can think of a portability problem that might be caused
by this behavior: A conforming program might rely on the address
uniqueness of the constants without static specifier. If such a program
was ported to clang, it would break silently.
Comment 11 Richard Smith 2015-12-29 14:27:06 PST
*** Bug 25955 has been marked as a duplicate of this bug. ***
Comment 12 Richard Smith 2016-04-21 13:39:56 PDT
*** Bug 27443 has been marked as a duplicate of this bug. ***
Comment 13 Mark Mentovai 2017-08-01 13:07:08 PDT
(In reply to Chris Lattner from comment #9)
> I'm not morally invested in this optimization, but I have to ask: why do you
> guys care about this?  Is it actually causing a problem in practice?  Is it
> causing a failure on some standards test suite, or something else?

This optimization hasn’t caused any functional problems in practice, but we have seen more of a human/social problem. Observing Clang perform this optimization has caused us to assume that, at function scope, a “static const” array (with true constant-expression initialization) is no different than a plain “const” one, and to prefer the less noisy “const” form, and even to standardize on it. That source code compiles to what we intended when fed to Clang, but it’s not so good when you bring it to other compilers, which produce less optimal code without “static” semantics unless you’re explicit.
Comment 14 Chris Lattner 2017-08-01 19:17:35 PDT
Ok, well, this is an incredibly old thread.  In the modern world, the optimization should only be applied to unnamed_addr globals.
Comment 15 Nick Desaulniers 2018-04-02 16:13:02 PDT
This was recently cited on LKML: https://lkml.org/lkml/2018/3/20/872
Comment 16 John McCall 2018-04-02 19:54:44 PDT
I think there's consensus that we should not be doing this by default, and we just need someone to write a patch to fix it.

Doing it for unnamed_addr constants does not require user intervention; it's an as-if optimization.
Comment 17 Manoj Gupta 2018-04-04 14:26:08 PDT
Patch at https://reviews.llvm.org/D45289
Comment 18 Manoj Gupta 2018-04-05 09:11:55 PDT
Submitted as https://reviews.llvm.org/rL329300