[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-02 22:07 
---
Prior versions of gcc did "respect" casts to pointer-to-volatile and did not
optimize away the access. I've seen a lot of code that relies on that, and which
would thus be broken by gcc 4.x (in a subtle and hard-to-debug way). One recent
example is an elusive bug in Fedora Core 4's X.org package which bit many users
(https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=161242).

I can't imagine a programmer casting into a pointer to volatile without really
meaning it, so if the behavior is not defined by the standard then both
compatibility and the principle of least astonishment seem to suggest reverting
to the old behavior.

-- 
   What|Removed |Added

 CC|            |gcc2eran at tromer dot org


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-02 23:30 
---
(In reply to comment #17)
> Furthermore, the fundamental issue is whether this
> 
>*(volatile int*) (int*) (&foo);
> 
> (or equivalent) where foo has been defined volatile int  should be
> treated differently from 
> 
>*(volatile int*) (&foo);
> 
>  or 
> 
>foo;

How about this?

int foo; 
*(volatile int*) (&foo);

In other words, why should the compiler bother at all with the qualifiers of
what the pointer "really" points to? It seems simplest and most natural to
decree that any dereference of a pointer-to-volatile (regardless of its origin)
is to be treated as volatile and thus never optimized away. In other words,
"volatile" should treated as a property of the type of the pointer being
dereferenced, not of the actual object being pointed to.

By analogy, if I write

long bar = 42;
x = *(char*)bar;

then the compiler won't optimize this (into a SEGV?) just because it can easily
tell that bar didn't "really" originate from a char*. Rather, it will take my
word that (char*)bar should be treated just like any char*. Sure, it might
optimize this subject to the usual semantics of char* -- but in case of
volatiles, these semantics (should) forbid certain optimizations.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 01:19 
---
(In reply to comment #22)
> | int foo; 
> | *(volatile int*) (&foo);
> 
> It was included in my previous message.

Then it's still eluding me, since your foo (the "object"?) was volatile.


> | In other words, why should the compiler bother at all with the qualifiers of
> | what the pointer "really" points to?
> 
> Because the language definition says that the compiler should preserve
> a semantics and the compiler better bothers.

Of course, but please forgive my ignorance -- where does does the standard 
prescribe these semantics? The N869 draft (I don't have the standard; is N869
best fall-back?) says this:

"[6.7.3/6] An object that has volatile-qualified type may be modified in ways
unknown to the lementation or have other unknown side effects. Therefore any
expression referring to such an object shall be evaluated strictly according to
the rules of the abstract machine, as described in 5.1.2.3. [...]"

All other references to the semantics volatile likewise talk about objects. So,
what is an object?

"[3.15/1] object: region of data storage in the execution environment, the
contents of which can represent values"
"[3.15/2] NOTE When referenced, an object may be interpreted as having a
particular type; see 6.3.2.1."

What indeed is the type of an object?

"[6.3.2.1/1] [...] When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. [...]"

And also, later on:

"[6.5.3.2/4] The unary * operator denotes indirection. If the operand [...]
points to an object, the result is an lvalue designating the
object. If the operand has type ‘‘pointer to type’’, the result has type
‘‘type’’. [...]"

And just to be sure about whether "volatile" is part of the type thus specified
by the lvalue:

"[6.2.5/26] [...] The qualified or unqualified versions of a type are distinct
types [...]."

So the way I read it, the object designated by *(volatile int*)(anything) has a
 volatile-qualified type and should thus be evaluated strictly according to the
rules of the abstract machine.


> but that is a fundamental departure from the language semantics.
> Replace "volatile" with "const" -- both are qualifiers -- and observe
> the disaster that would ensue.

I must be showing my ignorance again, but what disaster would that be?



BTW, according to your interpretation, what is the standard-compliant behavior
of the following?

  void quux(int *bar) {
*bar = 42;
  }

  volatile int foo;
  quux((int*)&foo);

I'm asking because as of 4.0.0, the assignment is optimized away by -O3.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 01:46 
---
(In reply to comment #24)

Thanks! 
None of the quotes and references in comment 23 changed in N1124.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 02:30 
---
(In reply to comment #25)
> If when the compiler sees "const T* p", it assumes that *p is
> effectively const, then it would miscompile
> 
>int foo(int* p, const int* q) {
>int r = *q;
>*p = r * r;
>return *q;
>}
>
> If the compiler assumed that *q is effectively const, therefore cannot
> have its value changed through *p, then the following assertion will fail
> 
> int i = 4;
> assert(foo(&i, &i) == 16);
> 
> because the compiler could just return the cached value "r". 

We need to distinguish between the semantics that that must be followed, and
optimizations that preserve these semantics. The way I understand it,
semantics-wise "const" is not a promise, it's only a requirement: it tells the
compiler that it can't change the object directly, that's all. Meanwhile, the
optimizer tries to do various optimizations that preserve the semantics, for
example by noting that variables don't change their values; but in your example
it can't make that assumption without aliasing analysis (which will fail), since
by itself the const-qualified argument guarantees nothing.

So the standard says the semantics are dumb: they considers just the type of the
dereferenced pointer and acts accordingly (forbid direct changes of consts,
apply strict abstrat machine for volatiles). But subject to those semantics, the
optimizer can be as smart as it wants. There's no contradiction here.


>[#5] If an attempt is made to modify an object defined  with
>a  const-qualified  type  through use of an lvalue with non-
>const-qualified type, the  behavior  is  undefined.   If  an
>attempt  is  made  to  refer  to  an  object  defined with a
>volatile-qualified type through use of an lvalue  with  non-
>volatile-qualified type, the behavior is undefined.113)

OK. Then the volatile-stripping direction can be handled arbitrarily.


(In reply to comment #26)
> It was my object "bar".

OK. I was looking at comment 17.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 04:14 
---
(In reply to comment #30)
> | OK. Then the volatile-stripping direction can be handled arbitrarily.
> 
> I do not understand that comment.

I meant that we were mostly concerned about what the standard says about the
effect of casting (say) int* into volatile int*, but the other directly is
simply undefined. 

Still, consider the following variant:

  void quux(int *bar) {
*(volatile int*)bar = 42;
  }

  volatile int foo;
  quux((int*)&foo);

This time there is no "attempt [...] to refer to an object defined with a
volatile-qualified type through use of an lvalue with non-volatile-qualified
type". So why does gcc 4.0.0 -O3 still optimize away the assignment? And how
would you fix that with an approach that construes the standard to require
following the type of the "real" object?

Could the standard intend something so convoluted, when the interpretation in
comment 23 makes things perfectly sensible, well-defined and (in principle) easy
to implement?


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug tree-optimization/21568] [4.0/4.1 regression] Casts in folding *& omitted

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 04:55 
---
Why was this bug closed? The testcases in comment 5 do *not* pass.

Here's the first testcase, fixed to compile cleanly:


int avail;

int main() {
  volatile int **outside = (volatile int**)0x0123;
  *outside = &avail; 
  // avail is now potentially modifiable externally to the program
  while (*(volatile int *)&avail == 0)
continue;
  return 0;
}


Following the reasoning of comment 5, the read in the loop must not be optimized
away. Still, gcc 4.0.0 with -O3 produces this:


...
movl$avail, 291
movlavail, %eax
testl   %eax, %eax
je  .L5
xorl%eax, %eax
leave
ret
.L5:
jmp .L5


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21568


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 05:09 
---
(In reply to comment #32)
> | I meant that we were mostly concerned about what the standard says about the
> | effect of casting (say) int* into volatile int*, but the other directly is
> | simply undefined. 
> 
> That is what I do not understand.  Could you point me to the relevant
> passage of the C standard?

(my quote above should read "the other *direction* is simply undefined")

Uhm? It's just the passage you quoted earlier:
"If an attempt is made to refer to an object defined with a volatile-qualified
type through use of an lvalue with non-volatile-qualified type, the behavior is
undefined".


> 
> |   void quux(int *bar) {
> | *(volatile int*)bar = 42;
> |   }
> | 
> |   volatile int foo;
> |   quux((int*)&foo);
> | 
> | This time there is no "attempt [...] to refer to an object defined with a
> | volatile-qualified type through use of an lvalue with non-volatile-qualified
> | type".
> 
> Really?  What does quux() does to the object defined through foo then?

It refers to it through an lvalue whose type is "volatile int", which *is*
volatile-qualified.


> My understanding is that you have gotten everything backwards.

In what sense?


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug tree-optimization/21568] [4.0/4.1 regression] Casts in folding *& omitted

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 06:50 
---
> Did you read what was writting in comment #1 and #4?

Carefully. Similarly to Paul Schlie in comment 5, I don't agree. My reasoning
follows.


> Because at this point avail is known not to volatile.  

That is irrelevant. According to the standard, all that matters is whether
*(volatile int *)&avail has a volatile-qualified type, which it does. Please
bear with me as I repeat the argument from PR 22267 comment 23, quoting N1124:

"[6.7.3/6] An object that has volatile-qualified type may be modified in ways
unknown to the implementation or have other unknown side effects. Therefore any
expression referring to such an object shall be evaluated strictly according to
the rules of the abstract machine, as described in 5.1.2.3. [...]"

All other references to the semantics of volatile likewise talk about "objects",
so let's look up their definition:

"[3.15/1] object: region of data storage in the execution environment, the
contents of which can represent values"
"[3.15/2] NOTE When referenced, an object may be interpreted as having a
particular type; see 6.3.2.1."

And here comes the punchline: what is the type of an object?

"[6.3.2.1/1] [...] When an object is said to have a particular type, the type is
specified by the lvalue used to designate the object. [...]"

And also, later on:

"[6.5.3.2/4] The unary * operator denotes indirection. If the operand [...]
points to an object, the result is an lvalue designating the
object. If the operand has type ‘‘pointer to type’’, the result has type
‘‘type’’. [...]"

And just to be sure about whether "volatile" is part of the type thus specified
by the lvalue:

"[6.2.5/26] [...] The qualified or unqualified versions of a type are distinct
types [...]."


Hence, any access to an lvalue whose type is volatile-qualified must be
evaluated strictly according to the rules of the abstract machine. So the
semantics are completely local, caring only about the type of the lvalue. The
type using which the "actual object" being dereferenced was originally defined
is irrelevant.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21568


[Bug c/22278] gcc -O2 discards cast to volatile

2005-07-02 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 06:59 
---
(In reply to comment #34)

OK, that was just a demonstration of of the problem you pointed out in comments
9 and 12 and example (a) of comment 16. In this case, your analysis ("be
conservative") and my reading of the standard (comment 23) lead to identical
conclusions.

This leaves example (b) of comment 16, where the "real object" is non-volatile.
Here we seem to still disagree: you said it's a QoI and "not well-founded on the
C standard", hence currently not a bug and "fixing" it would be a gcc extension.
I argued, in comment 23, that this too is a bug, since the standard says that
any access to an lvalue with volatile-qualified type must be left untouched. But
this case seems to fall under PR 21568, which I believe should be reopened. For
convenience I copied the relevant parts of comment 23 to that PR.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278


[Bug tree-optimization/21568] [4.0/4.1 regression] Casts in folding *& omitted

2005-07-03 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-03 12:12 
---
To make it easier to evaluate my claim, here are all messages in the thread
linked from comment 1 that seemingly contradicy comment 9:

Nathan Sidwell: http://gcc.gnu.org/ml/gcc/2005-05/msg00085.html
Dale Johannesen: http://gcc.gnu.org/ml/gcc/2005-05/msg00090.html
Andrew Haley: http://gcc.gnu.org/ml/gcc/2005-05/msg00144.html

All of these, I am sorry to say, misinterpret the standard since they
misconstrue the meaning of the term "object" in the C type system. They assume
that the object's type is determined by the way it was created (which is indeed
the usual meaning in other languages), whereas the standard quite clearly
defines an object's type to be determined by the lvalue referencing it.

To give one example of this confusion, here is what Dale Johannesen said:
  "the standard consistently talks about the type of the object,
  not the type of the lvalue, when describing volatile."
And here is what N1124 [6.3.2.1/1] says:
  "When an object is said to have a particular type, the type is
   specified by the lvalue used to designate the object."
See my point?

I admit to earning my language lawyer diploma on languages other than C, but the
evidence in comment 9 seems very firm to me. Does anyone see any flaw in it? If
not, then shouldn't this bug be reopened?

Hey, we should be *happy* that we found a standard-compliance excluse to fix the
code-breaking regression and make those casts work like everybody wanted!

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21568


[Bug tree-optimization/21568] [4.0/4.1 regression] Casts in folding *& omitted

2005-07-06 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-06 18:42 
---
Correction of typo in comment 9: the related PR referenced is PR 22278.

-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21568


[Bug tree-optimization/21568] [4.0/4.1 regression] Casts in folding *& omitted

2005-07-08 Thread gcc2eran at tromer dot org

--- Additional Comments From gcc2eran at tromer dot org  2005-07-08 09:18 
---
(In reply to comment #13)
> In the C99 standard, 6.5.4 Cast Operators, Footnote 85 "A cast does not 
> yield an lvalue.  Thus, a cast to a qualified type has the same effect 
> as a cast to the unqualified version of the type."

But the object being accessed is the one designated by *dereferencing* the cast
expression, and *that* is an lvalue. Quoting N1124:

"[6.5.3.2/4] The unary * operator denotes indirection. If the operand [...]
points to an object, the result is an lvalue designating the
object. If the operand has type ‘‘pointer to type’’, the result has type
‘‘type’’."

And of course:

"[6.5.4/2] Preceding an expression by a parenthesized type name converts the
value of the expression to the named type. [...]"

I think this answers the first half of your quote (i.e., footnote 86), but I'm
not sure what to make of the second half, especially in light of the "Thus".


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21568


[Bug c/29626] New: Code generation bug for aliased long long with -mpentium-m

2006-10-28 Thread gcc2eran at tromer dot org
The following C program gives incorrect results with vanilla gcc 4.1.1 (default
./configure options except --prefix, compiled on Fedora Core 5) and specific
compile options.


#include 

char buf[8] = {1,1,1,1,1,1,1,1};
char zero=0;

int main() {
int i;

*(long long*)buf  = 0;
*(short*)buf ^= (zero) ^ (zero<<1); 

for (i=0; i<8; i++) printf("%x,", buf[i]);
return 0;
}


The buffer should contain all zeros after the two assignments, but it doesn't:

$ ~/gcc-4.1.1/bin/gcc -W -Wall -Wno-long-long -pedantic \
   -march=pentium-m -O2 -o gcc-bug  gcc-bug.c
$ ./gcc-bug
1,1,0,0,0,0,0,0,

Looks like some sort of aliasing issue for long longs; I don't see it happening
with ints. Twiddling compile options and further code simplification tends to
make the problem disappear.

The above is a (painfully) reduced version of useful code which exhibited the
problem, so it's actually something you can bump into.


-- 
   Summary: Code generation bug for aliased long long with -
mpentium-m
   Product: gcc
   Version: 4.1.1
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c
AssignedTo: unassigned at gcc dot gnu dot org
    ReportedBy: gcc2eran at tromer dot org
 GCC build triplet: 4.1.1
GCC target triplet: i686-pc-linux-gnu


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29626