mirror of git://gcc.gnu.org/git/gcc.git
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
This commit is contained in:
parent
f8fe0a4a8e
commit
8f0fe81379
|
|
@ -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
|
||||||
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,,
|
||||||
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}).
|
||||||
* 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 C and C++ language specifications differ when an object is
|
||||||
|
accessed in a void context:
|
||||||
The behavior differs slightly between C and C++ in the non-obvious cases:
|
|
||||||
|
|
||||||
@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
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
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
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* { 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;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue