C++ PATCH: Restricted this pointers

Nathan Sidwell nathan@acm.org
Wed Nov 17 03:06:00 GMT 1999


hi,
Here's a patch which allows restricted this pointers with the following
method function qualifier syntax
        X::fn () __restrict__
The restrict qualifier is applied to the pointer rather than the object
(as volatile and const are). This extention is, I beleive, compatible
with other compilers which implement restrict (EDG for example). Yonks
ago there was some discussion on the list about this, and IIR, the
consensus was the above syntax.

Because toplevel qualifiers are ignored on function parameters in
overload matching, I do the same with restrict. So just as one can have
the following
        void fn (int);
        void fn (int const arg) {...};
one can have
        struct X {void fn();}
        void X::fn () __restrict__ {...};

I altered grok_method_quals (decl2.c) to return the outermost
qualifiers (normally TYPE_UNQUALIFIED). The previous return value of
the qualified class type (X const or whatever), was only used in
grokdeclarator, and that needed to peek into a dummy FUNCTION_DECL to
get the method type as well. So it can just peek a bit more and get the
qualified class type. Then grokclassfn applies the outermost qualifiers
in constructing a PARM_DECL for `this'. I also cleaned up grokclassfn
which tracked some unused values. There's no need to alter the error
reporting functions, as the qualifier never appears in the prototype.

A new node in extend.texi describes the C++ syntax for restricted
pointers, references and this pointers.

ok?

In examining the (i86) assembly output, I'm a bit confused about the
semantics of restricted pointers, which I thought I understood from
the c9x restricted pointer proposal (refreshed at
http://www.cuj.com/archive/1707/feature.html ).
I tried the following snippet

        int fn1 (int *ptr1, int *ptr2)
        {
          *ptr1 = 5;
          *ptr2 = 7;
          return *ptr1;
        }

and then applied __restrict__ to either ptr1, ptr2 or both. I expected
that if either was restricted, there would be no reload of *ptr1 to
determine the return value, and so constant propagation would directly
give the return value 5. However, it was only when both ptr1 and ptr2
were restricted, did this occur. (Of courese this is permitted, but
is not taking full advantage of restrict.)

Then I tried the above using the following struct
        struct X
        {
          int m;
        };
rather than ints. I expected the same results when accessing `m' as the
plain int cases. However, in no case was the final reload squashed.
My wild supposition about this is that,
        ptr1->m
gets turned into
        *(ptr1 + offset of m)
and that doesn't inherit the restrictedness of ptr1. This behaviour
makes restrict less useful on classes than one might hope.

<more wild guessing>
I guess each member of a structure pointed to by a restricted pointer
should be placed in its own alias set. So the lvalue
        ptr1->m
should be in alias set ptr1_m (for want of a name), and therefore not
alias ptr2->m, which would be in alias set ptr2_m (if ptr2 is
restricted), or alias set int, (for a non-restricted ptr2). Of course
the alias set would have to be as long-lived as ptr1, rather than
generated anew at each structure access (doing that would place two
occurances of ptr1->m in different alias sets).
</more wild guessing>

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
Never hand someone a gun unless you are sure where they will point it
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
1999-11-17  Nathan Sidwell  <nathan@acm.org>

	* extend.texi: Document C++ restricted pointers and references.
	
1999-11-17  Nathan Sidwell  <nathan@acm.org>

	* cp-tree.h (grok_method_quals): Return this pointer qualifiers.
	* decl.c (grokdeclarator): Adjust calls to grok_method_quals.
	* decl2.c (grok_method_quals): Accept `restrict' as applying to
	the object pointer. Return such qualifiers.
	(grokclassfn): Apply this pointer qualifiers. Cleanup unused
	variables.

Index: extend.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/extend.texi,v
retrieving revision 1.39
diff -c -3 -p -r1.39 extend.texi
*** extend.texi	1999/11/10 07:53:20	1.39
--- extend.texi	1999/11/17 09:32:12
*************** Predefined Macros,cpp.info,The C Preproc
*** 3219,3224 ****
--- 3219,3225 ----
  * Naming Results::      Giving a name to C++ function return values.
  * Min and Max::		C++ Minimum and maximum operators.
  * Volatiles::		What constitutes an access to a volatile object.
+ * Restricted Pointers:: C9X restricted pointers and references.
  * C++ Interface::       You can use a single C++ header file for both
                           declarations and definitions.
  * Template Instantiation:: Methods for ensuring that exactly one copy of
*************** becomes difficult to determine where vol
*** 3465,3470 ****
--- 3466,3520 ----
  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.
+ 
+ @node Restricted Pointers
+ @section Restricting Pointer Aliasing
+ @cindex restricted pointers
+ @cindex restricted references
+ @cindex restricted this pointer
+ 
+ As with gcc, g++ understands the C9X proposal of restricted pointers,
+ specified with the @code{__restrict__}, or @code{__restrict} type
+ qualifier. Because you cannot compile C++ by specifying the -flang-isoc9x
+ language flag, @code{restrict} is not a keyword in C++.
+ 
+ In addition to allowing restricted pointers, you can specify restricted
+ references, which indicate that the reference is not aliased in the local
+ context.
+ 
+ @example
+ void fn (int *__restrict__ rptr, int &__restrict__ rref)
+ @{
+   @dots{}
+ @}
+ @end example
+ 
+ @noindent
+ In the body of @code{fn}, @var{rptr} points to an unaliased integer and
+ @var{rref} refers to a (different) unaliased integer.
+ 
+ You may also specify whether a member function's @var{this} pointer is
+ unaliased by using @code{__restrict__} as a member function qualifier.
+ 
+ @example
+ void T::fn () __restrict__
+ @{
+   @dots{}
+ @}
+ @end example
+ 
+ @noindent
+ Within the body of @code{T::fn}, @var{this} will have the effective
+ definition @code{T *__restrict__ const this}. Notice that the
+ interpretation of a @code{__restrict__} member function qualifier is
+ different to that of @code{const} or @code{volatile} qualifier, in that it
+ is applied to the pointer rather than the object. This is consistent with
+ other compilers which implement restricted pointers.
+ 
+ As with all outermost parameter qualifiers, @code{__restrict__} is
+ ignored in function definition matching. This means you only need to
+ specify @code{__restrict__} in a function definition, rather than
+ in a function prototype as well.
  
  @node C++ Interface
  @section Declarations and Definitions in One Header
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.350
diff -c -3 -p -r1.350 cp-tree.h
*** cp-tree.h	1999/11/16 05:58:53	1.350
--- cp-tree.h	1999/11/17 09:32:17
*************** extern void make_rtl_for_local_static   
*** 3529,3535 ****
  extern void init_decl2				PROTO((void));
  extern int check_java_method			PROTO((tree));
  extern int lang_decode_option			PROTO((int, char **));
! extern tree grok_method_quals			PROTO((tree, tree, tree));
  extern void warn_if_unknown_interface		PROTO((tree));
  extern void grok_x_components			PROTO((tree));
  extern void maybe_retrofit_in_chrg		PROTO((tree));
--- 3529,3535 ----
  extern void init_decl2				PROTO((void));
  extern int check_java_method			PROTO((tree));
  extern int lang_decode_option			PROTO((int, char **));
! extern int grok_method_quals			PROTO((tree, tree, tree));
  extern void warn_if_unknown_interface		PROTO((tree));
  extern void grok_x_components			PROTO((tree));
  extern void maybe_retrofit_in_chrg		PROTO((tree));
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.505
diff -c -3 -p -r1.505 decl.c
*** decl.c	1999/11/16 05:58:53	1.505
--- decl.c	1999/11/17 09:32:27
*************** create_array_type_for_decl (name, type, 
*** 8919,8925 ****
     is erroneous, NULL_TREE is returned.
  
     QUALS is used only for FUNCDEF and MEMFUNCDEF cases.  For a member
!    function, these are the qualifiers to give to the `this' pointer.
  
     May return void_type_node if the declarator turned out to be a friend.
     See grokfield for details.  */
--- 8919,8926 ----
     is erroneous, NULL_TREE is returned.
  
     QUALS is used only for FUNCDEF and MEMFUNCDEF cases.  For a member
!    function, these are the qualifiers to give to the `this' pointer. We
!    apply TYPE_QUAL_RESTRICT to the this ptr, not the object.
  
     May return void_type_node if the declarator turned out to be a friend.
     See grokfield for details.  */
*************** grokdeclarator (declarator, declspecs, d
*** 9836,9843 ****
  	  if (ctype != NULL_TREE)
  	    {
  	      tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
! 	      ctype = grok_method_quals (ctype, dummy, quals);
  	      type = TREE_TYPE (dummy);
  	      quals = NULL_TREE;
  	    }
  	}
--- 9837,9845 ----
  	  if (ctype != NULL_TREE)
  	    {
  	      tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
! 	      grok_method_quals (ctype, dummy, quals);
  	      type = TREE_TYPE (dummy);
+ 	      ctype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
  	      quals = NULL_TREE;
  	    }
  	}
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.280
diff -c -3 -p -r1.280 decl2.c
*** decl2.c	1999/11/16 01:37:38	1.280
--- decl2.c	1999/11/17 09:32:30
*************** lang_decode_option (argc, argv)
*** 780,788 ****
  
  /* Incorporate `const' and `volatile' qualifiers for member functions.
     FUNCTION is a TYPE_DECL or a FUNCTION_DECL.
!    QUALS is a list of qualifiers.  */
  
! tree
  grok_method_quals (ctype, function, quals)
       tree ctype, function, quals;
  {
--- 780,790 ----
  
  /* Incorporate `const' and `volatile' qualifiers for member functions.
     FUNCTION is a TYPE_DECL or a FUNCTION_DECL.
!    QUALS is a list of qualifiers.  Returns any explicit
!    top-level qualifiers of the method's this pointer, anything other than
!    TYPE_UNQUALIFIED will be an extension.  */
  
! int
  grok_method_quals (ctype, function, quals)
       tree ctype, function, quals;
  {
*************** grok_method_quals (ctype, function, qual
*** 790,802 ****
    tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
    int type_quals = TYPE_UNQUALIFIED;
    int dup_quals = TYPE_UNQUALIFIED;
  
    do
      {
        int tq = cp_type_qual_from_rid (TREE_VALUE (quals));
        
!       if (type_quals & tq)
  	dup_quals |= tq;
        else
  	type_quals |= tq;
        quals = TREE_CHAIN (quals);
--- 792,807 ----
    tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
    int type_quals = TYPE_UNQUALIFIED;
    int dup_quals = TYPE_UNQUALIFIED;
+   int this_quals = TYPE_UNQUALIFIED;
  
    do
      {
        int tq = cp_type_qual_from_rid (TREE_VALUE (quals));
        
!       if ((type_quals | this_quals) & tq)
  	dup_quals |= tq;
+       else if (tq & TYPE_QUAL_RESTRICT)
+         this_quals |= tq;
        else
  	type_quals |= tq;
        quals = TREE_CHAIN (quals);
*************** grok_method_quals (ctype, function, qual
*** 817,823 ****
      fntype = build_exception_variant (fntype, raises);
  
    TREE_TYPE (function) = fntype;
!   return ctype;
  }
  
  /* Warn when -fexternal-templates is used and #pragma
--- 822,828 ----
      fntype = build_exception_variant (fntype, raises);
  
    TREE_TYPE (function) = fntype;
!   return this_quals;
  }
  
  /* Warn when -fexternal-templates is used and #pragma
*************** grokclassfn (ctype, function, flags, qua
*** 961,969 ****
       tree quals;
  {
    tree fn_name = DECL_NAME (function);
!   tree arg_types;
!   tree parm;
!   tree qualtype;
  
    if (fn_name == NULL_TREE)
      {
--- 966,972 ----
       tree quals;
  {
    tree fn_name = DECL_NAME (function);
!   int this_quals = TYPE_UNQUALIFIED;
  
    if (fn_name == NULL_TREE)
      {
*************** grokclassfn (ctype, function, flags, qua
*** 973,998 ****
      }
  
    if (quals)
!     qualtype = grok_method_quals (ctype, function, quals);
!   else
!     qualtype = ctype;
  
-   arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
    if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
      {
        /* Must add the class instance variable up front.  */
        /* Right now we just make this a pointer.  But later
  	 we may wish to make it special.  */
!       tree type = TREE_VALUE (arg_types);
  
!       parm = build_decl (PARM_DECL, this_identifier, type);
        /* Mark the artificial `this' parameter as "artificial".  */
        SET_DECL_ARTIFICIAL (parm);
        DECL_ARG_TYPE (parm) = type;
        /* We can make this a register, so long as we don't
  	 accidentally complain if someone tries to take its address.  */
        DECL_REGISTER (parm) = 1;
-       TREE_READONLY (parm) = 1;
        TREE_CHAIN (parm) = last_function_parms;
        last_function_parms = parm;
      }
--- 976,998 ----
      }
  
    if (quals)
!     this_quals = grok_method_quals (ctype, function, quals);
  
    if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
      {
        /* Must add the class instance variable up front.  */
        /* Right now we just make this a pointer.  But later
  	 we may wish to make it special.  */
!       tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (function)));
  
!       tree parm = build_decl (PARM_DECL, this_identifier,
!                          cp_build_qualified_type (type, this_quals | TYPE_QUAL_CONST));
        /* Mark the artificial `this' parameter as "artificial".  */
        SET_DECL_ARTIFICIAL (parm);
        DECL_ARG_TYPE (parm) = type;
        /* We can make this a register, so long as we don't
  	 accidentally complain if someone tries to take its address.  */
        DECL_REGISTER (parm) = 1;
        TREE_CHAIN (parm) = last_function_parms;
        last_function_parms = parm;
      }
*************** grokclassfn (ctype, function, flags, qua
*** 1003,1012 ****
    DECL_CLASS_CONTEXT (function) = ctype;
  
    if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))
!     {
!       maybe_retrofit_in_chrg (function);
!       arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
!     }
  
    if (flags == DTOR_FLAG)
      {
--- 1003,1009 ----
    DECL_CLASS_CONTEXT (function) = ctype;
  
    if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))
!     maybe_retrofit_in_chrg (function);
  
    if (flags == DTOR_FLAG)
      {


More information about the Gcc-patches mailing list