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: [PATCH] Fix PR middle-end/26306


> I'll not object to such a patch.  In fact, I'll pre-approve it, on one
> condition: fill in the section in the manual about implementation of C
> with respect to "qualifiers implementation" to explain under what
> conditions we generate an access to a volatile lvalue whose value is not
> otherwise required.  If we're going to restore this behavior, and you
> think it ought to be preserved in future, we ought to document it.

Agreed, this will be easier to read than the RTL expander in any cases.  
Moreover I think we should also make the "When is a Volatile Object Accessed" 
section for the C++ compiler reference this new section.  Patch attached.

> I'm not trying to be cute; I really do think those are the reasonable
> choices, if we want to preserve this behavior for the foreseeable future.

The Ada compiler happens to rely on this behavior of the middle-end for proper 
operation, so we certainly are interested in preserving it. :-)

-- 
Eric Botcazou
Index: gimplify.c
===================================================================
--- gimplify.c	(revision 118753)
+++ gimplify.c	(working copy)
@@ -5854,7 +5854,8 @@ gimplify_expr (tree *expr_p, tree *pre_p
 			     gimple_test_f, fallback);
 	      break;
 
-	    case ARRAY_REF: case ARRAY_RANGE_REF:
+	    case ARRAY_REF:
+	    case ARRAY_RANGE_REF:
 	      gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
 			     gimple_test_f, fallback);
 	      gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
@@ -5863,16 +5864,17 @@ gimplify_expr (tree *expr_p, tree *pre_p
 
 	    default:
 	       /* Anything else with side-effects must be converted to
-	       	  a valid statement before we get here.  */
+		  a valid statement before we get here.  */
 	      gcc_unreachable ();
 	    }
 
 	  *expr_p = NULL;
 	}
-      else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
+      else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p))
+	       && TYPE_MODE (TREE_TYPE (*expr_p)) != BLKmode)
 	{
-	  /* Historically, the compiler has treated a bare
-	     reference to a volatile lvalue as forcing a load.  */
+	  /* Historically, the compiler has treated a bare reference
+	     to a non-BLKmode volatile lvalue as forcing a load.  */
 	  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
 	  /* Normally, we do not want to create a temporary for a
 	     TREE_ADDRESSABLE type because such a type should not be
@@ -5887,7 +5889,10 @@ gimplify_expr (tree *expr_p, tree *pre_p
 	}
       else
 	/* We can't do anything useful with a volatile reference to
-	   incomplete type, so just throw it away.  */
+	   an incomplete type, so just throw it away.  Likewise for
+	   a BLKmode type, since any implicit inner load should
+	   already have been turned into an explicit one by the
+	   gimplification process.  */
 	*expr_p = NULL;
     }
 
Index: doc/implement-c.texi
===================================================================
--- doc/implement-c.texi	(revision 118753)
+++ doc/implement-c.texi	(working copy)
@@ -503,7 +503,40 @@ determined by the ABI@.
 @cite{What constitutes an access to an object that has volatile-qualified
 type (C90 6.5.3, C99 6.7.3).}
 
-@xref{Volatiles, , When is a Volatile Object Accessed?}.
+Such an object is normally accessed by pointers and used for accessing
+hardware.  In most expressions, it is intuitively obvious what is a read
+and what is a write.  For instance
+
+@smallexample
+volatile int *dst = @var{somevalue};
+volatile int *src = @var{someothervalue};
+*dst = *src;
+@end smallexample
+
+@noindent
+will cause a read of the volatile object pointed to by @var{src} and store the
+value into the volatile object pointed to by @var{dst}.  There is no
+guarantee that these reads and writes are atomic, especially for objects
+larger than @code{int}.
+
+Less obvious expressions are where something which looks like an access
+is used in a void context.  An example would be
+
+@smallexample
+volatile int *src = @var{somevalue};
+*src;
+@end smallexample
+
+According to (C90 ?, C99 6.3.2.1), such an expression is an rvalue whose
+type is the unqualified version of its original type, i.e. @code{int}.
+Whether GCC interprets this as a read of the volatile object being pointed
+to or only as a request to evaluate the expression for its side-effects
+depends on this unqualified version of the original type.
+
+If it is a scalar type, or an aggregate type whose only member object is
+of a scalar type, or a union type whose member objects are of scalar types,
+the expression is interpreted by GCC as a read of the volatile object; in
+the other cases, the expression is only evaluated for its side-effects.
 
 @end itemize
 
Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 118753)
+++ doc/extend.texi	(working copy)
@@ -10433,11 +10433,10 @@ Predefined Macros,cpp,The GNU C Preproce
 
 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 that it might perform on
-non-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
+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
@@ -10447,55 +10446,28 @@ for accesses across a sequence point.  T
 allow you to violate the restriction on updating objects multiple times
 within a sequence point.
 
-In most expressions, it is intuitively obvious what is a read and what is
-a write.  For instance
+@xref{Qualifiers implementation, , Volatile qualifier and the C compiler}.
 
-@smallexample
-volatile int *dst = @var{somevalue};
-volatile int *src = @var{someothervalue};
-*dst = *src;
-@end smallexample
-
-@noindent
-will cause a read of the volatile object pointed to by @var{src} and stores the
-value into the volatile object pointed to by @var{dst}.  There is no
-guarantee that these reads and writes are atomic, especially for objects
-larger than @code{int}.
-
-Less obvious expressions are where something which looks like an access
-is used in a void context.  An example would be,
+The behavior differs slightly between C and C++ in the non-obvious cases:
 
 @smallexample
 volatile int *src = @var{somevalue};
 *src;
 @end smallexample
 
-With C, such expressions are rvalues, and as rvalues cause a read of
-the object, GCC interprets this as a read of the volatile being pointed
-to.  The C++ standard specifies that such expressions do not undergo
-lvalue to rvalue conversion, and that the type of the dereferenced
+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 is responsible for
+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 in a void context as a read
-of the object.  When the object has incomplete type, G++ issues a
-warning.
-
-@smallexample
-struct S;
-struct T @{int m;@};
-volatile S *ptr1 = @var{somevalue};
-volatile T *ptr2 = @var{somevalue};
-*ptr1;
-*ptr2;
-@end smallexample
-
-In this example, a warning is issued for @code{*ptr1}, and @code{*ptr2}
-causes a read of the object pointed to.  If you wish to force an error on
-the first case, you must force a conversion to rvalue with, for instance
-a static cast, @code{static_cast<S>(*ptr1)}.
+pointer to volatile object of complete type in a void context like GCC
+would do it for an equivalent C type.  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

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