Commit 8f0fe813 by Nathan Sidwell Committed by Nathan Sidwell

gimplify.c (gimplify_modify_expr): When assigning to volatiles, copy the src…

gimplify.c (gimplify_modify_expr): When assigning to volatiles, copy the src value and return a copy.

	gcc/
	* gimplify.c (gimplify_modify_expr): When assigning to volatiles,
	copy the src value and return a copy.
	* doc/extend.texi (Volatiles): Move from C++ to C and expand.
	(C++ Volatiles): Adjust to describe C++ semantics only.

	gcc/testsuite/
	* gcc.target/i386/volatile-2.c: New.

From-SVN: r163400
parent f8fe0a4a
...@@ -66,6 +66,7 @@ extensions, accepted by GCC in C90 mode and in C++. ...@@ -66,6 +66,7 @@ extensions, accepted by GCC in C90 mode and in C++.
* Type Attributes:: Specifying attributes of types. * Type Attributes:: Specifying attributes of types.
* Alignment:: Inquiring about the alignment of a type or variable. * Alignment:: Inquiring about the alignment of a type or variable.
* Inline:: Defining inline functions (as fast as macros). * Inline:: Defining inline functions (as fast as macros).
* Volatiles:: What constitutes an access to a volatile object.
* Extended Asm:: Assembler instructions with C expressions as operands. * Extended Asm:: Assembler instructions with C expressions as operands.
(With them you can define ``built-in'' functions.) (With them you can define ``built-in'' functions.)
* Constraints:: Constraints for asm operands * Constraints:: Constraints for asm operands
...@@ -5052,6 +5053,88 @@ The definition in the header file will cause most calls to the function ...@@ -5052,6 +5053,88 @@ The definition in the header file will cause most calls to the function
to be inlined. If any uses of the function remain, they will refer to to be inlined. If any uses of the function remain, they will refer to
the single copy in the library. the single copy in the library.
@node Volatiles
@section When is a Volatile Object Accessed?
@cindex accessing volatiles
@cindex volatile read
@cindex volatile write
@cindex volatile access
C has the concept of volatile objects. These are normally accessed by
pointers and used for accessing hardware or inter-thread
communication. The standard encourage compilers to refrain from
optimizations concerning accesses to volatile objects, but leaves it
implementation defined as to what constitutes a volatile access. The
minimum requirement is that at a sequence point all previous accesses
to volatile objects have stabilized and no subsequent accesses have
occurred. Thus an implementation is free to reorder and combine
volatile accesses which occur between sequence points, but cannot do
so for accesses across a sequence point. The use of volatiles does
not allow you to violate the restriction on updating objects multiple
times between two sequence points.
Accesses to non-volatile objects are not ordered with respect to
volatile accesses. You cannot use a volatile object as a memory
barrier to order a sequence of writes to non-volatile memory. For
instance:
@smallexample
int *ptr = @var{something};
volatile int vobj;
*ptr = @var{something};
vobj = 1;
@end smallexample
Unless @var{*ptr} and @var{vobj} can be aliased, it is not guaranteed
that the write to @var{*ptr} will have occurred by the time the update
of @var{vobj} has happened. If you need this guarantee, you must use
a stronger memory barrier such as:
@smallexample
int *ptr = @var{something};
volatile int vobj;
*ptr = @var{something};
asm volatile ("" : : : "memory");
vobj = 1;
@end smallexample
A scalar volatile object is read, when it is accessed in a void context:
@smallexample
volatile int *src = @var{somevalue};
*src;
@end smallexample
Such expressions are rvalues, and GCC implements this as a
read of the volatile object being pointed to.
Assignments are also expressions and have an rvalue. However when
assigning to a scalar volatile, the volatile object is not reread,
regardless of whether the assignment expression's rvalue is used or
not. If the assignment's rvalue is used, the value is that assigned
to the volatile object. For instance, there is no read of @var{vobj}
in all the following cases:
@smallexample
int obj;
volatile int vobj;
vobj = @var{something};
obj = vobj = @var{something};
obj ? vobj = @var{onething} : vobj = @var{anotherthing};
obj = (@var{something}, vobj = @var{anotherthing});
@end smallexample
If you need to read the volatile object after an assignment has
occurred, you must use a separate expression with an intervening
sequence point.
As bitfields are not individually addressable, volatile bitfields may
be implicitly read when written to, or when adjacent bitfields are
accessed. Bitfield operations may be optimized such that adjacent
bitfields are only partially accessed, if they straddle a storage unit
boundary. For these reasons it is unwise to use volatile bitfields to
access hardware.
@node Extended Asm @node Extended Asm
@section Assembler Instructions with C Expression Operands @section Assembler Instructions with C Expression Operands
@cindex extended @code{asm} @cindex extended @code{asm}
...@@ -13152,7 +13235,7 @@ test specifically for GNU C++ (@pxref{Common Predefined Macros,, ...@@ -13152,7 +13235,7 @@ test specifically for GNU C++ (@pxref{Common Predefined Macros,,
Predefined Macros,cpp,The GNU C Preprocessor}). Predefined Macros,cpp,The GNU C Preprocessor}).
@menu @menu
* Volatiles:: What constitutes an access to a volatile object. * C++ Volatiles:: What constitutes an access to a volatile object.
* Restricted Pointers:: C99 restricted pointers and references. * Restricted Pointers:: C99 restricted pointers and references.
* Vague Linkage:: Where G++ puts inlines, vtables and such. * Vague Linkage:: Where G++ puts inlines, vtables and such.
* C++ Interface:: You can use a single C++ header file for both * C++ Interface:: You can use a single C++ header file for both
...@@ -13169,50 +13252,40 @@ Predefined Macros,cpp,The GNU C Preprocessor}). ...@@ -13169,50 +13252,40 @@ Predefined Macros,cpp,The GNU C Preprocessor}).
* Backwards Compatibility:: Compatibilities with earlier definitions of C++. * Backwards Compatibility:: Compatibilities with earlier definitions of C++.
@end menu @end menu
@node Volatiles @node C++ Volatiles
@section When is a Volatile Object Accessed? @section When is a Volatile C++ Object Accessed?
@cindex accessing volatiles @cindex accessing volatiles
@cindex volatile read @cindex volatile read
@cindex volatile write @cindex volatile write
@cindex volatile access @cindex volatile access
Both the C and C++ standard have the concept of volatile objects. These The C++ standard differs from the C standard in its treatment of
are normally accessed by pointers and used for accessing hardware. The volatile objects. It fails to specify what constitutes a volatile
standards encourage compilers to refrain from optimizations concerning access, except to say that C++ should behave in a similar manner to C
accesses to volatile objects. The C standard leaves it implementation with respect to volatiles, where possible. However, the different
defined as to what constitutes a volatile access. The C++ standard omits lvalueness of expressions between C and C++ complicate the behaviour.
to specify this, except to say that C++ should behave in a similar manner G++ behaves the same as GCC for volatile access, @xref{C
to C with respect to volatiles, where possible. The minimum either Extensions,,Volatiles}, for a description of GCC's behaviour.
standard specifies is that at a sequence point all previous accesses to
volatile objects have stabilized and no subsequent accesses have
occurred. Thus an implementation is free to reorder and combine
volatile accesses which occur between sequence points, but cannot do so
for accesses across a sequence point. The use of volatiles does not
allow you to violate the restriction on updating objects multiple times
within a sequence point.
@xref{Qualifiers implementation, , Volatile qualifier and the C compiler}.
The behavior differs slightly between C and C++ in the non-obvious cases: The C and C++ language specifications differ when an object is
accessed in a void context:
@smallexample @smallexample
volatile int *src = @var{somevalue}; volatile int *src = @var{somevalue};
*src; *src;
@end smallexample @end smallexample
With C, such expressions are rvalues, and GCC interprets this either as a The C++ standard specifies that such expressions do not undergo lvalue
read of the volatile object being pointed to or only as request to evaluate to rvalue conversion, and that the type of the dereferenced object may
the side-effects. The C++ standard specifies that such expressions do not be incomplete. The C++ standard does not specify explicitly that it
undergo lvalue to rvalue conversion, and that the type of the dereferenced is lvalue to rvalue conversion which is responsible for causing an
object may be incomplete. The C++ standard does not specify explicitly access. There is reason to believe that it is, because otherwise
that it is this lvalue to rvalue conversion which may be responsible for certain simple expressions become undefined. However, because it
causing an access. However, there is reason to believe that it is, would surprise most programmers, G++ treats dereferencing a pointer to
because otherwise certain simple expressions become undefined. However, volatile object of complete type as GCC would do for an equivalent
because it would surprise most programmers, G++ treats dereferencing a type in C@. When the object has incomplete type, G++ issues a
pointer to volatile object of complete type when the value is unused as warning; if you wish to force an error, you must force a conversion to
GCC would do for an equivalent type in C@. When the object has incomplete rvalue with, for instance, a static cast.
type, G++ issues a warning; if you wish to force an error, you must
force a conversion to rvalue with, for instance, a static cast.
When using a reference to volatile, G++ does not treat equivalent When using a reference to volatile, G++ does not treat equivalent
expressions as accesses to volatiles, but instead issues a warning that expressions as accesses to volatiles, but instead issues a warning that
...@@ -13222,6 +13295,18 @@ possible to ignore the return value from functions returning volatile ...@@ -13222,6 +13295,18 @@ possible to ignore the return value from functions returning volatile
references. Again, if you wish to force a read, cast the reference to references. Again, if you wish to force a read, cast the reference to
an rvalue. an rvalue.
G++ implements the same behaviour as GCC does when assigning to a
volatile object -- there is no reread of the assigned-to object, the
assigned rvalue is reused. Note that in C++ assignment expressions
are lvalues, and if used as an lvalue, the volatile object will be
referred to. For instance, @var{vref} will refer to @var{vobj}, as
expected, in the following example:
@smallexample
volatile int vobj;
volatile int &vref = vobj = @var{something};
@end smallexample
@node Restricted Pointers @node Restricted Pointers
@section Restricting Pointer Aliasing @section Restricting Pointer Aliasing
@cindex restricted pointers @cindex restricted pointers
......
...@@ -4576,6 +4576,9 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -4576,6 +4576,9 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
SET_DECL_DEBUG_EXPR (*from_p, *to_p); SET_DECL_DEBUG_EXPR (*from_p, *to_p);
} }
if (want_value && TREE_THIS_VOLATILE (*to_p))
*from_p = get_initialized_tmp_var (*from_p, pre_p, post_p);
if (TREE_CODE (*from_p) == CALL_EXPR) if (TREE_CODE (*from_p) == CALL_EXPR)
{ {
/* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL /* Since the RHS is a CALL_EXPR, we need to create a GIMPLE_CALL
...@@ -4603,7 +4606,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, ...@@ -4603,7 +4606,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
if (want_value) if (want_value)
{ {
*expr_p = unshare_expr (*to_p); *expr_p = TREE_THIS_VOLATILE (*to_p) ? *from_p : unshare_expr (*to_p);
return GS_OK; return GS_OK;
} }
else else
......
2010-08-20 Nathan Sidwell <nathan@codesourcery.com>
* gcc.target/i386/volatile-2.c: New.
2010-08-19 Andrey Belevantsev <abel@ispras.ru> 2010-08-19 Andrey Belevantsev <abel@ispras.ru>
PR rtl-optimization/44691 PR rtl-optimization/44691
......
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* Check volatiles are written, read or not re-read consistently */
/* simple assignments */
extern int volatile obj_0;
void test_0 (int data)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_0" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_0," } } */
obj_0 = data;
}
extern int volatile obj_1;
int test_1 (int data)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_1" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_1," } } */
return obj_1 = data;
}
extern int volatile obj_2;
int test_2 (void)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_2" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_2," } } */
return obj_2 = 0;
}
/* Assignments in compound exprs */
extern int volatile obj_3;
int test_3 (int data)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_3" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_3," } } */
return (obj_3 = data, 0);
}
extern int volatile obj_4;
int test_4 (void)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_4" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_4," } } */
return (obj_4 = 0, 0);
}
extern int volatile obj_5;
int test_5 (void)
{
/* should reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_5" } } */
/* { dg-final { scan-assembler "movl\[ \t\]obj_5," } } */
return (obj_5 = 0, obj_5);
}
/* Assignments in conditional exprs */
extern int volatile obj_6;
void test_6 (int data, int cond)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_6" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_6," } } */
cond ? obj_6 = data : 0;
}
extern int volatile obj_7;
int test_7 (int data, int cond)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_7" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_7," } } */
return cond ? obj_7 = data : 0;
}
extern int volatile obj_8;
int test_8 (int cond)
{
/* should not reread obj */
/* { dg-final { scan-assembler "movl\[ \t\]\[^,\]+, obj_8" } } */
/* { dg-final { scan-assembler-not "movl\[ \t\]obj_8," } } */
return cond ? obj_8 = 0 : 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment