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]

PATCH to improve use of alias sets



Michael Tiemann provided this example today:

    typedef float vec_t;
    typedef vec_t vec3_t[3];
    typedef struct
    {
	    vec3_t		viewoffset;
    } ps_t;
    typedef struct gc_s
    {
	    ps_t	ps;
    } gc_t;
    struct ed_s
    {
	    struct gc_s	*client;
    };
    typedef struct ed_s ed_t;

    void foo1 (ed_t *ent)
    {
       vec3_t v;
       struct gc_s *client;

       bar (v);

       client = ent->client;

       client->ps.viewoffset[0] = v[0];
       client->ps.viewoffset[1] = v[1];
       client->ps.viewoffset[2] = v[2];
    }

    void foo2 (ed_t *ent)
    {
       vec3_t v;

       bar (v);

       ent->client->ps.viewoffset[0] = v[0];
       ent->client->ps.viewoffset[1] = v[1];
       ent->client->ps.viewoffset[2] = v[2];
    }

Here, the code for `foo1' was better than that for `foo2'; in the
latter `ent->client' was reloaded on each access, despite the fact
that stores into `viewoffset[i]' are to floats, and therefore cannot
possibly affent `ent->client' which is a `struct gs*'.

It turns out that we weren't threading alias sets through to
store_field.  This patch fixes this, thereby eliminating the redundant
loads in `foo2', and presumably increasing the usefulness of the
alias-set optimizations.  I verified that no new test failures occur
after bootstrapping with this patch on x86-linux-gnu.

At the same time, I tweaked c_get_alias_set a bit; type-punning was
not handled quite right.  Also, alias sets for ARRAY_TYPEs were
incorrect; that doesn't matter yet, but might at some point in the
future.

Jeff, OK?

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

Mon Sep 21 12:46:22 1998  Mark Mitchell  <mark@markmitchell.com>

	* c-common.c (c_get_alias_set): Tighten slightly for FUNCTION_TYPEs
	and ARRAY_TYPEs.  Tidy up.  Improve support for type-punning. 
	* expr.c (store_field): Add alias_set parameter.  Set the
	MEM_ALIAS_SET accordingly, if the target is a MEM.
	(expand_assignment): Use it.
	(store_constructor_field): Pass 0.
	(expand_expr): Likewise.
	
Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.33
diff -c -p -r1.33 c-common.c
*** c-common.c	1998/09/20 23:54:07	1.33
--- c-common.c	1998/09/21 19:48:40
*************** c_get_alias_set (t)
*** 2990,3003 ****
      return 0;
  
    type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
!     ? t :  TREE_TYPE (t);
  
    if (type == error_mark_node)
      return 0;
  
!   if (TYPE_ALIAS_SET_KNOWN_P (type))
!     /* If we've already calculated the value, just return it.  */
!     return TYPE_ALIAS_SET (type);
  
    if (TREE_CODE (t) == BIT_FIELD_REF)
      /* Perhaps reads and writes to this piece of data alias fields
--- 2990,3002 ----
      return 0;
  
    type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
!     ? t : TREE_TYPE (t);
  
    if (type == error_mark_node)
      return 0;
  
!   /* Deal with special cases first; for certain kinds of references
!      we're interested in more than just the type.  */
  
    if (TREE_CODE (t) == BIT_FIELD_REF)
      /* Perhaps reads and writes to this piece of data alias fields
*************** c_get_alias_set (t)
*** 3005,3010 ****
--- 3004,3010 ----
         let's just assume that bitfields can alias everything, which is
         the conservative assumption.  */
      return 0;
+ 
    if (TREE_CODE (t) == COMPONENT_REF
        && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE)
      /* Permit type-punning when accessing a union, provided the
*************** c_get_alias_set (t)
*** 3014,3026 ****
         GCC extension, albeit a common and useful one; the C standard
         says that such accesses have implementation-defined behavior.  */ 
      return 0;
    else if (TYPE_MAIN_VARIANT (type) != type)
!     {
!       /* The C standard specifically allows aliasing between
! 	 cv-qualified variants of types.  */
!       TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
!       return TYPE_ALIAS_SET (type);
!     }
    else if (TREE_CODE (type) == INTEGER_TYPE)
      {
        tree signed_variant;
--- 3014,3029 ----
         GCC extension, albeit a common and useful one; the C standard
         says that such accesses have implementation-defined behavior.  */ 
      return 0;
+ 
+   /* From here on, only the type matters.  */
+ 
+   if (TYPE_ALIAS_SET_KNOWN_P (type))
+     /* If we've already calculated the value, just return it.  */
+     return TYPE_ALIAS_SET (type);
    else if (TYPE_MAIN_VARIANT (type) != type)
!     /* The C standard specifically allows aliasing between
!        cv-qualified variants of types.  */
!     TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
    else if (TREE_CODE (type) == INTEGER_TYPE)
      {
        tree signed_variant;
*************** c_get_alias_set (t)
*** 3031,3064 ****
        signed_variant = signed_type (type);
  
        if (signed_variant != type)
! 	{
! 	  TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
! 	  return TYPE_ALIAS_SET (type);
! 	}
        else if (signed_variant == signed_char_type_node)
  	/* The C standard guarantess that any object may be accessed
  	   via an lvalue that has character type.  We don't have to
  	   check for unsigned_char_type_node or char_type_node because
  	   we are specifically looking at the signed variant.  */
! 	{
! 	  TYPE_ALIAS_SET (type) = 0;
! 	  return TYPE_ALIAS_SET (type);
! 	}
      }
    else if (TREE_CODE (type) == RECORD_TYPE
  	   || TREE_CODE (type) == UNION_TYPE)
!     {
!       /* If TYPE is a struct or union type then we're reading or
! 	 writing an entire struct.  Thus, we don't know anything about
! 	 aliasing.  (In theory, such an access can only alias objects
! 	 whose type is the same as one of the fields, recursively, but
! 	 we don't yet make any use of that information.)  */
!       TYPE_ALIAS_SET (type) = 0;
!       return TYPE_ALIAS_SET (type);
!     }
  
-   /* TYPE is something we haven't seen before.  Put it in a new alias
-      set.  */
-   TYPE_ALIAS_SET (type) = new_alias_set ();
    return TYPE_ALIAS_SET (type);
  }
--- 3034,3070 ----
        signed_variant = signed_type (type);
  
        if (signed_variant != type)
! 	TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
        else if (signed_variant == signed_char_type_node)
  	/* The C standard guarantess that any object may be accessed
  	   via an lvalue that has character type.  We don't have to
  	   check for unsigned_char_type_node or char_type_node because
  	   we are specifically looking at the signed variant.  */
! 	TYPE_ALIAS_SET (type) = 0;
      }
+   else if (TREE_CODE (type) == ARRAY_TYPE)
+     /* Anything that can alias one of the array elements can alias
+        the entire array as well.  */
+     TYPE_ALIAS_SET (type) = c_get_alias_set (TREE_TYPE (type));
+   else if (TREE_CODE (type) == FUNCTION_TYPE)
+     /* There are no objects of FUNCTION_TYPE, so there's no point in
+        using up an alias set for them.  (There are, of course,
+        pointers and references to functions, but that's 
+        different.)  */
+     TYPE_ALIAS_SET (type) = 0;
    else if (TREE_CODE (type) == RECORD_TYPE
  	   || TREE_CODE (type) == UNION_TYPE)
!     /* If TYPE is a struct or union type then we're reading or
!        writing an entire struct.  Thus, we don't know anything about
!        aliasing.  (In theory, such an access can only alias objects
!        whose type is the same as one of the fields, recursively, but
!        we don't yet make any use of that information.)  */
!     TYPE_ALIAS_SET (type) = 0;
! 
!   if (!TYPE_ALIAS_SET_KNOWN_P (type)) 
!     /* TYPE is something we haven't seen before.  Put it in a new
!        alias set.  */
!     TYPE_ALIAS_SET (type) = new_alias_set ();
  
    return TYPE_ALIAS_SET (type);
  }
Index: expr.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/expr.c,v
retrieving revision 1.96
diff -c -p -r1.96 expr.c
*** expr.c	1998/09/15 19:18:52	1.96
--- expr.c	1998/09/21 19:49:15
*************** static void store_constructor_field PROT
*** 168,174 ****
  					   tree, tree, int));
  static void store_constructor	PROTO((tree, rtx, int));
  static rtx store_field		PROTO((rtx, int, int, enum machine_mode, tree,
! 				       enum machine_mode, int, int, int));
  static enum memory_use_mode
    get_memory_usage_from_modifier PROTO((enum expand_modifier));
  static tree save_noncopied_parts PROTO((tree, tree));
--- 168,175 ----
  					   tree, tree, int));
  static void store_constructor	PROTO((tree, rtx, int));
  static rtx store_field		PROTO((rtx, int, int, enum machine_mode, tree,
! 				       enum machine_mode, int, int,
! 				       int, int));
  static enum memory_use_mode
    get_memory_usage_from_modifier PROTO((enum expand_modifier));
  static tree save_noncopied_parts PROTO((tree, tree));
*************** expand_assignment (to, from, want_value,
*** 3223,3229 ****
  			    unsignedp,
  			    /* Required alignment of containing datum.  */
  			    alignment,
! 			    int_size_in_bytes (TREE_TYPE (tem)));
        preserve_temp_slots (result);
        free_temp_slots ();
        pop_temp_slots ();
--- 3224,3231 ----
  			    unsignedp,
  			    /* Required alignment of containing datum.  */
  			    alignment,
! 			    int_size_in_bytes (TREE_TYPE (tem)),
! 			    get_alias_set (to));
        preserve_temp_slots (result);
        free_temp_slots ();
        pop_temp_slots ();
*************** store_constructor_field (target, bitsize
*** 3805,3811 ****
    else
      store_field (target, bitsize, bitpos, mode, exp,
  		 VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
! 		 int_size_in_bytes (type));
  }
  
  /* Store the value of constructor EXP into the rtx TARGET.
--- 3807,3813 ----
    else
      store_field (target, bitsize, bitpos, mode, exp,
  		 VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
! 		 int_size_in_bytes (type), 0);
  }
  
  /* Store the value of constructor EXP into the rtx TARGET.
*************** store_constructor (exp, target, cleared)
*** 4355,4365 ****
     In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
  
     ALIGN is the alignment that TARGET is known to have, measured in bytes.
!    TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.  */
  
  static rtx
  store_field (target, bitsize, bitpos, mode, exp, value_mode,
! 	     unsignedp, align, total_size)
       rtx target;
       int bitsize, bitpos;
       enum machine_mode mode;
--- 4357,4371 ----
     In this case, UNSIGNEDP must be nonzero if the value is an unsigned type.
  
     ALIGN is the alignment that TARGET is known to have, measured in bytes.
!    TOTAL_SIZE is the size in bytes of the structure, or -1 if varying.  
  
+    ALIAS_SET is the alias set for the destination.  This value will
+    (in general) be different from that for TARGET, since TARGET is a
+    reference to the containing structure.  */
+ 
  static rtx
  store_field (target, bitsize, bitpos, mode, exp, value_mode,
! 	     unsignedp, align, total_size, alias_set)
       rtx target;
       int bitsize, bitpos;
       enum machine_mode mode;
*************** store_field (target, bitsize, bitpos, mo
*** 4368,4373 ****
--- 4374,4380 ----
       int unsignedp;
       int align;
       int total_size;
+      int alias_set;
  {
    HOST_WIDE_INT width_mask = 0;
  
*************** store_field (target, bitsize, bitpos, mo
*** 4403,4409 ****
  	emit_move_insn (object, target);
  
        store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
! 		   align, total_size);
  
        /* Even though we aren't returning target, we need to
  	 give it the updated value.  */
--- 4410,4416 ----
  	emit_move_insn (object, target);
  
        store_field (blk_object, bitsize, bitpos, mode, exp, VOIDmode, 0,
! 		   align, total_size, alias_set);
  
        /* Even though we aren't returning target, we need to
  	 give it the updated value.  */
*************** store_field (target, bitsize, bitpos, mo
*** 4518,4523 ****
--- 4525,4531 ----
  							(bitpos
  							 / BITS_PER_UNIT))));
        MEM_IN_STRUCT_P (to_rtx) = 1;
+       MEM_ALIAS_SET (to_rtx) = alias_set;
  
        return store_expr (exp, to_rtx, value_mode != VOIDmode);
      }
*************** expand_expr (exp, target, tmode, modifie
*** 6584,6590 ****
  	    store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
  			 TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
  			 VOIDmode, 0, 1,
! 			 int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))));
  	  else
  	    abort ();
  
--- 6592,6599 ----
  	    store_field (target, GET_MODE_BITSIZE (TYPE_MODE (valtype)), 0,
  			 TYPE_MODE (valtype), TREE_OPERAND (exp, 0),
  			 VOIDmode, 0, 1,
! 			 int_size_in_bytes (TREE_TYPE (TREE_OPERAND (exp, 0))),
! 			 0);
  	  else
  	    abort ();
  


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