Re: Spurious register spill with volatile function argument
* Paul Koning: >> On Mar 28, 2016, at 8:11 AM, Florian Weimerwrote: >> >> ... >> The problem is that “reading” is either not defined, or the existing >> flatly contradicts existing practice. >> >> For example, if p is a pointer to a struct, will the expression >m >> read *p? > > Presumably the offset of m is substantially larger than 0? If so, my > answer would be "it had better not". Does any compiler treat that > statement as an access to *p ? As I tried to explain, GCC does, for aliasing purposes. For the expression p->m, there is an implicit read of *p, asserting that the static and dynamic types match.
Re: Spurious register spill with volatile function argument
> On Mar 28, 2016, at 8:11 AM, Florian Weimerwrote: > > ... > The problem is that “reading” is either not defined, or the existing > flatly contradicts existing practice. > > For example, if p is a pointer to a struct, will the expression >m > read *p? Presumably the offset of m is substantially larger than 0? If so, my answer would be "it had better not". Does any compiler treat that statement as an access to *p ? paul
Re: Spurious register spill with volatile function argument
* Andrew Haley: > "volatile" doesn't really mean very much, formally speaking. Sure, the > standard says "accesses to volatile objects are evaluated > strictly according to the rules of the abstract machine," but nowhere > is it specified exactly what constitutes an access. Reading or modifying an object is defined as “access”. The problem is that “reading” is either not defined, or the existing flatly contradicts existing practice. For example, if p is a pointer to a struct, will the expression >m read *p? Previously, this wasn't very interesting. But under the model memory, it's suddenly quite relevant. If reading p->m implies a read of the entire object *p, you cannot use a member to synchronize access to other members of the struct. For example, if m is a mutex, and carefully acquire the mutex before you read or write other members, you still have data race between a write to some other member and the acquisition of the mutex because the mutex acquisition reads the entire struct (including the member written to ). One possible cure is to take the address of the mutex and keep track of it separately. Or you could construct a pointer using offsetof. But no one is doing that, obviously. This is not entirely hypothetical. Even today, GCC's aliasing analysis requires that those implicit whole-object reads take place, to make certain forms of type-punning invalid which would otherwise be well-defined (and for which GCC would generate invalid code).
Re: Spurious register spill with volatile function argument
On 27/03/16 06:57, Michael Clark wrote: > GCC, Clang folk, any ideas on why there is a stack spill for a > volatile register argument passed in esi? Does volatile force the > argument to have storage allocated on the stack? Is this a corner > case in the C standard? This argument in the x86_64 calling > convention only has a register, so technically it can’t change > outside the control of the C "virtual machine” so volatile has a > vague meaning here. "volatile" doesn't really mean very much, formally speaking. Sure, the standard says "accesses to volatile objects are evaluated strictly according to the rules of the abstract machine," but nowhere is it specified exactly what constitutes an access. (To be precise, "what constitutes an access to an object that has volatile-qualified type is implementation-defined.") So, we have to fall back to tradition. Traditionally, all volatile objects are allocated stack slots and all accesses to them are memory accesses. This is consistent behaviour, and has been for a long time. It is also extremely useful when debugging optimized code. > volatile for scalar function arguments seems to mean: “make this > volatile and subject to change outside of the compiler” rather than > being a qualifier for its storage (which is a register). No, arguments are not necessarily stored in registers: they're passed in registers, but after function entry function they're just auto variables and are stored wherever the compiler likes. Andrew.