gcc/
authornathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 20 Aug 2010 12:22:11 +0000 (12:22 +0000)
committernathan <nathan@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 20 Aug 2010 12:22:11 +0000 (12:22 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@163400 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/doc/extend.texi
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/volatile-2.c [new file with mode: 0644]

index 508c476..a12d21b 100644 (file)
@@ -66,6 +66,7 @@ extensions, accepted by GCC in C90 mode and in C++.
 * Type Attributes::     Specifying attributes of types.
 * Alignment::           Inquiring about the alignment of a type or variable.
 * 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.
                         (With them you can define ``built-in'' functions.)
 * 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
 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
 @section Assembler Instructions with C Expression Operands
 @cindex extended @code{asm}
@@ -13152,7 +13235,7 @@ test specifically for GNU C++ (@pxref{Common Predefined Macros,,
 Predefined Macros,cpp,The GNU C Preprocessor}).
 
 @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.
 * Vague Linkage::       Where G++ puts inlines, vtables and such.
 * 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++.
 @end menu
 
-@node Volatiles
-@section When is a Volatile Object Accessed?
+@node C++ Volatiles
+@section When is a Volatile C++ Object Accessed?
 @cindex accessing volatiles
 @cindex volatile read
 @cindex volatile write
 @cindex volatile access
 
-Both the C and C++ standard have the concept of volatile objects.  These
-are normally accessed by pointers and used for accessing hardware.  The
-standards encourage compilers to refrain from optimizations concerning
-accesses to volatile objects.  The C standard leaves it implementation
-defined  as to what constitutes a volatile access.  The C++ standard omits
-to specify this, except to say that C++ should behave in a similar manner
-to C with respect to volatiles, where possible.  The minimum either
-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++ standard differs from the C standard in its treatment of
+volatile objects.  It fails to specify what constitutes a volatile
+access, except to say that C++ should behave in a similar manner to C
+with respect to volatiles, where possible.  However, the different
+lvalueness of expressions between C and C++ complicate the behaviour.
+G++ behaves the same as GCC for volatile access, @xref{C
+Extensions,,Volatiles}, for a description of GCC's behaviour.
 
-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
 volatile int *src = @var{somevalue};
 *src;
 @end smallexample
 
-With C, such expressions are rvalues, and GCC interprets this either as a
-read of the volatile object being pointed to or only as request to evaluate
-the side-effects.  The C++ standard specifies that such expressions do not
-undergo lvalue to rvalue conversion, and that the type of the dereferenced
-object may be incomplete.  The C++ standard does not specify explicitly
-that it is this lvalue to rvalue conversion which may be responsible for
-causing an access.  However, there is reason to believe that it is,
-because otherwise certain simple expressions become undefined.  However,
-because it would surprise most programmers, G++ treats dereferencing a
-pointer to volatile object of complete type when the value is unused as
-GCC would do for an equivalent type in C@.  When the object has incomplete
-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.
+The C++ standard specifies that such expressions do not undergo lvalue
+to rvalue conversion, and that the type of the dereferenced object may
+be incomplete.  The C++ standard does not specify explicitly that it
+is lvalue to rvalue conversion which is responsible for causing an
+access.  There is reason to believe that it is, because otherwise
+certain simple expressions become undefined.  However, because it
+would surprise most programmers, G++ treats dereferencing a pointer to
+volatile object of complete type as GCC would do for an equivalent
+type in C@.  When the object has incomplete 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
 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
 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
 @section Restricting Pointer Aliasing
 @cindex restricted pointers
index 7e33666..6b654be 100644 (file)
@@ -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);
    }
 
+  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)
     {
       /* 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)
     {
-      *expr_p = unshare_expr (*to_p);
+      *expr_p = TREE_THIS_VOLATILE (*to_p) ? *from_p : unshare_expr (*to_p);
       return GS_OK;
     }
   else
index be71700..7d15024 100644 (file)
@@ -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>
 
        PR rtl-optimization/44691
diff --git a/gcc/testsuite/gcc.target/i386/volatile-2.c b/gcc/testsuite/gcc.target/i386/volatile-2.c
new file mode 100644 (file)
index 0000000..3f4d425
--- /dev/null
@@ -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;
+}