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]

Change to reuse of temporaries


We currently have a bug in that it's possible we can allocate a
temporary for one object, mark it with RTX_UNCHANGING_P and reallocate the
same location for an object of the same type but without RTX_UNCHANGING_P.
If the references to those objects are close enough (e.g., within the same
basic block), they can be mis-scheduled (or otherwise mis-optimized) since
they will appear not to conflict.

The solution to this problem is to only have assign_stack_for_temp set the
memory attributes of what it allocates instead of the caller.  It then
records the type used for the object and ensures that a temporary slot is
only reused for a type where objects will always conflict (perhaps the same
type).  As part of this change, as many allocations of temporary space as
possible have been converted to call assign_temp and pass a type.  If the
location will only be stored once, a readonly variant of that type is used.

I also modified safe_from_p to use the new routines I added to do a better
job of detecting cases where the input can't conflict.

Testing this is tricky.  First of all, I haven't been able to build libstdc++
and testing on only one machine isn't that useful anyway.  I've done as much
testing as I can and read the code a few times, but there's still the
possibility of a bug coming up here.

2000-12-30  Richard Kenner  <kenner@vlsi1.ultra.nyu.edu>

	* alias.c (alias_sets_conflict_p): New function.
	(mems_in_disjoint_alias_sets_p): Use it.
	(readonly_fields_p): Moved from expr.c; check for record type.
	(objects_must_conflict_p): New function.
	* calls.c (expand_call): Use assign_temp as much as possible, use
	readonly variant if assigned once, and don't set memory attributes.
	(emit_library_call_value_1, store_one_arg): Likewise.
	* integrate.c (expand_inline_function): Likewise.
	* stmt.c (expand_asm_operands, expand_return): Likewise.
	* expr.c (copy_blkmode_from_reg, store_constructor): Likewise.
	(store_field, save_noncopied_parts, expand_expr): Likewise.
	(expand_expr_unaligned): Likewise.
	(readonly_fields_p): Moved to alias.c.
	(safe_from_p): Rework handling of SAVE_EXPR.
	MEMs ony conflict if alias sets conflict; likewise for INDIRECT_REF.
	* function.c (struct temp_slot): Delete field ALIAS_SET; add TYPE.
	(assign_stack_for_temp): Use objects_must_confict_p.
	Set all memory attributes from type, if specified.
	(mark_temp_slot): Mark TYPE field.
	* tree.h (alias_sets_conflict_p, readonly_fields_p): New decls.
	(objects_must_conflict_p): Likewise.

	* stmt.c (expand_decl): Don't use assign_stack_temp in error case.
	(add_case_node): No need to copy nodes anymore.
	
*** alias.c	2000/12/15 00:04:28	1.108
--- alias.c	2000/12/29 15:57:32
*************** mems_in_disjoint_alias_sets_p (mem1, mem
*** 212,217 ****
       rtx mem2;
  {
-   alias_set_entry ase;
- 
  #ifdef ENABLE_CHECKING	
  /* Perform a basic sanity check.  Namely, that there are no alias sets
--- 212,215 ----
*************** mems_in_disjoint_alias_sets_p (mem1, mem
*** 227,271 ****
  #endif
  
!   /* If have no alias set information for one of the MEMs, we have to assume
!      it can alias anything.  */
!   if (MEM_ALIAS_SET (mem1) == 0 || MEM_ALIAS_SET (mem2) == 0)
!     return 0;
  
!   /* If the two alias sets are the same, they may alias.  */
!   if (MEM_ALIAS_SET (mem1) == MEM_ALIAS_SET (mem2))
!     return 0;
  
    /* See if the first alias set is a subset of the second.  */
!   ase = get_alias_set_entry (MEM_ALIAS_SET (mem1));
    if (ase != 0
        && (ase->has_zero_child
  	  || splay_tree_lookup (ase->children,
! 				(splay_tree_key) MEM_ALIAS_SET (mem2))))
!     return  0;
  
    /* Now do the same, but with the alias sets reversed.  */
!   ase = get_alias_set_entry (MEM_ALIAS_SET (mem2));
    if (ase != 0
        && (ase->has_zero_child
  	  || splay_tree_lookup (ase->children,
! 				(splay_tree_key) MEM_ALIAS_SET (mem1))))
!     return  0;
  
!   /* The two MEMs are in distinct alias sets, and neither one is the
       child of the other.  Therefore, they cannot alias.  */
!   return 1;
  }
  
! /* Insert the NODE into the splay tree given by DATA.  Used by
!    record_alias_subset via splay_tree_foreach.  */
  
! static int
! insert_subset_children (node, data)
!      splay_tree_node node;
!      void *data;
! {
!   splay_tree_insert ((splay_tree) data, node->key, node->value);
  
    return 0;
  }
  
--- 225,332 ----
  #endif
  
!   return ! alias_sets_conflict_p (MEM_ALIAS_SET (mem1), MEM_ALIAS_SET (mem2));
! }
  
! /* Insert the NODE into the splay tree given by DATA.  Used by
!    record_alias_subset via splay_tree_foreach.  */
  
+ static int
+ insert_subset_children (node, data)
+      splay_tree_node node;
+      void *data;
+ {
+   splay_tree_insert ((splay_tree) data, node->key, node->value);
+ 
+   return 0;
+ }
+ 
+ /* Return 1 if the two specified alias sets may conflict.  */
+ 
+ int
+ alias_sets_conflict_p (set1, set2)
+      HOST_WIDE_INT set1, set2;
+ {
+   alias_set_entry ase;
+ 
+   /* If have no alias set information for one of the operands, we have
+      to assume it can alias anything.  */
+   if (set1 == 0 || set2 == 0
+       /* If the two alias sets are the same, they may alias.  */
+       || set1 == set2)
+     return 1;
+ 
    /* See if the first alias set is a subset of the second.  */
!   ase = get_alias_set_entry (set1);
    if (ase != 0
        && (ase->has_zero_child
  	  || splay_tree_lookup (ase->children,
! 				(splay_tree_key) set2)))
!     return 1;
  
    /* Now do the same, but with the alias sets reversed.  */
!   ase = get_alias_set_entry (set2);
    if (ase != 0
        && (ase->has_zero_child
  	  || splay_tree_lookup (ase->children,
! 				(splay_tree_key) set1)))
!     return 1;
  
!   /* The two alias sets are distinct and neither one is the
       child of the other.  Therefore, they cannot alias.  */
!   return 0;
  }
+ 
+ /* Return 1 if TYPE is a RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE and has
+    has any readonly fields.  If any of the fields have types that
+    contain readonly fields, return true as well.  */
+ 
+ int
+ readonly_fields_p (type)
+      tree type;
+ {
+   tree field;
  
!   if (TREE_CODE (type) != RECORD_TYPE && TREE_CODE (type) != UNION_TYPE
!       && TREE_CODE (type) != QUAL_UNION_TYPE)
!     return 0;
  
!   for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
!     if (TREE_CODE (field) == FIELD_DECL
! 	&& (TREE_READONLY (field)
! 	    || readonly_fields_p (TREE_TYPE (field))))
!       return 1;
  
    return 0;
+ }
+ 
+ /* Return 1 if any MEM object of type T1 will always conflict (using the
+    dependency routines in this file) with any MEM object of type T2.
+    This is used when allocating temporary storage.  If T1 and/or T2 are
+    NULL_TREE, it means we know nothing about the storage.  */
+ 
+ int
+ objects_must_conflict_p (t1, t2)
+      tree t1, t2;
+ {
+   /* If they are the same type, they must conflict.  */
+   if (t1 == t2
+       /* Likewise if both are volatile.  */
+       || (t1 != 0 && TYPE_VOLATILE (t1) && t2 != 0 && TYPE_VOLATILE (t2)))
+     return 1;
+ 
+   /* We now know they are different types.  If one or both has readonly fields
+      or if one is readonly and the other not, they may not conflict.
+      Likewise if one is aggregate and the other is scalar.  */
+   if ((t1 != 0 && readonly_fields_p (t1))
+       || (t2 != 0 && readonly_fields_p (t2))
+       || ((t1 != 0 && TYPE_READONLY (t1))
+ 	  != (t2 != 0 && TYPE_READONLY (t2)))
+       || ((t1 != 0 && AGGREGATE_TYPE_P (t1))
+ 	  != (t2 != 0 && AGGREGATE_TYPE_P (t2))))
+     return 0;
+ 
+   /* Otherwise they conflict only if the alias sets conflict. */
+   return alias_sets_conflict_p (t1 ? get_alias_set (t1) : 0,
+ 				t2 ? get_alias_set (t2) : 0);
  }
  
*** calls.c	2000/12/29 04:36:00	1.170
--- calls.c	2000/12/29 15:57:45
*************** expand_call (exp, target, ignore)
*** 2261,2274 ****
  	else
  	  {
- 	    rtx d;
- 
  	    /* For variable-sized objects, we must be called with a target
  	       specified.  If we were to allocate space on the stack here,
  	       we would have no way of knowing when to free it.  */
  
- 	    if (struct_value_size < 0)
- 	      abort ();
- 
- 	    d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
  	    mark_temp_addr_taken (d);
  	    structure_value_addr = XEXP (d, 0);
--- 2261,2269 ----
  	else
  	  {
  	    /* For variable-sized objects, we must be called with a target
  	       specified.  If we were to allocate space on the stack here,
  	       we would have no way of knowing when to free it.  */
+ 	    rtx d = assign_temp (TREE_TYPE (exp), 1, 1, 1);
  
  	    mark_temp_addr_taken (d);
  	    structure_value_addr = XEXP (d, 0);
*************** expand_call (exp, target, ignore)
*** 3231,3246 ****
        else if (GET_CODE (valreg) == PARALLEL)
  	{
- 	  int bytes = int_size_in_bytes (TREE_TYPE (exp));
- 
  	  if (target == 0)
  	    {
! 	      target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)),
! 					  bytes, 0);
! 	      MEM_SET_IN_STRUCT_P (target, AGGREGATE_TYPE_P (TREE_TYPE (exp)));
  	      preserve_temp_slots (target);
  	    }
  
  	  if (! rtx_equal_p (target, valreg))
! 	    emit_group_store (target, valreg, bytes,
  			      TYPE_ALIGN (TREE_TYPE (exp)));
  
--- 3226,3243 ----
        else if (GET_CODE (valreg) == PARALLEL)
  	{
  	  if (target == 0)
  	    {
! 	      /* This will only be assigned once, so it can be readonly.  */
! 	      tree nt = build_qualified_type (TREE_TYPE (exp),
! 					      (TYPE_QUALS (TREE_TYPE (exp))
! 					       | TYPE_QUAL_CONST));
! 
! 	      target = assign_temp (nt, 0, 1, 1);
  	      preserve_temp_slots (target);
  	    }
  
  	  if (! rtx_equal_p (target, valreg))
! 	    emit_group_store (target, valreg,
! 			      int_size_in_bytes (TREE_TYPE (exp)),
  			      TYPE_ALIGN (TREE_TYPE (exp)));
  
*************** emit_library_call_value_1 (retval, orgfu
*** 3563,3567 ****
  	mem_value = value;
        else
! 	mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0);
  #endif
  
--- 3560,3564 ----
  	mem_value = value;
        else
! 	mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1);
  #endif
  
*************** emit_library_call_value_1 (retval, orgfu
*** 3667,3671 ****
  	  /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can
  	     be viewed as just an efficiency improvement.  */
! 	  rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
  	  call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
  					   gen_rtx_USE (VOIDmode, slot),
--- 3664,3669 ----
  	  /* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can
  	     be viewed as just an efficiency improvement.  */
! 	  rtx slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1);
! 
  	  call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
  					   gen_rtx_USE (VOIDmode, slot),
*************** store_one_arg (arg, argblock, flags, var
*** 4340,4352 ****
  	      if (save_mode == BLKmode)
  		{
! 		  arg->save_area = assign_stack_temp (BLKmode,
! 						      arg->size.constant, 0);
! 		  MEM_SET_IN_STRUCT_P (arg->save_area,
! 				       AGGREGATE_TYPE_P (TREE_TYPE
! 							 (arg->tree_value)));
  		  preserve_temp_slots (arg->save_area);
  		  emit_block_move (validize_mem (arg->save_area), stack_area,
! 				   GEN_INT (arg->size.constant),
! 				   PARM_BOUNDARY);
  		}
  	      else
--- 4338,4350 ----
  	      if (save_mode == BLKmode)
  		{
! 		  tree ot = TREE_TYPE (arg->tree_value);
! 		  tree nt = build_qualified_type (ot, (TYPE_QUALS (ot)
! 						       | TYPE_QUAL_CONST));
! 
! 		  arg->save_area = assign_temp (nt, 0, 1, 1);
  		  preserve_temp_slots (arg->save_area);
  		  emit_block_move (validize_mem (arg->save_area), stack_area,
! 				   expr_size (arg->tree_value),
! 				   MIN (PARM_BOUNDARY, TYPE_ALIGN (nt)));
  		}
  	      else
*** expr.c	2000/12/09 03:42:29	1.282
--- expr.c	2000/12/29 15:58:19
*************** static tree init_noncopied_parts PARAMS 
*** 182,186 ****
  static int fixed_type_p		PARAMS ((tree));
  static rtx var_rtx		PARAMS ((tree));
- static int readonly_fields_p	PARAMS ((tree));
  static rtx expand_expr_unaligned PARAMS ((tree, unsigned int *));
  static rtx expand_increment	PARAMS ((tree, int, int));
--- 182,185 ----
*************** copy_blkmode_from_reg (tgtblk, srcreg, t
*** 2146,2151 ****
    if (tgtblk == 0)
      {
!       tgtblk = assign_stack_temp (BLKmode, bytes, 0);
!       MEM_SET_IN_STRUCT_P (tgtblk, AGGREGATE_TYPE_P (type));
        preserve_temp_slots (tgtblk);
      }
--- 2145,2152 ----
    if (tgtblk == 0)
      {
!       tgtblk = assign_temp (build_qualified_type (type,
! 						  (TYPE_QUALS (type)
! 						   | TYPE_QUAL_CONST)),
! 			    0, 1, 1);
        preserve_temp_slots (tgtblk);
      }
*************** store_constructor (exp, target, align, c
*** 4922,4928 ****
  	  if (REG_P (target))
  	    {
! 	      targetx = assign_stack_temp (GET_MODE (target),
! 					   GET_MODE_SIZE (GET_MODE (target)),
! 					   0);
  	      emit_move_insn (targetx, target);
  	    }
--- 4923,4931 ----
  	  if (REG_P (target))
  	    {
! 	      targetx
! 		= assign_temp
! 		  ((build_qualified_type (type_for_mode (GET_MODE (target), 0),
! 					  TYPE_QUAL_CONST)),
! 		   0, 1, 1);
  	      emit_move_insn (targetx, target);
  	    }
*************** store_field (target, bitsize, bitpos, mo
*** 5023,5032 ****
        && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
      {
!       rtx object = assign_stack_temp (GET_MODE (target),
! 				      GET_MODE_SIZE (GET_MODE (target)), 0);
        rtx blk_object = copy_rtx (object);
  
-       MEM_SET_IN_STRUCT_P (object, 1);
-       MEM_SET_IN_STRUCT_P (blk_object, 1);
        PUT_MODE (blk_object, BLKmode);
  
--- 5026,5036 ----
        && (GET_CODE (target) == REG || GET_CODE (target) == SUBREG))
      {
!       rtx object
! 	= assign_temp
! 	  (build_qualified_type (type_for_mode (GET_MODE (target), 0),
! 				 TYPE_QUAL_CONST),
! 	   0, 1, 1);
        rtx blk_object = copy_rtx (object);
  
        PUT_MODE (blk_object, BLKmode);
  
*************** save_noncopied_parts (lhs, list)
*** 5507,5511 ****
  	tree part_type = TREE_TYPE (part);
  	tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
! 	rtx target = assign_temp (part_type, 0, 1, 1);
  	if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
  	  target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
--- 5511,5520 ----
  	tree part_type = TREE_TYPE (part);
  	tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
! 	rtx target
! 	  = assign_temp (build_qualified_type (part_type,
! 					       (TYPE_QUALS (part_type)
! 						| TYPE_QUAL_CONST)),
! 			 0, 1, 1);
! 
  	if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
  	  target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
*************** safe_from_p (x, exp, top_p)
*** 5560,5567 ****
    rtx exp_rtl = 0;
    int i, nops;
!   static int save_expr_count;
!   static int save_expr_size = 0;
!   static tree *save_expr_rewritten;
!   static tree save_expr_trees[256];
  
    if (x == 0
--- 5569,5573 ----
    rtx exp_rtl = 0;
    int i, nops;
!   static tree save_expr_list;
  
    if (x == 0
*************** safe_from_p (x, exp, top_p)
*** 5578,5606 ****
  	      || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
  	      != INTEGER_CST)
! 	  && GET_MODE (x) == BLKmode))
      return 1;
  
-   if (top_p && save_expr_size == 0)
-     {
-       int rtn;
- 
-       save_expr_count = 0;
-       save_expr_size = ARRAY_SIZE (save_expr_trees);
-       save_expr_rewritten = &save_expr_trees[0];
- 
-       rtn = safe_from_p (x, exp, 1);
- 
-       for (i = 0; i < save_expr_count; ++i)
- 	{
- 	  if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
- 	    abort ();
- 	  TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
- 	}
- 
-       save_expr_size = 0;
- 
-       return rtn;
-     }
- 
    /* If this is a subreg of a hard register, declare it unsafe, otherwise,
       find the underlying pseudo.  */
--- 5584,5595 ----
  	      || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
  	      != INTEGER_CST)
! 	  && GET_MODE (x) == BLKmode)
!       /* If X is in the outgoing argument area, it is always safe.  */
!       || (GET_CODE (x) == MEM
! 	  && (XEXP (x, 0) == virtual_outgoing_args_rtx
! 	      || (GET_CODE (XEXP (x, 0)) == PLUS
! 		  && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx))))
      return 1;
  
    /* If this is a subreg of a hard register, declare it unsafe, otherwise,
       find the underlying pseudo.  */
*************** safe_from_p (x, exp, top_p)
*** 5612,5622 ****
      }
  
!   /* If X is a location in the outgoing argument area, it is always safe.  */
!   if (GET_CODE (x) == MEM
!       && (XEXP (x, 0) == virtual_outgoing_args_rtx
! 	  || (GET_CODE (XEXP (x, 0)) == PLUS
! 	      && XEXP (XEXP (x, 0), 0) == virtual_outgoing_args_rtx)))
!     return 1;
  
    switch (TREE_CODE_CLASS (TREE_CODE (exp)))
      {
--- 5601,5629 ----
      }
  
!   /* A SAVE_EXPR might appear many times in the expression passed to the
!      top-level safe_from_p call, and if it has a complex subexpression,
!      examining it multiple times could result in a combinatorial explosion.
!      E.g. on an Alpha running at least 200MHz, a Fortran test case compiled
!      with optimization took about 28 minutes to compile -- even though it was
!      only a few lines long.  So we mark each SAVE_EXPR we see with TREE_PRIVATE
!      and turn that off when we are done.  We keep a list of the SAVE_EXPRs
!      we have processed.  Note that the only test of top_p was above.  */
! 
!   if (top_p)
!     {
!       int rtn;
!       tree t;
! 
!       save_expr_list = 0;
! 
!       rtn = safe_from_p (x, exp, 0);
! 
!       for (t = save_expr_list; t != 0; t = TREE_CHAIN (t))
! 	TREE_PRIVATE (TREE_PURPOSE (t)) = 0;
! 
!       return rtn;
!     }
  
+   /* Now look at our tree code and possibly recurse.  */
    switch (TREE_CODE_CLASS (TREE_CODE (exp)))
      {
*************** safe_from_p (x, exp, top_p)
*** 5658,5666 ****
  	case ADDR_EXPR:
  	  return (staticp (TREE_OPERAND (exp, 0))
! 		  || safe_from_p (x, TREE_OPERAND (exp, 0), 0)
! 		  || TREE_STATIC (exp));
  
  	case INDIRECT_REF:
! 	  if (GET_CODE (x) == MEM)
  	    return 0;
  	  break;
--- 5665,5675 ----
  	case ADDR_EXPR:
  	  return (staticp (TREE_OPERAND (exp, 0))
! 		  || TREE_STATIC (exp)
! 		  || safe_from_p (x, TREE_OPERAND (exp, 0), 0));
  
  	case INDIRECT_REF:
! 	  if (GET_CODE (x) == MEM
! 	      && alias_sets_conflict_p (MEM_ALIAS_SET (x),
! 					get_alias_set (exp)))
  	    return 0;
  	  break;
*************** safe_from_p (x, exp, top_p)
*** 5696,5730 ****
  	    break;
  
! 	  /* This SAVE_EXPR might appear many times in the top-level
! 	     safe_from_p() expression, and if it has a complex
! 	     subexpression, examining it multiple times could result
! 	     in a combinatorial explosion.  E.g. on an Alpha
! 	     running at least 200MHz, a Fortran test case compiled with
! 	     optimization took about 28 minutes to compile -- even though
! 	     it was only a few lines long, and the complicated line causing
! 	     so much time to be spent in the earlier version of safe_from_p()
! 	     had only 293 or so unique nodes.
! 
! 	     So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember
! 	     where it is so we can turn it back in the top-level safe_from_p()
! 	     when we're done.  */
  
! 	  /* For now, don't bother re-sizing the array.  */
! 	  if (save_expr_count >= save_expr_size)
! 	    return 0;
! 	  save_expr_rewritten[save_expr_count++] = exp;
! 
! 	  nops = TREE_CODE_LENGTH (SAVE_EXPR);
! 	  for (i = 0; i < nops; i++)
  	    {
! 	      tree operand = TREE_OPERAND (exp, i);
! 	      if (operand == NULL_TREE)
! 		continue;
! 	      TREE_SET_CODE (exp, ERROR_MARK);
! 	      if (!safe_from_p (x, operand, 0))
! 		return 0;
! 	      TREE_SET_CODE (exp, SAVE_EXPR);
  	    }
! 	  TREE_SET_CODE (exp, ERROR_MARK);
  	  return 1;
  
--- 5705,5722 ----
  	    break;
  
! 	  /* If we've already scanned this, don't do it again.  Otherwise,
! 	     show we've scanned it and record for clearing the flag if we're
! 	     going on.  */
! 	  if (TREE_PRIVATE (exp))
! 	    return 1;
  
! 	  TREE_PRIVATE (exp) = 1;
! 	  if (! safe_from_p (x, TREE_OPERAND (exp, 0), 0))
  	    {
! 	      TREE_PRIVATE (exp) = 0;
! 	      return 0;
  	    }
! 
! 	  save_expr_list = tree_cons (exp, NULL_TREE, save_expr_list);
  	  return 1;
  
*************** safe_from_p (x, exp, top_p)
*** 5773,5780 ****
  
        /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
! 	 are memory and EXP is not readonly.  */
        return ! (rtx_equal_p (x, exp_rtl)
  		|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
! 		    && ! TREE_READONLY (exp)));
      }
  
--- 5765,5773 ----
  
        /* If the rtl is X, then it is not safe.  Otherwise, it is unless both
! 	 are memory and they conflict.  */
        return ! (rtx_equal_p (x, exp_rtl)
  		|| (GET_CODE (x) == MEM && GET_CODE (exp_rtl) == MEM
! 		    && true_dependence (exp_rtl, GET_MODE (x), x,
! 					rtx_addr_varies_p)));
      }
  
*************** check_max_integer_computation_mode (exp)
*** 5871,5894 ****
  #endif
  
- /* Utility function used by expand_expr to see if TYPE, a RECORD_TYPE,
-    has any readonly fields.  If any of the fields have types that
-    contain readonly fields, return true as well.  */
- 
- static int
- readonly_fields_p (type)
-      tree type;
- {
-   tree field;
- 
-   for (field = TYPE_FIELDS (type); field != 0; field = TREE_CHAIN (field))
-     if (TREE_CODE (field) == FIELD_DECL
- 	&& (TREE_READONLY (field)
- 	    || (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
- 		&& readonly_fields_p (TREE_TYPE (field)))))
-       return 1;
- 
-   return 0;
- }
- 
  /* expand_expr: generate code for computing expression EXP.
     An rtx for the computed value is returned.  The value is never null.
--- 5864,5867 ----
*************** expand_expr (exp, target, tmode, modifie
*** 6351,6359 ****
  	    temp = const0_rtx;
  	  else
! 	    {
! 	      temp = assign_temp (type, 3, 0, 0);
! 	      if (GET_CODE (temp) == MEM)
! 		RTX_UNCHANGING_P (temp) = 1;
! 	    }
  
  	  SAVE_EXPR_RTL (exp) = temp;
--- 6324,6331 ----
  	    temp = const0_rtx;
  	  else
! 	    temp = assign_temp (build_qualified_type (type,
! 						      (TYPE_QUALS (type)
! 						       | TYPE_QUAL_CONST)),
! 				3, 0, 0);
  
  	  SAVE_EXPR_RTL (exp) = temp;
*************** expand_expr (exp, target, tmode, modifie
*** 6607,6611 ****
  	  return constructor;
  	}
- 
        else
  	{
--- 6579,6582 ----
*************** expand_expr (exp, target, tmode, modifie
*** 6614,6632 ****
  	  if (target == 0 || ! safe_from_p (target, exp, 1)
  	      || GET_CODE (target) == PARALLEL)
! 	    {
! 	      if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
! 		target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
! 	      else
! 		target = assign_temp (type, 0, 1, 1);
! 	    }
  
- 	  if (TREE_READONLY (exp))
- 	    {
- 	      if (GET_CODE (target) == MEM)
- 		target = copy_rtx (target);
- 
- 	      RTX_UNCHANGING_P (target) = 1;
- 	    }
- 
  	  store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
  			     int_size_in_bytes (TREE_TYPE (exp)));
--- 6585,6595 ----
  	  if (target == 0 || ! safe_from_p (target, exp, 1)
  	      || GET_CODE (target) == PARALLEL)
! 	    target
! 	      = assign_temp (build_qualified_type (type,
! 						   (TYPE_QUALS (type)
! 						    | (TREE_READONLY (exp)
! 						       * TYPE_QUAL_CONST))),
! 			     TREE_ADDRESSABLE (exp), 1, 1);
  
  	  store_constructor (exp, target, TYPE_ALIGN (TREE_TYPE (exp)), 0,
  			     int_size_in_bytes (TREE_TYPE (exp)));
*************** expand_expr (exp, target, tmode, modifie
*** 6686,6691 ****
  	   readonly fields, we must mark it as readonly so it will
  	   conflict with readonly references to those fields.  */
! 	if (modifier == EXPAND_MEMORY_USE_WO
! 	    && TREE_CODE (type) == RECORD_TYPE && readonly_fields_p (type))
  	  RTX_UNCHANGING_P (temp) = 1;
  
--- 6649,6653 ----
  	   readonly fields, we must mark it as readonly so it will
  	   conflict with readonly references to those fields.  */
! 	if (modifier == EXPAND_MEMORY_USE_WO && readonly_fields_p (type))
  	  RTX_UNCHANGING_P (temp) = 1;
  
*************** expand_expr (exp, target, tmode, modifie
*** 6903,6907 ****
  		|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
  	      {
! 		rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
  
  		mark_temp_addr_taken (memloc);
--- 6865,6872 ----
  		|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
  	      {
! 		tree nt = build_qualified_type (TREE_TYPE (tem),
! 						(TYPE_QUALS (TREE_TYPE (tem))
! 						 | TYPE_QUAL_CONST));
! 		rtx memloc = assign_temp (nt, 1, 1, 1);
  
  		mark_temp_addr_taken (memloc);
*************** expand_expr (exp, target, tmode, modifie
*** 7078,7088 ****
  	    if (mode == BLKmode)
  	      {
! 		rtx new = assign_stack_temp (ext_mode,
! 					     bitsize / BITS_PER_UNIT, 0);
  
  		emit_move_insn (new, op0);
  		op0 = copy_rtx (new);
  		PUT_MODE (op0, BLKmode);
- 		MEM_SET_IN_STRUCT_P (op0, 1);
  	      }
  
--- 7043,7053 ----
  	    if (mode == BLKmode)
  	      {
! 		tree nt = build_qualified_type (type_for_size (ext_mode, 0),
! 						TYPE_QUAL_CONST);
! 		rtx new = assign_temp (nt, 0, 1, 1);
  
  		emit_move_insn (new, op0);
  		op0 = copy_rtx (new);
  		PUT_MODE (op0, BLKmode);
  	      }
  
*************** expand_expr (exp, target, tmode, modifie
*** 7304,7313 ****
  
  	  if (target == 0)
! 	    {
! 	      if (mode != BLKmode)
! 		target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
! 	      else
! 		target = assign_temp (type, 0, 1, 1);
! 	    }
  
  	  if (GET_CODE (target) == MEM)
--- 7269,7273 ----
  
  	  if (target == 0)
! 	    target = assign_temp (type, 0, 1, 1);
  
  	  if (GET_CODE (target) == MEM)
*************** expand_expr (exp, target, tmode, modifie
*** 8515,8519 ****
  		 be BLKmode.  */
  	      tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
! 	      rtx memloc = assign_temp (inner_type, 1, 1, 1);
  
  	      mark_temp_addr_taken (memloc);
--- 8475,8482 ----
  		 be BLKmode.  */
  	      tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
! 	      tree nt = build_qualified_type (inner_type,
! 					      (TYPE_QUALS (inner_type)
! 					       | TYPE_QUAL_CONST));
! 	      rtx memloc = assign_temp (nt, 1, 1, 1);
  
  	      mark_temp_addr_taken (memloc);
*************** expand_expr_unaligned (exp, palign)
*** 8915,8919 ****
  		|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
  	      {
! 		rtx memloc = assign_temp (TREE_TYPE (tem), 1, 1, 1);
  
  		mark_temp_addr_taken (memloc);
--- 8878,8885 ----
  		|| GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
  	      {
! 		tree nt = build_qualified_type (TREE_TYPE (tem),
! 						(TYPE_QUALS (TREE_TYPE (tem))
! 						 | TYPE_QUAL_CONST));
! 		rtx memloc = assign_temp (nt, 1, 1, 1);
  
  		mark_temp_addr_taken (memloc);
*************** expand_expr_unaligned (exp, palign)
*** 8997,9002 ****
  	    else
  	      {
! 		rtx new = assign_stack_temp (ext_mode,
! 					     bitsize / BITS_PER_UNIT, 0);
  
  		op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
--- 8963,8969 ----
  	    else
  	      {
! 		tree nt = build_qualified_type (type_for_mode (ext_mode, 0),
! 						TYPE_QUAL_CONST);
! 		rtx new = assign_temp (nt, 0, 1, 1);
  
  		op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
*** function.c	2000/12/29 08:38:19	1.237
--- function.c	2000/12/29 15:58:37
*************** struct temp_slot
*** 194,208 ****
    /* The size, in units, of the slot.  */
    HOST_WIDE_INT size;
!   /* The alias set for the slot.  If the alias set is zero, we don't
!      know anything about the alias set of the slot.  We must only
!      reuse a slot if it is assigned an object of the same alias set.
!      Otherwise, the rest of the compiler may assume that the new use
!      of the slot cannot alias the old use of the slot, which is
!      false.  If the slot has alias set zero, then we can't reuse the
!      slot at all, since we have no idea what alias set may have been
!      imposed on the memory.  For example, if the stack slot is the
!      call frame for an inline functioned, we have no idea what alias
!      sets will be assigned to various pieces of the call frame.  */
!   HOST_WIDE_INT alias_set;
    /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
    tree rtl_expr;
--- 194,202 ----
    /* The size, in units, of the slot.  */
    HOST_WIDE_INT size;
!   /* The type of the object in the slot, or zero if it doesn't correspond
!      to a type.  We use this to determine whether a slot can be reused.
!      It can be reused if objects of the type of the new slot will always
!      conflict with objects of the type of the old slot.  */
!   tree type;
    /* The value of `sequence_rtl_expr' when this temporary is allocated.  */
    tree rtl_expr;
*************** assign_stack_temp_for_type (mode, size, 
*** 659,663 ****
  {
    int align;
-   HOST_WIDE_INT alias_set;
    struct temp_slot *p, *best_p = 0;
  
--- 653,656 ----
*************** assign_stack_temp_for_type (mode, size, 
*** 667,678 ****
      abort ();
  
-   /* If we know the alias set for the memory that will be used, use
-      it.  If there's no TYPE, then we don't know anything about the
-      alias set for the memory.  */
-   if (type)
-     alias_set = get_alias_set (type);
-   else
-     alias_set = 0;
- 
    if (mode == BLKmode)
      align = BIGGEST_ALIGNMENT;
--- 660,663 ----
*************** assign_stack_temp_for_type (mode, size, 
*** 692,697 ****
      if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
  	&& ! p->in_use
! 	&& (! flag_strict_aliasing
! 	    || (alias_set && p->alias_set == alias_set))
  	&& (best_p == 0 || best_p->size > p->size
  	    || (best_p->size == p->size && best_p->align > p->align)))
--- 677,681 ----
      if (p->align >= align && p->size >= size && GET_MODE (p->slot) == mode
  	&& ! p->in_use
! 	&& objects_must_conflict_p (p->type, type)
  	&& (best_p == 0 || best_p->size > p->size
  	    || (best_p->size == p->size && best_p->align > p->align)))
*************** assign_stack_temp_for_type (mode, size, 
*** 729,733 ****
  	      p->address = 0;
  	      p->rtl_expr = 0;
! 	      p->alias_set = best_p->alias_set;
  	      p->next = temp_slots;
  	      temp_slots = p;
--- 713,717 ----
  	      p->address = 0;
  	      p->rtl_expr = 0;
! 	      p->type = best_p->type;
  	      p->next = temp_slots;
  	      temp_slots = p;
*************** assign_stack_temp_for_type (mode, size, 
*** 767,771 ****
  
        p->align = align;
-       p->alias_set = alias_set;
  
        /* The following slot size computation is necessary because we don't
--- 751,754 ----
*************** assign_stack_temp_for_type (mode, size, 
*** 798,801 ****
--- 781,785 ----
    p->addr_taken = 0;
    p->rtl_expr = seq_rtl_expr;
+   p->type = type;
  
    if (keep == 2)
*************** assign_stack_temp_for_type (mode, size, 
*** 820,827 ****
    MEM_IN_STRUCT_P (p->slot) = 0;
    MEM_SCALAR_P (p->slot) = 0;
!   MEM_ALIAS_SET (p->slot) = alias_set;
  
    if (type != 0)
!     MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
  
    return p->slot;
--- 804,824 ----
    MEM_IN_STRUCT_P (p->slot) = 0;
    MEM_SCALAR_P (p->slot) = 0;
!   MEM_VOLATILE_P (p->slot) = 0;
  
+   /* If we know the alias set for the memory that will be used, use
+      it.  If there's no TYPE, then we don't know anything about the
+      alias set for the memory.  */
+   if (type)
+     MEM_ALIAS_SET (p->slot) = get_alias_set (type);
+   else
+     MEM_ALIAS_SET (p->slot) = 0;
+ 
+   /* If a type is specified, set the relevant flags. */
    if (type != 0)
!     {
!       RTX_UNCHANGING_P (p->slot) = TYPE_READONLY (type);
!       MEM_VOLATILE_P (p->slot) = TYPE_VOLATILE (type);
!       MEM_SET_IN_STRUCT_P (p->slot, AGGREGATE_TYPE_P (type));
!     }
  
    return p->slot;
*************** mark_temp_slot (t)
*** 7454,7457 ****
--- 7452,7456 ----
        ggc_mark_rtx (t->address);
        ggc_mark_tree (t->rtl_expr);
+       ggc_mark_tree (t->type);
  
        t = t->next;
*** integrate.c	2000/12/15 13:46:51	1.122
--- integrate.c	2000/12/29 15:58:47
*************** expand_inline_function (fndecl, parms, t
*** 717,728 ****
  	  && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
  	{
! 	  rtx stack_slot
! 	    = assign_stack_temp (TYPE_MODE (TREE_TYPE (arg)),
! 				 int_size_in_bytes (TREE_TYPE (arg)), 1);
! 	  MEM_SET_IN_STRUCT_P (stack_slot,
! 			       AGGREGATE_TYPE_P (TREE_TYPE (arg)));
  
  	  store_expr (arg, stack_slot, 0);
- 
  	  arg_vals[i] = XEXP (stack_slot, 0);
  	  invisiref = 1;
--- 717,723 ----
  	  && REGNO (XEXP (loc, 0)) > LAST_VIRTUAL_REGISTER)
  	{
! 	  rtx stack_slot = assign_temp (TREE_TYPE (arg), 1, 1, 1);
  
  	  store_expr (arg, stack_slot, 0);
  	  arg_vals[i] = XEXP (stack_slot, 0);
  	  invisiref = 1;
*** stmt.c	2000/12/21 01:11:31	1.180
--- stmt.c	2000/12/29 15:59:02
*************** expand_asm_operands (string, outputs, in
*** 1758,1762 ****
  	    {
  	      tree type = TREE_TYPE (TREE_VALUE (tail));
! 	      rtx memloc = assign_temp (type, 1, 1, 1);
  
  	      emit_move_insn (memloc, op);
--- 1758,1765 ----
  	    {
  	      tree type = TREE_TYPE (TREE_VALUE (tail));
! 	      tree qual_type = build_qualified_type (type,
! 						     (TYPE_QUALS (type)
! 						      | TYPE_QUAL_CONST));
! 	      rtx memloc = assign_temp (qual_type, 1, 1, 1);
  
  	      emit_move_insn (memloc, op);
*************** expand_return (retval)
*** 3101,3106 ****
        /* Calculate the return value into a temporary (usually a pseudo
           reg).  */
!       val = assign_temp (TREE_TYPE (DECL_RESULT (current_function_decl)),
! 			 0, 0, 1);
        val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
        val = force_not_mem (val);
--- 3104,3111 ----
        /* Calculate the return value into a temporary (usually a pseudo
           reg).  */
!       tree ot = TREE_TYPE (DECL_RESULT (current_function_decl));
!       tree nt = build_qualified_type (ot, TYPE_QUALS (ot) | TYPE_QUAL_CONST);
! 
!       val = assign_temp (nt, 0, 0, 1);
        val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
        val = force_not_mem (val);
*************** expand_decl (decl)
*** 3828,3832 ****
        if (DECL_INITIAL (decl) == 0)
  	/* Error message was already done; now avoid a crash.  */
! 	DECL_RTL (decl) = assign_stack_temp (DECL_MODE (decl), 0, 1);
        else
  	/* An initializer is going to decide the size of this array.
--- 3834,3838 ----
        if (DECL_INITIAL (decl) == 0)
  	/* Error message was already done; now avoid a crash.  */
! 	DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx);
        else
  	/* An initializer is going to decide the size of this array.
*************** add_case_node (low, high, label, duplica
*** 4736,4745 ****
      }
  
!   /* Add this label to the chain, and succeed.
!      Copy LOW, HIGH so they are on temporary rather than momentary
!      obstack and will thus survive till the end of the case statement.  */
  
    r = (struct case_node *) xmalloc (sizeof (struct case_node));
!   r->low = copy_node (low);
  
    /* If the bounds are equal, turn this into the one-value case.  */
--- 4742,4749 ----
      }
  
!   /* Add this label to the chain, and succeed.  */
  
    r = (struct case_node *) xmalloc (sizeof (struct case_node));
!   r->low = low;
  
    /* If the bounds are equal, turn this into the one-value case.  */
*************** add_case_node (low, high, label, duplica
*** 4747,4751 ****
      r->high = r->low;
    else
!     r->high = copy_node (high);
  
    r->code_label = label;
--- 4751,4755 ----
      r->high = r->low;
    else
!     r->high = high;
  
    r->code_label = label;
*** tree.h	2000/11/27 07:09:19	1.214
--- tree.h	2000/12/29 15:59:21
*************** extern void rest_of_type_compilation PAR
*** 2624,2627 ****
--- 2624,2631 ----
  extern void record_component_aliases		PARAMS ((tree));
  extern HOST_WIDE_INT get_alias_set		PARAMS ((tree));
+ extern int alias_sets_conflict_p		PARAMS ((HOST_WIDE_INT,
+ 							 HOST_WIDE_INT));
+ extern int readonly_fields_p			PARAMS ((tree));
+ extern int objects_must_conflict_p		PARAMS ((tree, tree));
  
  /* In c-common.c */


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