[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences

2018-04-18 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319

Tim Rentsch  changed:

   What|Removed |Added

 CC||txr at alumni dot caltech.edu

--- Comment #13 from Tim Rentsch  ---
Right you are.  I don't know how I could have missed that.

[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences

2018-04-18 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319

--- Comment #14 from Tim Rentsch  ---
(In reply to James Kuyper from comment #11)

That last message was in reply to James Kuyper in #11.  I
was expecting a reference would be added automatically.

[Bug c/83584] "ISO C forbids conversion of object pointer to function pointer type" -- no, not really

2017-12-26 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584

Tim Rentsch  changed:

   What|Removed |Added

 CC||txr at alumni dot caltech.edu

--- Comment #13 from Tim Rentsch  ---
(In reply to Andrew Pinski from comment #11)
> So again this is not a bug.

I mostly agree, but I think some clarification is needed.  For reference
here is the diagnostic gcc gives (under -pedantic-errors)

   error: ISO C forbids conversion of object pointer to function pointer

This text is wrong because it is factually incorrect.  There is nothing
in the ISO C standard that forbids or prohibits converting an object
pointer type to a function pointer type, or vice versa.

The catch is that these conversions aren't required to be supported
either.  Section 6.3 discusses conversions, with section 6.3.2.3
specifically concerned with pointer types.  Each case involving converting
a type to or from a pointer type is listed with a specific permission, eg,
"Any pointer type may be converted to an integer type."  There is no such
statement that says object pointer types may be converted to function
pointer types, or vice versa.  We may reasonably infer from these
statements that the "may be converted" cases must be accepted by all
conforming compilers, but not the others.  To say this the other way, any
case not explicitly covered (involving a pointer type) /may/ be accepted
but is not required to be.  Of course if such a conversion is evaluated
its behavior is undefined, but I mean something else, namely, whether a
program is accepted if it contains any such conversion, whether it is
evaluated or not.  To me it seems clear that the ISO C standard means that
such a program doesn't have to be accepted:  it /can/ be accepted, but it
doesn't /have/ to be.

Note section 4 paragraph 5:  "A /strictly conforming program/ shall use
only those features of the language and library specified in this
International Standard."  Converting between object pointer types and
function pointer types is not covered in the Standard.  I don't mean the
behavior isn't defined;  I mean the case is not addressed, ie, it is not a
feature of the language.  Hence any program containing such a conversion
is not a strictly conforming program, and as such it can be rejected.  So
I believe gcc is within its rights to make this an error.  It would be
nice if the diagnostic text were better, and consistent with what the
Standard says, but as far as being an error goes I think gcc is in the
clear here.

[Bug c/83584] "ISO C forbids conversion of object pointer to function pointer type" -- no, not really

2017-12-28 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83584

--- Comment #16 from Tim Rentsch  ---
(In reply to Andrew Pinski from comment #14)
> -pedantic is not designed to reject all programs that are not strictly
> conforming, but to enable emitting all _required_ diagnostics.  I
> don't think a conversion between function and object pointer type
> requires a diagnostic.

A conversion between function and object pointer type does not require a
diagnostic.  The point of my comment is that rejecting a program on that
basis is consistent with the Standard.  Moreover, it is reasonable for
gcc to reject such a program on that basis, as explained below.

The -pedantic option is not designed to reject all programs that are not
strictly conforming.  Indeed it could not do so because detecting exactly
those cases is not computable.

I agree that the -pedantic option is meant to enable emitting all required
diagnostics.  But it is not meant to emit _only_ those diagnostics that
the Standard requires.  For example, there is this case:

static int foo[];  /* given a size later in the source */

Compiling with -pedantic (note: not -pedantic-errors!) and no other
options gives

 error: array size missing in 'foo'

This construct is syntactically valid and has no constraint violations,
yet it is rejected under -pedantic.  (Rejecting the program is okay
because the construct itself has undefined behavior, under 6.9.2 p3.)

I believe -pedantic is meant to accept(*) only those programs that are
accepted by other compilers that strictly follow what ISO C requires
(assuming the same type sizes, etc).  That is, -pedantic is meant to be
conservative, allowing only those programs that any other conforming
implementation would not reject.  Hence it is reasonable for -pedantic to
reject the construct shown above, because some implementations might not
be able to handle it.  For the same reasons it is reasonable for -pedantic
to reject programs with a conversion between an object pointer type and a
function pointer type.  More strongly, it would be _un_reasonable for such
a program to be allowed under -pedantic-errors, because they very likely
would be rejected by other conforming implementations;  allowing such
programs pretty much defeats the purpose of -pedantic.

(*) Here "accept" is meant in the sense of not issuing any diagnostics
for, regardless of whether the diagnostics are warnings or errors.

[Bug rtl-optimization/14319] incorrect optimization of union of structs with common initial sequences

2016-11-01 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14319

--- Comment #10 from Tim Rentsch  ---
I would like to add a few comments to the discussion.

One:  C and C++ are different in how they treat unions.  My comments
here are about C.  I believe they apply to C++ as well, but I am not
as familiar with the C++ standard as the C standard, so please take
that into consideration.

Two:  The issue here is about how accesses involving struct and union
members interact with aliasing questions.  Clearly possible aliasing
is allowed IF one considers just the effective type rules (6.5 p6&7),
because the access types involved are both just 'int'.  What makes a
difference here is accesses being performed by way of the '->'
operator, and possible union membership for the objects in question.

Three:  The ISO C standard doesn't articulate clearly (at least, not
as clearly as I would like) what the aliasing implications are for
accesses involving struct and union members.  Obviously it would help
if the Standard were improved in this area.

Four:  Despite the last observation, the "one special guarantee" clause
(and hence also DR 257) is clearly not germane to this problem.  The
reason for this is that the "one special guarantee" clause is concerned
with read access ("inspect" is the word used in the Standard), but the
example code has no read accesses, only write accesses.  That paragraph
of the Standard is not relevant here.

Five:  For basically the same reason, this bug should not be considered
a duplicate of Bug 65892.  The example code in Bug 65892 _does_ involve
a read access, and the "one special guarantee" clause _is_ relevant to
that discussion.  Because of that, these two bugs should be separated
again, as their resolutions may be (and I believe probably will be)
different in the two cases.

I am expecting to post a separate comment for Bug 65892 shortly.

[Bug c/65892] gcc fails to implement N685 aliasing of union members

2016-11-01 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892

Tim Rentsch  changed:

   What|Removed |Added

 CC||txr at alumni dot caltech.edu

--- Comment #18 from Tim Rentsch  ---
I would like to add a few comments to the discussion.

One:  C and C++ are different in how they treat unions.  My comments
here are about C.  I believe they apply to C++ as well, but I am not
as familiar with the C++ standard as the C standard, so please take
that into consideration.

Two:  I have recently posted a comment for Bug 14319.  That comment
explains my reasoning why these two bugs should be separated and
not be considered duplicates.

Three:  I note the comments made by joseph with regard to the .s1/.s2
matter.  There may be a larger open question there, but to avoid
muddying the waters please assume that his change to use .s2 in the
initializer has been made.

Four:  I understand that there are also larger issues related to how
union membership may have a bearing on alias analysis.  My comments
here are confined to the particular case at hand, namely, given a
definition for union U followed by a definition for function f(),
could f() be optimized so the p1->m value is cached in a register
(or something similar) before the body of the if() is executed,
and the cached value used as the return value.

Five:  The answer to the question is clearly No.  The example code
is very much on point to the "one special guarantee" clause, and
so the read access p1->m is permitted.  As the access is permitted,
and as there are no other conditions present that cause undefined
or unspecified behavior, the behavior is well-defined, which means
any optimization that changes the unoptimized behavior is wrong.

Six:  To see the example code is covered under the "one special
guarantee" clause, note the second part of EXAMPLE 3 in 6.5.2.3.
In particular, the commentary in parentheses, "(because the union
type is not visible within function f)", shows that whether the
union type is defined before or after f() is the determining
factor here.  Whether a . or -> union membership operation is
present or not present has no bearing on the definedness of
the struct member access p1->m.

Seven:  I understand the objections about impacting alias analysis
and so forth.  I agree that it makes the analysis more difficult
(although not as sweeping in its implications as some comments
imply).  Despite the problems, the examples in the Standard, and
also the response to DR 257, both show that the committee members
fully intend that this case be covered under the "one special
guarantee" clause.

Eight:  In the meantime, I strongly recommend gcc be patched to
support the expected decision (which is the more conservative
choice) rather than suspending activity until some indefinite
time in the future.

[Bug c/65892] gcc fails to implement N685 aliasing of union members

2016-11-02 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892

--- Comment #21 from Tim Rentsch  ---
[responding to comments from jos...@codesourcery.com in Comment 19]

>> Five:  The answer to the question is clearly No.  The example code
>> is very much on point to the "one special guarantee" clause, and
>> so the read access p1->m is permitted.  As the access is permitted,
>
> I maintain that, as I said in comment#9, the textual history
> indicates that the original intent of saying things are permitted
> here is *only* an exception to the general implementation-defined
> nature of type punning, not to any other reason why things might
> be undefined (such as aliasing rules, data races, etc.).

I went back and read through your earlier comments more carefully.
After that I also reviewed C90, N869, C99, N1124, N1256, DR 236,
DR 257, DR 283, and C11 (in the guise of the just-pre-C11 draft
N1570).

Let me say first that I agree with you that the Semantics section
of the member access operators (. and ->) needs at least some
revision and clarification.

Having said that, let me offer several more detailed responses
and/or comments.

One:  IME later versions of the C standard generally do a better
job of expressing what is intended than earlier versions do.

Two:  The "visible union" condition in C99 was viewed not as a
change to C90 but as correcting an oversight;  it was expected
all along that the union type would be in scope, even if the
expectation was not a conscious one originally.  I am sorry I
don't have a reference handy for this, but one can be found
digging around in the historical documents on the open-std.org
website.

Three:  The "one special guarantee" rule is independent of the
rules for effective types.  This observation is obviously right
because effective type rules matter only for access to objects.
The only objects being accessed under the "one special guarantee"
rule are guaranteed to have compatible types, which is always
allowed by effective type rules.

Four:  The "one special guarantee" rule is related to the area of
"type punning" through unions, but seen by WG14 as a separate
issue relative to the general topic.  This is evident from the
committee response in DR 257.

Five:  The footnote added in C99 TC3 about type punning is seen
by WG14 not as a change but just as a clarifying comment noting
what behavior was intended all along.  This is evident from the
text and response in DR 283.  Note that Clark Nelson, the author
of this DR, is a long-standing member of WG14, and the suggested
revision given in the text was adopted verbatim for the TC.

Six:  A key question here is What is the point or purpose of the
"one special guarantee" rule in the first place?  the Standard
doesn't say, but let me propose two likely motivations.

1. Normally objects may be assumed not to overlap unless
they are accessed through an explicit union membership
expression (or through a character type, etc).  The "one
special guarantee" rule identifies a case where an explicit
union membership expression is not needed.

2. The C standard distinctly allows any amount of padding
between consecutive members of a struct.  Without the "one
special guarantee" rule, there would be no way to be sure
that the offsets of the respective members would match in
all cases.  The "one special guarantee" rule has the effect
of forcing offsets of struct members in a common initial
sequence to be the same.  That is important for code
portability.

Seven:  Given that the question is now under serious debate, IMO
someone involved with gcc development should take the initiative
and responsibility to submit a defect report in order to clarify
the issue.  Apparently other compilers don't have this problem -
only gcc does.

Eight:  In the meantime, the most prudent course of action is to
fix gcc so that it does not reorder code in cases like the above.
Whenever there is any doubt, the only sensible choice is to err
on the side of caution, and not perform any code transformations
that might not be allowed in a conforming implementation.  (Of
course it would be okay to perform such transformations under
some non-default compiler option, as long as it is not in force
unless explicitly requested, and clearly flagged as possibly
non-conforming.)

Nine:  Doing a final review, I realized I have not yet responded
directly to your last comment.  I agree with your general
sentiment that the "one special guarantee" rule is not meant as
a "super rule" that trumps all other possible reasons for
undefined behavior.  However, I do not agree with your primary
point that it is meant to be limited to the "type punning" area.
The example I previously mentioned in the C standard, and the
committee discussion in DR 257, both show that there are other
factors involved here beyond just those related to type punning.

I hope the above has helped clarify the matter.  I look forward
to reading your responding comment

[Bug c/65892] gcc fails to implement N685 aliasing of union members

2016-11-02 Thread txr at alumni dot caltech.edu
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65892

--- Comment #22 from Tim Rentsch  ---
[responding to comments from rguent...@suse.de in Comment 20]

> GCC already implements this if you specify -fno-strict-aliasing.

The main point of my comments is that the ISO C standard requires
the behavior in this case (and similar cases) be defined and not
subject to any reordering.  In other words the result must be the
same as an unoptimized version.  If a -fstrict-aliasing gcc /does/
transform the code so that the behavior is not the same as an
unoptimized version, then gcc is not a conforming implementation.
Or is it your position that gcc is conforming only when operated
in the -fno-strict-aliasing mode?  That position seems contrary to
the documented description of the -fstrict-aliasing option.