On Fri, Aug 22, 2014 at 1:47 AM, Mike Stump <mikest...@comcast.net> wrote:
> On Aug 21, 2014, at 4:22 AM, Richard Biener <richard.guent...@gmail.com> 
> wrote:
>> I still say we need to solve the issue at language level - that is,
>> try to figure out what the language standard says about
>>
>> volatile struct X x, y;
>
>> x = y;
>
> The definition of x = y doesn’t change wrt volatile above.  See below for the 
> semantic of x = y;  What this does is it makes the members of x and y 
> volatile:
>
>        [#7] EXAMPLE 2 In:                                           |
>
>                struct s { int i; const int ci; };
>                struct s s;
>                const struct s cs;
>                volatile struct s vs;
>
>        the various members have the types:                          |
>
>                s.i     int
>                s.ci    const int
>                cs.i    const int
>                cs.ci   const int
>                vs.i    volatile int
>                vs.ci   volatile const int
>
>> or about
>>
>> struct X { volatile int x; } x, y;
>>
>> x = y;
>
> So, what the C99 standard[1] says is that memcpy copies n characters from one 
> to the other, leaving unspecified the order of the copy.  C++98 reuses by 
> reference those semantics.  Of course, there are quite a few memcpy 
> implementations that don’t do that.
>
> For x = y, in C++98, it is defined like so:
>
> 8 The implicitly-defined copy constructor for class X performs a member-
>   wise  copy of its subobjects.  The order of copying is the same as the
>   order of initialization of bases and members in  a  user-defined  con-
>   structor  (see  _class.base.init_).   Each  subobject is copied in the
>   manner appropriate to its type

Thats quite specific ;)

> which means a volatile int member translates to volatile SI read/write as 
> appropriate, or put another way, one can’t use memcpy for it.  Now, that 
> isn’t to say that we can’t change the language standard or improve it with 
> different semantics.
>
> For C99:
>
>        [#2] In simple  assignment  (=),  the  value  of  the  right
>        operand   is   converted  to  the  type  of  the  assignment
>        expression and replaces  the  value  stored  in  the  object
>        designated by the left operand.
>
> which I’d claim isn’t exactly clear and precise.  Clearly what they were 
> thinking was:

Indeed.

>        36)Thus,  for   example,   structure   assignment   may   be
>           implemented element-at-a-time or via memcpy.
>
> left not exactly well defined is the case of volatile.  Reasonable people 
> would say that volatile semantics are likely the same as C++98 (also, C++ was 
> mostly just noting what we thought the C standard said in the first place).
>
> I don’t keep up on DRs that might explicitly cover details, so I’d defer 
> those those if any.
>
>> I expect that most structs have volatile for a bogus reason
>> anyway and we slow down and enlarge code for no good reason.
>
> Yes, I suspect if we put in code to handle volatile members better, that no 
> code will care.  Why, cause no one has asked for those semantics, no code 
> depends upon those semantics.  Though, in time, some code might care.
>
>> So - why bother fixing this?  ISTR reading in the C standard
>> that structure assignments are expected to compile to memcpy.
>
> Your ISTR is quoted for you above.  That wording isn’t a prescription of 
> semantics.  It is an observation that there are some situations where the 
> implementation may use memcpy.
>
> In C99, sig_atomic_t defines when something is lock free, leaving unspecific 
> what else may be.  In later C++ standards (for example C++14), 
> [atomics.lockfree] defines additional types that are atomic.
>
>
> 1 - I use n843 for C99, which is slightly different from the standard, but in 
> this case I suspect it is the same.

So after reading the std quotations I still think that if we want to
fix anything
here then we want to fix it in the frontends (only the C++ FE knows
init order in the details required - though I suppose the description was for
non-POD types where the FE may already do this).

_If_ we want to do this in the middle-end then I suggest to do the
decomposition during gimplification as the rest of the middle-end
doesn't treat the second example as a volatile aggregate copy at all.

Fixing this with the proposed patch doesn't really fix it and it will
perform the worst of all implementations (a byte-by-byte copy
certainly will break that hardware access the patch was meant to fix,
also thinking of a struct with volatile bitfields and
-fstrict-volatile-bitfields).

I'd still lean towards doing this in frontends (or c-family/ code).

Richard.

Reply via email to