aliasing
Martin Uecker
uecker@tugraz.at
Mon Mar 18 10:55:46 GMT 2024
Am Montag, dem 18.03.2024 um 09:26 +0100 schrieb Richard Biener:
> On Mon, Mar 18, 2024 at 8:03 AM Martin Uecker <uecker@tugraz.at> wrote:
> >
> >
> > Hi,
> >
> > can you please take a quick look at this? This is intended to align
> > the C standard with existing practice with respect to aliasing by
> > removing the special rules for "objects with no declared type" and
> > making it fully symmetric and only based on types with non-atomic
> > character types being able to alias everything.
> >
> >
> > Unrelated to this change, I have another question: I wonder if GCC
> > (or any other compiler) actually exploits the " or is copied as an
> > array of byte type, " rule to make assumptions about the effective
> > types of the target array?
>
> We do not make assumptions about this anymore. We did in the
> past (might be a distant past) transform say
>
> struct X { int i; float f; } a, b;
>
> void foo ()
> {
> __builtin_memcpy (&a, &b, sizeof (struct X));
> }
>
> into
>
> a = b;
>
> which has an lvalue of type struct X. But this assumed b's effective
> type was X. Nowadays we treat the copy as using alias set zero.
> That effectively means the destination gets its effective type "cleared"
> (all subsequent accesses are valid to access storage with the effective
> type of a byte array).
Ok, thanks! I wonder whether we should remove this special rule
from the standard. I mostly worried about the "copied as an
array of byte type" wording which seems difficult to precisely
define.
>
> > I know compilers do this work memcpy...
> > Maybe also if a loop is transformed to memcpy?
>
> We currently do not preserve the original effective type of the destination
> (or the effective type used to access the source) when doing this. With
> some tricks we could (we also lose aligment guarantees of the original
> accesses).
>
> > Martin
> >
> >
> > Add the following definition after 3.5, paragraph 2:
> >
> > byte array
> > object having either no declared type or an array of objects declared with a byte type
> >
> > byte type
> > non-atomic character type
This essentially becomes the "alias anything" type.
> >
> > Modify 6.5,paragraph 6:
> > The effective type of an object that is not a byte array, for an access to its
> > stored value, is the declared type of the object.97) If a value is
> > stored into a byte array through an lvalue having a byte type, then
> > the type of the lvalue becomes the effective type of the object for that
> > access and for subsequent accesses that do not modify the stored value.
> > If a value is copied into a byte array using memcpy or memmove, or is
> > copied as an array of byte type, then the effective type of the
> > modified object for that access and for subsequent accesses that do not
> > modify the value is the effective type of the object from which the
> > value is copied, if it has one. For all other accesses to a byte array,
> > the effective type of the object is simply the type of the lvalue used
> > for the access.
>
> What's the purpose of this change? To me this reads more confusing and
> complicated than what I find in the c23 draft from April last year.
Note that C23 has been finalized. This change is proposed for the
revision after c23.
>
> I'll note that GCC does not take advantage of "The effective type of an
> object for an access to its stored value is the declard type of the object",
> instead it always relies on the type of the lvalue (treating non-atomic
> character types specially, as well as treating all string ops like memcpy
> or strcpy as using a character type for the access) and the effective type
> of the object for that access and for subsequent accesses that do not
> modify the stored value always becomes that of the lvalue type used for
> the access.
Understood.
>
> Let me give you an complication example made valid in C++:
>
> struct B { float x; float y; };
> struct X { int n; char buf[8]; } x, y;
>
> void foo(struct B *b)
> {
> memcpy (x.buf, b, sizeof (struct B)); // in C++: new (x.buf) B (*b);
Let's make it an explicit store for the moment
(should not make a difference though):
*(struct B*)x.buf = *b;
> y = x; // (*)
> }
>
> What's the effective type of 'x' in the 'y = x' copy?
Good point. The existing wording would take the declared
type of x as the effective type, but this may not be
what you are interested in. Let's assume that x has no declared
type but that it had effective type struct X before the
store to x.buf (because of an even earlier store to
x with type struct X).
There is a general question how stores to subobjects
affect effective types and I do not think this is clear
even before this proposed change.
> With your new
> wording, does 'B' transfer to x.buf with memcpy?
Yes, it would. At least this is the intention.
Note that this would currently be undefined behavior
because x.buf has a declared type. So this is main
thing we want to change, i.e. making this defined.
> What's the
> frankenstein effective type of 'x' then? What's the effective type
> of 'y' after the copy? Can an lvalue of type 'B' access y.buf?
All good questions, but unfortunately not clear even
in the current wording I think.
Martin
>
> Richard.
>
> > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3230.pdf
> >
> >
More information about the Gcc
mailing list