This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Volatile MEMs in statement expressions and functions inlinedastrees



On 15 Dec 2001, Alexandre Oliva wrote:
> >>
> >> but that, after the assignment is performed, and the result is
> >> actually an lvalue, so it can be asserted that the value stored was
> >> written into lvalue, and it can be only assumed that reading it back
> >> would get the same value back,
>
> > That's not true, and you know it.
>
> Hmm...  Perhaps I didn't express myself well.  I meant that one can be
> sure that the value stored was written, but that there may be doubt on
> whether reading the value back would give the same value back.

Yes, that phrasing I certainly agree with. That's what "volatile" has
traditionally meant.

We can be absolutely certain what the "value stored" was, but there is
some doubt what a subsequent read-back would result in.

This is also why I think that

	(a = 10) == 10

must be true, because while there is "reasonable doubt" about what the
contents of 'a' are when read back, there is absolutely no doubt about
what the value we stored was. It was clearly 10.

(This is all assuming 'a' is volatile, of course, for non-volatile 'a'
there is no doubt in the compilers mind in either case, and the compiler
can do whatever it pretty well chooses, including reading back the value
one bit at a time in a random order).

> >  (a) according to the C++ standard, that assert must NEVER fire
>
> I disagree this can be drawn from the C++ standard.

I really do not see how you can ignore the sentence that says so.

Think of it this way:

 - the expression 'a = 10' is an lvalue. We all agree.

 - the lvalue 'a' has the value 10 at the _exact_ time of the
   assignment, but not necessarily _ever_ again afterwards.

 - the assignment returns the value 'a' had WHEN ASSIGNED.

 - the assignment does NOT return the value 'a' had 5 nanoseconds later,
   when we read it back.

None of these are mutually exclusive statements.

Gabriel has tried and tried and tried to say that the "lvalue"ness of "a =
10" is mutually exclusive with the notion that we return the value "10".

I do not agree. I see absolutely zero conflict of interest.

Do you see any fundamental conflict in the above four statements? Gabriel
claims that the "lvalueness" of "a = 10" _proves_ that we cannot just
return 10. Can you explain to me what that "proof" is?

I think Gaby is full of it.

> > The _what_ do you claim that "value stored" thing actually means?
>
> I propose that the meaning of ``The result of the assignment operation
> is the value stored in the left operand after the assignment has taken
> place; the result is an lvalue.'' may be that the lvalue is guaranteed
> to have already been assigned the rvalue, so if you read it back, odds
> are that you'll find it there, but the result is still an lvalue,
> whose value is probably the stored value.

But would you at least agree that my reading of it is also logical, and
consistent, and, to some degree the "natural" reading of it?

Would you also agree that my reading of it guarantees consistent results,
and if implemented, also guarantees that the user can _depend_ on how many
times (and _how_) volatile objects are accessed?

Would you agree that my reading of it certainly does not violate the
spirit _or_ the letter of the C++ standard?

Note also how my reading of the standard means that there are absolutely
_no_ special cases about when we access a volatile object? There are no
"if used" or "if blue moon" or other rules..



> >> That depends on whether the function returns a reference (lvalue) or
> >> not (rvalue).
>
> > It does NOT.
>
> Sure it does.  It depends on the return type of the function, that you
> didn't include in your posting.

Oh. I thought you meant "assignment function", not some external thing. My
bad.

> > The fact that it is an lvalue means that you can do other things with it,
> > like take its address.
>
> Or return it by reference, but then the caller will have to access the
> variable to convert it to rvalue.  Or could the access be optimized
> away should the function call be inlined?

Once a lvalue has been returned by a function, that lvalue is no longer
"the assignment" - it's a new "copy" of the lvalue.

> > The meaning of "result of the assignment is the value stored" is not open
> > to much debate.
>
> Right.  But the fact that it's an lvalue may mean that the value may
> be there, in the variable, should you access it.

Absolutely.

And if you access the variable (as opposed to looking at the return value
of the assignment), you get that new value. No arguments there.

The standard says that the result of the _assignment_ is the "value
stored".

Nothing else. See the function call "return by value" example (let's make
this explicit):

	volatile int a;

	volatile int& fn(void)
	{
		return (a = 10);
	}

	main()
	{
		return fn();
	}

There is no doubt about this case: in "main()" we have an lvalue, not an
assignment, and all the regular lvalue dereferencing stuff applied. The
standards claim that "the result of an assignment is the value stored"
doesn't apply, because there is no assignment in "main()", only a function
call.

In fact, from a low-level implementation standpoint, "fn()" really returns
a pointer to a volatile int, the rest is just C++ syntax. Agreed?

However, that still isn't in any conflict with the _value_ of the actual
assignment being the "value stored", ie "10". The lack of conflict comes
from the fact that outside of that one expression we no longer have an
assignment, we have a function return of an lvalue (or whatever else). At
which point the standard is very very silent about what the actual "lvalue
to rvalue conversion" really does. The _implementation_ usually is just a
dereference of the pointer implied by the lvalue.

> But, just like some people are choosing to neglect the part of the
> sentence that says that the result is the stored value, others are
> choosing to neglect the fact that it's an lvalue, or trying to impose
> an associated rvalue to the lvalue that can't be obtained by accessing
> it.  See?  None of the readings is perfectly consistent.

I disagree. Anybody who ignores _any_ part of the standard is simply not
following the standard. You _have_ to read them all, and I'm saying that
you _can_ be consistent.

See the four points above. They are perfectly consistent.

> > I further claim that NOWHERE does the standard say that the "lvalue to
> > rvalue conversion" is an "access". Show me.
>
> I've suggested that the only hint we could find for this fact is the
> absence of access when evaluating the operand of sizeof.  From it, one
> could draw the conclusion that, in other cases, the lvalue-to-rvalue
> conversion does perform an access, but it would not be on strong
> grounds, I agree.

I would say that we can draw the conclusion that in other cases the
conversion _may_ be an access, and because of the requirement of not
trapping, in the sizeof case it MUST NOT be.

> Then let's turn the table around: now you show me where the Standard
> says that an lvalue may have an rvalue associated with it that is not
> the rvalue you'd obtain by accessing it.

I'd be more than happy to (big groan from the audience).

It's in section 5.17, second sentence. It goes like "The result of the
assignment operation is the value stored in the left operand after the
assignment has taken place; the result is an lvalue".

See? The standard says that the result is an lvalue, and that the result
is the "value stored".

NOTE! If you absolutely want to say that this is "the rvalue you'd obtain
by accessing it", then I can give you another excuse to read it my way.

I'm claiming that we _are_ actually accessing the lvalue. We're trivially
accessing it by _writing_, not by reading. The standard doesn't say what
really constitutes an "access", so you might as well say that "writing the
value is a form of access that modifies the lvalue and returns the value
stored".

On an implementation level, you could think of this (surprise surprise) as
a "mov" instruction. You can (validly) claim that

	movl %eax,a

is a sequence that atomically writes the value (in %eax) into the lvalue
'a', _and_ clearly accesses 'a' in a way that means that at the time of
the assignment, the value of 'a' is also the value in %eax.

So the assignment operation obviously _does_ do an "access" of the object
pointed to by "a", but this time it just happens to be a write.

And a write always implicitly _contains_ the "instantaneous read". Anbd
for an object marked "volatile", you MUST NOT do another read, because
that other read might return a different value than the one you implicitly
read back when you stored the value.

That's another way ofthinking about the write. And it's again a completely
_consistent_ way of thinking about it, that violates _none_ of the
requirements in the standard.

While yours and Gabriels way of thinking about it clearly _does_ violate
one part of the standard. The "value stored" part.

			Linus


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]