This is the mail archive of the gcc@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]

[RFC] Not using VAR_DECLs for temporary variables


Hello,

during expansion of expressions, gimplification creates a lot of temporary
variables.  VAR_DECLs are fairly large (88 bytes on i686), and
additionally an annotation (44 bytes on i686) are allocated for each of
them (some of them even get names, for additional ~50 bytes of memory
each).  This is quite wasteful.

Basic observation is that these temporaries have exactly one definition.
It is therefore possible to generate directly SSA_NAMEs for them,
setting SSA_NAME_VAR to NULL (and be careful to never rewrite them out
of ssa).  Theoretically, it should need only a few changes to gimplification,
into- and out-of-ssa, and expand, and everything should work.  Unfortunately,
lot of SSA passes looks on SSA_NAME_VAR.  This seems wrong to me, but
changing all the places would be very hard.

However, if we instead put a really minimal DECL node (we allocate only
one per type, and consisting just of struct tree_common -- 16 bytes) as
a SSA_NAME_VAR, things are much easier to get working.

The patch below is the first attempt for the idea (completely untested,
I just made it to work somehow so that I may measure its usefullness).
We get the following results (for combine.i):

-O0:
 TOTAL                 :   3.91            22668 kB
 TOTAL                 :   3.87            22096 kB (-2.5%)

-O1:
 TOTAL                 :  20.77            34640 kB
 TOTAL                 :  20.26            33688 kB (-2.7%)

-O2:
 TOTAL                 :  25.93            41116 kB
 TOTAL                 :  25.80            40582 kB (-1.2%)

That is, we need about 2% less memory, and also the compilation seems to
be a bit faster (maybe because of the memory savings, or possibly
because less work needs to be done in into- and outof- ssa passes).

However, this idea is a bit hackish, so I would like to hear an opinion
about it before I spend more time on testing it.

Zdenek

Index: tree-into-ssa.c
===================================================================
*** tree-into-ssa.c	(revision 108807)
--- tree-into-ssa.c	(working copy)
*************** mark_def_sites (struct dom_walk_data *wa
*** 650,655 ****
--- 650,668 ----
  			    SSA_OP_USE | SSA_OP_VUSE | SSA_OP_VMUSTKILL)
      {
        tree sym = USE_FROM_PTR (use_p);
+ 
+       if (TREE_CODE (sym) == SSA_NAME)
+ 	{
+ 	  /* Only gimplifier temporaries are now in ssa form.  We had already
+ 	     seen the definition, so we have assigned a version to the ssa
+ 	     name, and the definition must dominate it.  */
+ 	  gcc_assert (TMP_NAME_P (sym));
+ 	  gcc_assert (SSA_NAME_VERSION (sym) != 0);
+ 	  gcc_assert (dominated_by_p (CDI_DOMINATORS, bb,
+ 				      bb_for_stmt (SSA_NAME_DEF_STMT (sym))));
+ 	  continue;
+ 	}
+ 
        gcc_assert (DECL_P (sym));
        if (!bitmap_bit_p (kills, DECL_UID (sym)))
  	set_livein_block (sym, bb);
*************** mark_def_sites (struct dom_walk_data *wa
*** 674,679 ****
--- 687,700 ----
    /* Now process the defs and must-defs made by this statement.  */
    FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF | SSA_OP_VMUSTDEF)
      {
+       if (TREE_CODE (def) == SSA_NAME)
+ 	{
+ 	  gcc_assert (TMP_NAME_P (def));
+ 	  gcc_assert (SSA_NAME_VERSION (def) == 0);
+ 	  gcc_assert (SSA_NAME_DEF_STMT (def) == stmt);
+ 	  register_tmp_ssa_name (def);
+ 	  continue;
+ 	}
        gcc_assert (DECL_P (def));
        set_def_block (def, bb, false);
        bitmap_set_bit (kills, DECL_UID (def));
*************** rewrite_stmt (struct dom_walk_data *walk
*** 1039,1044 ****
--- 1060,1067 ----
  	                      SSA_OP_ALL_USES|SSA_OP_ALL_KILLS)
        {
  	tree var = USE_FROM_PTR (use_p);
+ 	if (TMP_NAME_P (var))
+ 	  continue;
  	gcc_assert (DECL_P (var));
  	SET_USE (use_p, get_reaching_def (var));
        }
*************** rewrite_stmt (struct dom_walk_data *walk
*** 1048,1053 ****
--- 1071,1078 ----
      FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_ALL_DEFS)
        {
  	tree var = DEF_FROM_PTR (def_p);
+ 	if (TMP_NAME_P (var))
+ 	  continue;
  	gcc_assert (DECL_P (var));
  	SET_DEF (def_p, make_ssa_name (var, stmt));
  	register_new_def (DEF_FROM_PTR (def_p), &block_defs_stack);
Index: tree-pretty-print.c
===================================================================
*** tree-pretty-print.c	(revision 108807)
--- tree-pretty-print.c	(working copy)
*************** dump_generic_node (pretty_printer *buffe
*** 708,713 ****
--- 708,717 ----
        dump_decl_name (buffer, node, flags);
        break;
  
+     case GVAR_DECL:
+       pp_printf (buffer, "<tmp%u>", DECL_UID (node));
+       break;
+ 
      case RESULT_DECL:
        pp_string (buffer, "<retval>");
        break;
Index: tree.c
===================================================================
*** tree.c	(revision 108807)
--- tree.c	(working copy)
*************** static const char * const tree_node_kind
*** 100,106 ****
  };
  #endif /* GATHER_STATISTICS */
  
! /* Unique id for next decl created.  */
  static GTY(()) int next_decl_uid;
  /* Unique id for next type created.  */
  static GTY(()) int next_type_uid = 1;
--- 100,108 ----
  };
  #endif /* GATHER_STATISTICS */
  
! /* Unique id for next decl created.  Even uids are used for decls, odd
!    ones are reserved for uids of gimplifier temporaries (for those,
!    the uid is derived from uid of their type).  */
  static GTY(()) int next_decl_uid;
  /* Unique id for next type created.  */
  static GTY(()) int next_type_uid = 1;
*************** tree_code_size (enum tree_code code)
*** 283,288 ****
--- 285,292 ----
  	    return sizeof (struct tree_field_decl);
  	  case PARM_DECL:
  	    return sizeof (struct tree_parm_decl);
+ 	  case GVAR_DECL:
+ 	    return sizeof (struct tree_common);
  	  case VAR_DECL:
  	    return sizeof (struct tree_var_decl);
  	  case LABEL_DECL:
*************** make_node_stat (enum tree_code code MEM_
*** 490,495 ****
--- 494,501 ----
        break;
  
      case tcc_declaration:
+       if (code == GVAR_DECL)
+ 	break;
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
  	DECL_IN_SYSTEM_HEADER (t) = in_system_header;
        if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
*************** make_node_stat (enum tree_code code MEM_
*** 501,507 ****
  	  DECL_POINTER_ALIAS_SET (t) = -1;
  	}
        DECL_SOURCE_LOCATION (t) = input_location;
!       DECL_UID (t) = next_decl_uid++;
  
        break;
  
--- 507,514 ----
  	  DECL_POINTER_ALIAS_SET (t) = -1;
  	}
        DECL_SOURCE_LOCATION (t) = input_location;
!       SET_DECL_UID (t, next_decl_uid);
!       next_decl_uid += 2;
  
        break;
  
*************** copy_node_stat (tree node MEM_STAT_DECL)
*** 575,581 ****
  
    if (TREE_CODE_CLASS (code) == tcc_declaration)
      {
!       DECL_UID (t) = next_decl_uid++;
        if ((TREE_CODE (node) == PARM_DECL || TREE_CODE (node) == VAR_DECL)
  	  && DECL_HAS_VALUE_EXPR_P (node))
  	{
--- 582,589 ----
  
    if (TREE_CODE_CLASS (code) == tcc_declaration)
      {
!       SET_DECL_UID (t, next_decl_uid);
!       next_decl_uid += 2;
        if ((TREE_CODE (node) == PARM_DECL || TREE_CODE (node) == VAR_DECL)
  	  && DECL_HAS_VALUE_EXPR_P (node))
  	{
*************** tree_node_structure (tree t)
*** 1979,1984 ****
--- 1987,1994 ----
        {
  	switch (code)
  	  {
+ 	  case GVAR_DECL:
+ 	    return TS_COMMON;
  	  case FIELD_DECL:
  	    return TS_FIELD_DECL;
  	  case PARM_DECL:
*************** in_array_bounds_p (tree ref)
*** 6669,6674 ****
--- 6679,6687 ----
  bool
  is_global_var (tree t)
  {
+   if (TREE_CODE (t) == GVAR_DECL)
+     return false;
+ 
    if (MTAG_P (t))
      return (TREE_STATIC (t) || MTAG_GLOBAL (t));
    else
Index: tree.h
===================================================================
*** tree.h	(revision 108807)
--- tree.h	(working copy)
*************** extern const enum tree_code_class tree_c
*** 100,105 ****
--- 100,111 ----
  #define DECL_P(CODE)\
          (TREE_CODE_CLASS (TREE_CODE (CODE)) == tcc_declaration)
  
+ /* True if this is a ssa name for gimple temporary.  */
+ 
+ #define TMP_NAME_P(NODE) \
+ 	(TREE_CODE (NODE) == SSA_NAME \
+ 	 && TREE_CODE (SSA_NAME_VAR (NODE)) == GVAR_DECL)
+ 
  /* Nonzero if CODE represents a memory tag.  */
  
  #define MTAG_P(CODE) \
*************** struct tree_binfo GTY (())
*** 1986,1999 ****
  	 || TREE_CODE (DECL) == PARM_DECL				\
  	 || TREE_CODE (DECL) == RESULT_DECL				\
  	 || MTAG_P (DECL)						\
! 	 || (TREE_CODE (DECL) == SSA_NAME				\
! 	     && (TREE_CODE (SSA_NAME_VAR (DECL)) == VAR_DECL		\
! 		 || TREE_CODE (SSA_NAME_VAR (DECL)) == PARM_DECL	\
! 		 || TREE_CODE (SSA_NAME_VAR (DECL)) == RESULT_DECL	\
! 		 || MTAG_P (SSA_NAME_VAR (DECL)))))
! 
! 
! 
  
  /* Enumerate visibility settings.  */
  #ifndef SYMBOL_VISIBILITY_DEFINED
--- 1992,1998 ----
  	 || TREE_CODE (DECL) == PARM_DECL				\
  	 || TREE_CODE (DECL) == RESULT_DECL				\
  	 || MTAG_P (DECL)						\
! 	 || TREE_CODE (DECL) == SSA_NAME)
  
  /* Enumerate visibility settings.  */
  #ifndef SYMBOL_VISIBILITY_DEFINED
*************** struct function;
*** 2015,2021 ****
  #define DECL_NAME(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.name)
  
  /* Every ..._DECL node gets a unique number.  */
! #define DECL_UID(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.uid)
  
  /* These two fields describe where in the source code the declaration
     was.  If the declaration appears in several places (as for a C
--- 2014,2025 ----
  #define DECL_NAME(NODE) (DECL_MINIMAL_CHECK (NODE)->decl_minimal.name)
  
  /* Every ..._DECL node gets a unique number.  */
! #define SET_DECL_UID(NODE, UID) \
!   (DECL_MINIMAL_CHECK (NODE)->decl_minimal.uid = (UID))
! #define DECL_UID(NODE) \
!   (TREE_CODE (NODE) == GVAR_DECL \
!    ? (2 * TYPE_UID (TREE_TYPE (NODE)) + 1) \
!    : DECL_MINIMAL_CHECK (NODE)->decl_minimal.uid)
  
  /* These two fields describe where in the source code the declaration
     was.  If the declaration appears in several places (as for a C
*************** extern void phinodes_print_statistics (v
*** 3151,3156 ****
--- 3155,3161 ----
  extern void init_ssanames (void);
  extern void fini_ssanames (void);
  extern tree make_ssa_name (tree, tree);
+ extern void register_tmp_ssa_name (tree);
  extern tree duplicate_ssa_name (tree, tree);
  extern void duplicate_ssa_name_ptr_info (tree, struct ptr_info_def *);
  extern void release_ssa_name (tree);
*************** extern void gimplify_function_tree (tree
*** 4129,4134 ****
--- 4134,4140 ----
  extern const char *get_name (tree);
  extern tree unshare_expr (tree);
  extern void sort_case_labels (tree);
+ tree gvar_for_type (tree);
  
  /* If KIND=='I', return a suitable global initializer (constructor) name.
     If KIND=='D', return a suitable global clean-up (destructor) name.  */
Index: tree-gimple.c
===================================================================
*** tree-gimple.c	(revision 108807)
--- tree-gimple.c	(working copy)
*************** is_gimple_reg (tree t)
*** 268,273 ****
--- 268,275 ----
  {
    if (TREE_CODE (t) == SSA_NAME)
      t = SSA_NAME_VAR (t);
+   if (TREE_CODE (t) == GVAR_DECL)
+     return true;
  
    if (MTAG_P (t))
      return false;
Index: tree-ssa-copyrename.c
===================================================================
*** tree-ssa-copyrename.c	(revision 108807)
--- tree-ssa-copyrename.c	(working copy)
*************** copy_rename_partition_coalesce (var_map 
*** 188,195 ****
        return;
      }
  
!   ign1 = TREE_CODE (root1) == VAR_DECL && DECL_IGNORED_P (root1);
!   ign2 = TREE_CODE (root2) == VAR_DECL && DECL_IGNORED_P (root2);
  
    /* Never attempt to coalesce 2 user variables unless one is an inline 
       variable.  */
--- 188,197 ----
        return;
      }
  
!   ign1 = (TREE_CODE (root1) == GVAR_DECL
! 	  || (TREE_CODE (root1) == VAR_DECL && DECL_IGNORED_P (root1)));
!   ign2 = (TREE_CODE (root2) == GVAR_DECL
! 	  || (TREE_CODE (root2) == VAR_DECL && DECL_IGNORED_P (root2)));
  
    /* Never attempt to coalesce 2 user variables unless one is an inline 
       variable.  */
Index: tree-ssa-alias.c
===================================================================
*** tree-ssa-alias.c	(revision 108807)
--- tree-ssa-alias.c	(working copy)
*************** debug_may_aliases_for (tree var)
*** 2187,2192 ****
--- 2187,2195 ----
  bool
  may_be_aliased (tree var)
  {
+   if (TREE_CODE (var) == GVAR_DECL)
+     return false;
+ 
    /* Obviously.  */
    if (TREE_ADDRESSABLE (var))
      return true;
*************** create_structure_vars (void)
*** 2814,2820 ****
    FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, rvi)
      {
        /* The C++ FE creates vars without DECL_SIZE set, for some reason.  */
!       if (var 	  
  	  && DECL_SIZE (var)
  	  && var_can_have_subvars (var)
  	  && !MTAG_P (var)
--- 2817,2824 ----
    FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, rvi)
      {
        /* The C++ FE creates vars without DECL_SIZE set, for some reason.  */
!       if (var
! 	  && TREE_CODE (var) != GVAR_DECL
  	  && DECL_SIZE (var)
  	  && var_can_have_subvars (var)
  	  && !MTAG_P (var)
Index: expr.c
===================================================================
*** expr.c	(revision 108807)
--- expr.c	(working copy)
*************** expand_expr_real (tree exp, rtx target, 
*** 6561,6566 ****
--- 6561,6593 ----
    return ret;
  }
  
+ /* Returns pseudoregister used for ssa name NAME.  */
+ 
+ static rtx
+ reg_for_ssa_name (tree name)
+ {
+   rtx x = SSA_NAME_AUX (name);
+   tree type = TREE_TYPE (name);
+   int unsignedp = TYPE_UNSIGNED (type);
+   enum machine_mode x_mode = TYPE_MODE (type);
+   enum machine_mode reg_mode = promote_mode (type, x_mode, &unsignedp, 0);
+   
+   if (!x)
+     {
+       x = gen_reg_rtx (reg_mode);
+       SSA_NAME_AUX (name) = x;
+     }
+ 
+   if (x_mode != reg_mode)
+     {
+       x = gen_lowpart_SUBREG (x_mode, x);
+       SUBREG_PROMOTED_VAR_P (x) = 1;
+       SUBREG_PROMOTED_UNSIGNED_SET (x, unsignedp);
+     }
+ 
+   return x;
+ }
+ 
  static rtx
  expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
  		    enum expand_modifier modifier, rtx *alt_rtl)
*************** expand_expr_real_1 (tree exp, rtx target
*** 6671,6678 ****
        }
  
      case SSA_NAME:
!       return expand_expr_real_1 (SSA_NAME_VAR (exp), target, tmode, modifier,
! 				 NULL);
  
      case PARM_DECL:
      case VAR_DECL:
--- 6698,6705 ----
        }
  
      case SSA_NAME:
!       gcc_assert (TMP_NAME_P (exp));
!       return reg_for_ssa_name (exp);
  
      case PARM_DECL:
      case VAR_DECL:
Index: c-decl.c
===================================================================
*** c-decl.c	(revision 108807)
--- c-decl.c	(working copy)
*************** merge_decls (tree newdecl, tree olddecl,
*** 1850,1856 ****
  		(char *) newdecl + sizeof (struct tree_decl_common),
  		sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common));
        }
!     DECL_UID (olddecl) = olddecl_uid;
      DECL_CONTEXT (olddecl) = olddecl_context;
    }
  
--- 1850,1856 ----
  		(char *) newdecl + sizeof (struct tree_decl_common),
  		sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common));
        }
!     SET_DECL_UID (olddecl, olddecl_uid);
      DECL_CONTEXT (olddecl) = olddecl_context;
    }
  
Index: ipa-type-escape.c
===================================================================
*** ipa-type-escape.c	(revision 108807)
--- ipa-type-escape.c	(working copy)
*************** Software Foundation, 51 Franklin Street,
*** 60,72 ****
     this phase has been run.  */
  static bool initialized = false;
  
- /* This bitmap contains the set of local vars that are the lhs of
-    calls to mallocs.  These variables, when seen on the rhs as part of
-    a cast, the cast are not marked as doing bad things to the type
-    even though they are generally of the form 
-    "foo = (type_of_foo)void_temp". */
- static bitmap results_of_malloc;
- 
  /* Scratch bitmap for avoiding work. */
  static bitmap been_there_done_that;
  static bitmap bitmap_tmp;
--- 60,65 ----
*************** check_cast_type (tree to_type, tree from
*** 649,654 ****
--- 642,664 ----
    return CT_SIDEWAYS;
  }     
  
+ /* Returns true if STMT is a call to malloc.  */
+ 
+ static bool
+ malloc_stmt_p (tree stmt)
+ {
+   tree call;
+ 
+   if (TREE_CODE (stmt) != MODIFY_EXPR)
+     return false;
+ 
+   call = TREE_OPERAND (stmt, 1);
+   if (TREE_CODE (call) != CALL_EXPR)
+     return false;
+ 
+   return (call_expr_flags (call) & ECF_MALLOC) != 0;
+ }
+ 
  /* Check a cast FROM this variable, TO_TYPE.  Mark the escaping types
     if appropriate.  */ 
  static void
*************** check_cast (tree to_type, tree from) 
*** 692,698 ****
        {
  	/* If this is a cast from the local that is a result from a
  	   call to malloc, do not mark the cast as bad.  */
! 	if (DECL_P (from) && !bitmap_bit_p (results_of_malloc, DECL_UID (from)))
  	  mark_type (to_type, FULL_ESCAPE);
        }
    else if (from_interesting_type)
--- 702,709 ----
        {
  	/* If this is a cast from the local that is a result from a
  	   call to malloc, do not mark the cast as bad.  */
! 	if (TREE_CODE (from) != SSA_NAME
! 	    || !malloc_stmt_p (SSA_NAME_DEF_STMT (from)))
  	  mark_type (to_type, FULL_ESCAPE);
        }
    else if (from_interesting_type)
*************** get_asm_expr_operands (tree stmt)
*** 1013,1022 ****
     this is either an indirect call, a call outside the compilation
     unit.  */
  
! static bool
  check_call (tree call_expr) 
  {
-   int flags = call_expr_flags(call_expr);
    tree operand_list = TREE_OPERAND (call_expr, 1);
    tree operand;
    tree callee_t = get_callee_fndecl (call_expr);
--- 1024,1032 ----
     this is either an indirect call, a call outside the compilation
     unit.  */
  
! static void
  check_call (tree call_expr) 
  {
    tree operand_list = TREE_OPERAND (call_expr, 1);
    tree operand;
    tree callee_t = get_callee_fndecl (call_expr);
*************** check_call (tree call_expr) 
*** 1136,1142 ****
  	  mark_interesting_type (type, EXPOSED_PARAMETER);
  	}
      }
-   return (flags & ECF_MALLOC);
  }
  
  /* CODE is the operation on OP0 and OP1.  OP0 is the operand that we
--- 1146,1151 ----
*************** scan_for_refs (tree *tp, int *walk_subtr
*** 1264,1274 ****
  		check_rhs_var (rhs);
  		break;
  	      case CALL_EXPR: 
! 		/* If this is a call to malloc, squirrel away the
! 		   result so we do mark the resulting cast as being
! 		   bad.  */
! 		if (check_call (rhs))
! 		  bitmap_set_bit (results_of_malloc, DECL_UID (lhs));
  		break;
  	      default:
  		break;
--- 1273,1279 ----
  		check_rhs_var (rhs);
  		break;
  	      case CALL_EXPR: 
! 		check_call (rhs);
  		break;
  	      default:
  		break;
*************** ipa_init (void) 
*** 1314,1320 ****
    global_types_exposed_parameter = BITMAP_ALLOC (&ipa_obstack);
    global_types_full_escape = BITMAP_ALLOC (&ipa_obstack);
    global_types_seen = BITMAP_ALLOC (&ipa_obstack);
-   results_of_malloc = BITMAP_ALLOC (&ipa_obstack);
  
    uid_to_canon_type = splay_tree_new (splay_tree_compare_ints, 0, 0);
    all_canon_types = splay_tree_new (compare_type_brand, 0, 0);
--- 1319,1324 ----
*************** type_escape_execute (void)
*** 1822,1828 ****
    BITMAP_FREE (global_types_exposed_parameter);
    BITMAP_FREE (been_there_done_that);
    BITMAP_FREE (bitmap_tmp);
-   BITMAP_FREE (results_of_malloc);
  }
  
  static bool
--- 1826,1831 ----
Index: alias.c
===================================================================
*** alias.c	(revision 108807)
--- alias.c	(working copy)
*************** get_alias_set (tree t)
*** 522,528 ****
  	{
  	  tree decl = find_base_decl (TREE_OPERAND (inner, 0));
  
! 	  if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
  	    {
  	      /* If we haven't computed the actual alias set, do it now.  */
  	      if (DECL_POINTER_ALIAS_SET (decl) == -2)
--- 522,530 ----
  	{
  	  tree decl = find_base_decl (TREE_OPERAND (inner, 0));
  
! 	  if (decl
! 	      && TREE_CODE (decl) != GVAR_DECL
! 	      && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
  	    {
  	      /* If we haven't computed the actual alias set, do it now.  */
  	      if (DECL_POINTER_ALIAS_SET (decl) == -2)
Index: gimplify.c
===================================================================
*** gimplify.c	(revision 108807)
--- gimplify.c	(working copy)
*************** static struct gimplify_ctx
*** 55,116 ****
    tree exit_label;
    tree return_temp;
    VEC(tree,heap) *case_labels;
-   /* The formal temporary table.  Should this be persistent?  */
-   htab_t temp_htab;
    int conditions;
    bool save_stack;
    bool into_ssa;
  } *gimplify_ctxp;
  
  
- /* Formal (expression) temporary table handling: Multiple occurrences of
-    the same scalar expression are evaluated into the same temporary.  */
- 
- typedef struct gimple_temp_hash_elt
- {
-   tree val;   /* Key */
-   tree temp;  /* Value */
- } elt_t;
- 
  /* Forward declarations.  */
  static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
  #ifdef ENABLE_CHECKING
  static bool cpt_same_type (tree a, tree b);
  #endif
  
- 
- /* Return a hash value for a formal temporary table entry.  */
- 
- static hashval_t
- gimple_tree_hash (const void *p)
- {
-   tree t = ((const elt_t *) p)->val;
-   return iterative_hash_expr (t, 0);
- }
- 
- /* Compare two formal temporary table entries.  */
- 
- static int
- gimple_tree_eq (const void *p1, const void *p2)
- {
-   tree t1 = ((const elt_t *) p1)->val;
-   tree t2 = ((const elt_t *) p2)->val;
-   enum tree_code code = TREE_CODE (t1);
- 
-   if (TREE_CODE (t2) != code
-       || TREE_TYPE (t1) != TREE_TYPE (t2))
-     return 0;
- 
-   if (!operand_equal_p (t1, t2, 0))
-     return 0;
- 
-   /* Only allow them to compare equal if they also hash equal; otherwise
-      results are nondeterminate, and we fail bootstrap comparison.  */
-   gcc_assert (gimple_tree_hash (p1) == gimple_tree_hash (p2));
- 
-   return 1;
- }
- 
  /* Set up a context for the gimplifier.  */
  
  void
--- 55,72 ----
*************** push_gimplify_context (void)
*** 119,129 ****
    gcc_assert (!gimplify_ctxp);
    gimplify_ctxp
      = (struct gimplify_ctx *) xcalloc (1, sizeof (struct gimplify_ctx));
-   if (optimize)
-     gimplify_ctxp->temp_htab
-       = htab_create (1000, gimple_tree_hash, gimple_tree_eq, free);
-   else
-     gimplify_ctxp->temp_htab = NULL;
  }
  
  /* Tear down a context for the gimplifier.  If BODY is non-null, then
--- 75,80 ----
*************** pop_gimplify_context (tree body)
*** 151,158 ****
  	     htab_collisions (gimplify_ctxp->temp_htab));
  #endif
  
-   if (optimize)
-     htab_delete (gimplify_ctxp->temp_htab);
    free (gimplify_ctxp);
    gimplify_ctxp = NULL;
  }
--- 102,107 ----
*************** get_name (tree t)
*** 425,431 ****
  
    stripped_decl = t;
    STRIP_NOPS (stripped_decl);
!   if (DECL_P (stripped_decl) && DECL_NAME (stripped_decl))
      return IDENTIFIER_POINTER (DECL_NAME (stripped_decl));
    else
      {
--- 374,382 ----
  
    stripped_decl = t;
    STRIP_NOPS (stripped_decl);
!   if (DECL_P (stripped_decl)
!       && TREE_CODE (stripped_decl) != GVAR_DECL
!       && DECL_NAME (stripped_decl))
      return IDENTIFIER_POINTER (DECL_NAME (stripped_decl));
    else
      {
*************** get_name (tree t)
*** 440,494 ****
      }
  }
  
! /* Create a temporary with a name derived from VAL.  Subroutine of
!    lookup_tmp_var; nobody else should call this function.  */
  
! static inline tree
! create_tmp_from_val (tree val)
  {
!   return create_tmp_var (TYPE_MAIN_VARIANT (TREE_TYPE (val)), get_name (val));
  }
  
! /* Create a temporary to hold the value of VAL.  If IS_FORMAL, try to reuse
!    an existing expression temporary.  */
  
  static tree
  lookup_tmp_var (tree val, bool is_formal)
  {
!   tree ret;
  
!   /* If not optimizing, never really reuse a temporary.  local-alloc
!      won't allocate any variable that is used in more than one basic
!      block, which means it will go into memory, causing much extra
!      work in reload and final and poorer code generation, outweighing
!      the extra memory allocation here.  */
!   if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val))
!     ret = create_tmp_from_val (val);
!   else
      {
!       elt_t elt, *elt_p;
!       void **slot;
  
!       elt.val = val;
!       slot = htab_find_slot (gimplify_ctxp->temp_htab, (void *)&elt, INSERT);
!       if (*slot == NULL)
! 	{
! 	  elt_p = XNEW (elt_t);
! 	  elt_p->val = val;
! 	  elt_p->temp = ret = create_tmp_from_val (val);
! 	  *slot = (void *) elt_p;
! 	}
!       else
! 	{
! 	  elt_p = (elt_t *) *slot;
!           ret = elt_p->temp;
! 	}
      }
! 
!   if (is_formal)
!     DECL_GIMPLE_FORMAL_TEMP_P (ret) = 1;
! 
!   return ret;
  }
  
  /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
--- 391,447 ----
      }
  }
  
! /* Table of gimple var for type.  */
  
! static GTY((param_is (struct int_tree_map))) htab_t gvar_for_types;
! 
! /* Returns the unique GVAR_DECL for temporary variables of TYPE.  */
! 
! tree
! gvar_for_type (tree type)
  {
!   struct int_tree_map *h, in;
!   void **slot;
!   unsigned uid = TYPE_UID (type);
! 
!   if (!gvar_for_types)
!     gvar_for_types = htab_create_ggc (20, int_tree_map_hash, 
! 				      int_tree_map_eq, NULL);
! 
!   in.uid = uid;
!   slot = htab_find_slot_with_hash (gvar_for_types, &in, uid, INSERT);
!   if (*slot)
!     h = *slot;
!   else
!     {
!       h = GGC_NEW (struct int_tree_map);
!       h->uid = uid;
!       h->to = make_node (GVAR_DECL);
!       TREE_TYPE (h->to) = type;
!       *slot = h;
!     }
! 
!   return h->to;
  }
  
! /* Create a temporary to hold the value of VAL.  If IS_FORMAL, create a ssa
!    name for it as well.  */
  
  static tree
  lookup_tmp_var (tree val, bool is_formal)
  {
!   tree type = TYPE_MAIN_VARIANT (TREE_TYPE (val));
  
!   if (is_formal)
      {
!       tree var = make_ssa_name (gvar_for_type (type), NULL_TREE);
  
!       if (SSA_NAME_VERSION (var) != 0)
! 	add_referenced_tmp_var (SSA_NAME_VAR (var));
!       return var;
      }
!   else
!     return create_tmp_var (type, get_name (val));
  }
  
  /* Returns a formal temporary variable initialized with VAL.  PRE_P is as
*************** lookup_tmp_var (tree val, bool is_formal
*** 506,537 ****
  static tree
  internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
  {
!   tree t, mod;
  
    gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_rhs, fb_rvalue);
  
-   t = lookup_tmp_var (val, is_formal);
- 
    if (is_formal)
      {
!       tree u = find_single_pointer_decl (val);
  
!       if (u && TREE_CODE (u) == VAR_DECL && DECL_BASED_ON_RESTRICT_P (u))
! 	u = DECL_GET_RESTRICT_BASE (u);
!       if (u && TYPE_RESTRICT (TREE_TYPE (u)))
  	{
! 	  if (DECL_BASED_ON_RESTRICT_P (t))
! 	    gcc_assert (u == DECL_GET_RESTRICT_BASE (t));
! 	  else
! 	    {
! 	      DECL_BASED_ON_RESTRICT_P (t) = 1;
! 	      SET_DECL_RESTRICT_BASE (t, u);
! 	    }
  	}
      }
  
!   if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
!     DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
  
    mod = build2 (MODIFY_EXPR, TREE_TYPE (t), t, val);
  
--- 459,500 ----
  static tree
  internal_get_tmp_var (tree val, tree *pre_p, tree *post_p, bool is_formal)
  {
!   tree t, mod, restr_base = NULL_TREE;
  
    gimplify_expr (&val, pre_p, post_p, is_gimple_formal_tmp_rhs, fb_rvalue);
  
    if (is_formal)
      {
!       restr_base = find_single_pointer_decl (val);
  
!       if (restr_base)
  	{
! 	  if (TREE_CODE (restr_base) == VAR_DECL
! 	      && DECL_BASED_ON_RESTRICT_P (restr_base))
! 	    restr_base = DECL_GET_RESTRICT_BASE (restr_base);
! 	  else if (!TYPE_RESTRICT (TREE_TYPE (restr_base)))
! 	    restr_base = NULL_TREE;
  	}
      }
  
!   t = lookup_tmp_var (val,
! 		      is_formal
! 		      && (restr_base == NULL_TREE)
! 		      && is_gimple_reg_type (TREE_TYPE (val)));
! 
!   if (restr_base != NULL_TREE)
!     {
!       DECL_BASED_ON_RESTRICT_P (t) = 1;
!       SET_DECL_RESTRICT_BASE (t, restr_base);
!     }
! 
!   if (TREE_CODE (t) != SSA_NAME)
!     {
!       if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
! 	DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
!       if (is_formal)
! 	DECL_GIMPLE_FORMAL_TEMP_P (t) = 1;
!     }
  
    mod = build2 (MODIFY_EXPR, TREE_TYPE (t), t, val);
  
*************** gimplify_modify_expr (tree *expr_p, tree
*** 3338,3350 ****
        && is_gimple_reg (TREE_OPERAND (*to_p, 0)))
      return gimplify_modify_expr_complex_part (expr_p, pre_p, want_value);
  
!   if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
      {
!       /* If we've somehow already got an SSA_NAME on the LHS, then
! 	 we're probably modified it twice.  Not good.  */
!       gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
!       *to_p = make_ssa_name (*to_p, *expr_p);
      }
  
    if (want_value)
      {
--- 3301,3314 ----
        && is_gimple_reg (TREE_OPERAND (*to_p, 0)))
      return gimplify_modify_expr_complex_part (expr_p, pre_p, want_value);
  
!   if (TREE_CODE (*to_p) == SSA_NAME)
      {
!       /* This must be the single definition of the ssa name.  */
!       gcc_assert (SSA_NAME_DEF_STMT (*to_p) == NULL_TREE);
!       SSA_NAME_DEF_STMT (*to_p) = *expr_p;
      }
+   else if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
+     *to_p = make_ssa_name (*to_p, *expr_p);
  
    if (want_value)
      {
*************** force_gimple_operand (tree expr, tree *s
*** 5028,5034 ****
    push_gimplify_context ();
    gimplify_ctxp->into_ssa = in_ssa_p;
  
!   if (var)
      expr = build2 (MODIFY_EXPR, TREE_TYPE (var), var, expr);
  
    ret = gimplify_expr (&expr, stmts, NULL,
--- 4992,4998 ----
    push_gimplify_context ();
    gimplify_ctxp->into_ssa = in_ssa_p;
  
!   if (var && TREE_CODE (var) != GVAR_DECL)
      expr = build2 (MODIFY_EXPR, TREE_TYPE (var), var, expr);
  
    ret = gimplify_expr (&expr, stmts, NULL,
Index: tree.def
===================================================================
*** tree.def	(revision 108807)
--- tree.def	(working copy)
*************** DEFTREECODE (CONST_DECL, "const_decl", t
*** 357,362 ****
--- 357,363 ----
  DEFTREECODE (PARM_DECL, "parm_decl", tcc_declaration, 0)
  DEFTREECODE (TYPE_DECL, "type_decl", tcc_declaration, 0)
  DEFTREECODE (RESULT_DECL, "result_decl", tcc_declaration, 0)
+ DEFTREECODE (GVAR_DECL, "gimple_var_decl", tcc_declaration, 0)
  
  /* Memory tags used in tree-ssa to represent memory locations in
     virtual SSA.  */
Index: tree-dfa.c
===================================================================
*** tree-dfa.c	(revision 108807)
--- tree-dfa.c	(working copy)
*************** find_vars_r (tree *tp, int *walk_subtree
*** 560,572 ****
  
    /* If T is a regular variable that the optimizers are interested
       in, add it to the list of variables.  */
!   if (SSA_VAR_P (*tp))
      add_referenced_var (*tp, walk_state);
  
    /* Type, _DECL and constant nodes have no interesting children.
       Ignore them.  */
    else if (IS_TYPE_OR_DECL_P (*tp) || CONSTANT_CLASS_P (*tp))
!     *walk_subtrees = 0;
  
    return NULL_TREE;
  }
--- 560,577 ----
  
    /* If T is a regular variable that the optimizers are interested
       in, add it to the list of variables.  */
!   *walk_subtrees = 0;
!   if (TREE_CODE (*tp) == SSA_NAME)
!     add_referenced_var (SSA_NAME_VAR (*tp), walk_state);
!   else if (SSA_VAR_P (*tp))
      add_referenced_var (*tp, walk_state);
  
    /* Type, _DECL and constant nodes have no interesting children.
       Ignore them.  */
    else if (IS_TYPE_OR_DECL_P (*tp) || CONSTANT_CLASS_P (*tp))
!     ;
!   else
!     *walk_subtrees = 1;
  
    return NULL_TREE;
  }
*************** tree 
*** 623,628 ****
--- 628,637 ----
  default_def (tree var)
  {
    struct int_tree_map *h, in;
+ 
+   if (TREE_CODE (var) == GVAR_DECL)
+     return NULL_TREE;
+ 
    gcc_assert (SSA_VAR_P (var));
    in.uid = DECL_UID (var);
    h = (struct int_tree_map *) htab_find_with_hash (default_defs, &in,
*************** add_referenced_var (tree var, struct wal
*** 701,707 ****
  	mark_call_clobbered (var);
  
        /* Tag's don't have DECL_INITIAL.  */
!       if (MTAG_P (var))
  	return;
        
        /* Scan DECL_INITIAL for pointer variables as they may contain
--- 710,716 ----
  	mark_call_clobbered (var);
  
        /* Tag's don't have DECL_INITIAL.  */
!       if (MTAG_P (var) || TREE_CODE (var) == GVAR_DECL)
  	return;
        
        /* Scan DECL_INITIAL for pointer variables as they may contain
Index: tree-ssa-live.c
===================================================================
*** tree-ssa-live.c	(revision 108807)
--- tree-ssa-live.c	(working copy)
*************** create_ssa_var_map (int flags)
*** 381,388 ****
  	  stmt = bsi_stmt (bsi);
  
  	  /* Register USE and DEF operands in each statement.  */
! 	  FOR_EACH_SSA_TREE_OPERAND (use , stmt, iter, SSA_OP_USE)
  	    {
  	      register_ssa_partition (map, use, true);
  
  #ifdef ENABLE_CHECKING
--- 381,391 ----
  	  stmt = bsi_stmt (bsi);
  
  	  /* Register USE and DEF operands in each statement.  */
! 	  FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
  	    {
+ 	      if (TMP_NAME_P (use))
+ 		continue;
+ 
  	      register_ssa_partition (map, use, true);
  
  #ifdef ENABLE_CHECKING
*************** create_ssa_var_map (int flags)
*** 392,397 ****
--- 395,403 ----
  
  	  FOR_EACH_SSA_TREE_OPERAND (dest, stmt, iter, SSA_OP_DEF)
  	    {
+ 	      if (TMP_NAME_P (dest))
+ 		continue;
+ 
  	      register_ssa_partition (map, dest, false);
  
  #ifdef ENABLE_CHECKING
Index: print-tree.c
===================================================================
*** print-tree.c	(revision 108807)
--- print-tree.c	(working copy)
*************** print_node (FILE *file, const char *pref
*** 224,230 ****
    /* Print the name, if any.  */
    if (class == tcc_declaration)
      {
!       if (DECL_NAME (node))
  	fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node)));
        else if (TREE_CODE (node) == LABEL_DECL
  	       && LABEL_DECL_UID (node) != -1)
--- 224,232 ----
    /* Print the name, if any.  */
    if (class == tcc_declaration)
      {
!       if (TREE_CODE (node) == GVAR_DECL)
! 	fprintf (file, "%c.%u", 'T', DECL_UID (node));
!       else if (DECL_NAME (node))
  	fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node)));
        else if (TREE_CODE (node) == LABEL_DECL
  	       && LABEL_DECL_UID (node) != -1)
Index: tree-ssa.c
===================================================================
*** tree-ssa.c	(revision 108807)
--- tree-ssa.c	(working copy)
*************** delete_tree_ssa (void)
*** 817,828 ****
    for (i = 0; i < num_ssa_names; i++)
      {
        tree var = ssa_name (i);
!       if (var && TREE_CODE (var) == SSA_NAME)
          {
  	  SSA_NAME_IMM_USE_NODE (var).prev = &(SSA_NAME_IMM_USE_NODE (var));
  	  SSA_NAME_IMM_USE_NODE (var).next = &(SSA_NAME_IMM_USE_NODE (var));
  	}
-       release_ssa_name (var);
      }
  
    /* Remove annotations from every tree in the function.  */
--- 817,830 ----
    for (i = 0; i < num_ssa_names; i++)
      {
        tree var = ssa_name (i);
!       if (var 
! 	  && TREE_CODE (var) == SSA_NAME
! 	  && !TMP_NAME_P (var))
          {
  	  SSA_NAME_IMM_USE_NODE (var).prev = &(SSA_NAME_IMM_USE_NODE (var));
  	  SSA_NAME_IMM_USE_NODE (var).next = &(SSA_NAME_IMM_USE_NODE (var));
+ 	  release_ssa_name (var);
  	}
      }
  
    /* Remove annotations from every tree in the function.  */
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 108807)
--- tree-inline.c	(working copy)
*************** remap_decl (tree decl, inline_data *id)
*** 200,251 ****
    if (!n)
      {
        /* Make a copy of the variable or label.  */
!       tree t;
!       t = copy_decl_for_dup (decl, fn, id->caller, id->versioning_p);
!      
!       /* Remember it, so that if we encounter this local entity again
! 	 we can reuse this copy.  Do this early because remap_type may
! 	 need this decl for TYPE_STUB_DECL.  */
!       insert_decl_map (id, decl, t);
  
!       /* Remap types, if necessary.  */
!       TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
!       if (TREE_CODE (t) == TYPE_DECL)
!         DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
! 
!       /* Remap sizes as necessary.  */
!       walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
!       walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL);
! 
!       /* If fields, do likewise for offset and qualifier.  */
!       if (TREE_CODE (t) == FIELD_DECL)
! 	{
! 	  walk_tree (&DECL_FIELD_OFFSET (t), copy_body_r, id, NULL);
! 	  if (TREE_CODE (DECL_CONTEXT (t)) == QUAL_UNION_TYPE)
! 	    walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
! 	}
! 
! #if 0
!       /* FIXME handle anon aggrs.  */
!       if (! DECL_NAME (t) && TREE_TYPE (t)
! 	  && lang_hooks.tree_inlining.anon_aggr_type_p (TREE_TYPE (t)))
! 	{
! 	  /* For a VAR_DECL of anonymous type, we must also copy the
! 	     member VAR_DECLS here and rechain the DECL_ANON_UNION_ELEMS.  */
! 	  tree members = NULL;
! 	  tree src;
  
! 	  for (src = DECL_ANON_UNION_ELEMS (t); src;
! 	       src = TREE_CHAIN (src))
  	    {
! 	      tree member = remap_decl (TREE_VALUE (src), id);
! 
! 	      gcc_assert (!TREE_PURPOSE (src));
! 	      members = tree_cons (NULL, member, members);
  	    }
! 	  DECL_ANON_UNION_ELEMS (t) = nreverse (members);
  	}
- #endif
  
        /* Remember it, so that if we encounter this local entity
  	 again we can reuse this copy.  */
--- 200,240 ----
    if (!n)
      {
        /* Make a copy of the variable or label.  */
!       tree t, type;
  
!       if (TREE_CODE (decl) == SSA_NAME)
! 	{
! 	  gcc_assert (TMP_NAME_P (decl));
! 	  type = remap_type (TREE_TYPE (decl), id);
! 	  t = make_ssa_name (gvar_for_type (type), NULL_TREE);
! 	}
!       else
! 	{
! 	  t = copy_decl_for_dup (decl, fn, id->caller, id->versioning_p);
!      
! 	  /* Remember it, so that if we encounter this local entity again
! 	     we can reuse this copy.  Do this early because remap_type may
! 	     need this decl for TYPE_STUB_DECL.  */
! 	  insert_decl_map (id, decl, t);
! 
! 	  /* Remap types, if necessary.  */
! 	  TREE_TYPE (t) = remap_type (TREE_TYPE (t), id);
! 	  if (TREE_CODE (t) == TYPE_DECL)
! 	    DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id);
! 
! 	  /* Remap sizes as necessary.  */
! 	  walk_tree (&DECL_SIZE (t), copy_body_r, id, NULL);
! 	  walk_tree (&DECL_SIZE_UNIT (t), copy_body_r, id, NULL);
  
! 	  /* If fields, do likewise for offset and qualifier.  */
! 	  if (TREE_CODE (t) == FIELD_DECL)
  	    {
! 	      walk_tree (&DECL_FIELD_OFFSET (t), copy_body_r, id, NULL);
! 	      if (TREE_CODE (DECL_CONTEXT (t)) == QUAL_UNION_TYPE)
! 		walk_tree (&DECL_QUALIFIER (t), copy_body_r, id, NULL);
  	    }
! 
  	}
  
        /* Remember it, so that if we encounter this local entity
  	 again we can reuse this copy.  */
*************** copy_body_r (tree *tp, int *walk_subtree
*** 547,552 ****
--- 536,546 ----
  	  return (tree) (void *)1;
  	}
      }
+   else if (TREE_CODE (*tp) == SSA_NAME)
+     {
+       *tp = remap_decl (*tp, id);
+       *walk_subtrees = 0;
+     }
  
    /* Local variables and labels need to be replaced by equivalent
       variables.  We don't want to copy static variables; there's only
*************** copy_body_r (tree *tp, int *walk_subtree
*** 707,712 ****
--- 701,722 ----
  	  recompute_tree_invariant_for_addr_expr (*tp);
  	  *walk_subtrees = 0;
  	}
+ 
+       if (TREE_CODE (*tp) == MODIFY_EXPR)
+ 	{
+ 	  tree op;
+ 
+ 	  walk_tree (&TREE_OPERAND (*tp, 0), copy_body_r, id, NULL);
+ 	  walk_tree (&TREE_OPERAND (*tp, 1), copy_body_r, id, NULL);
+ 	  op = TREE_OPERAND (*tp, 0);
+ 	  if (TREE_CODE (op) == SSA_NAME)
+ 	    {
+ 	      gcc_assert (SSA_NAME_DEF_STMT (op) == NULL_TREE);
+ 	      SSA_NAME_DEF_STMT (op) = *tp;
+ 	    }
+ 	  *walk_subtrees = 0;
+ 	  return NULL_TREE;
+ 	}
      }
  
    /* Keep iterating.  */
Index: tree-outof-ssa.c
===================================================================
*** tree-outof-ssa.c	(revision 108807)
--- tree-outof-ssa.c	(working copy)
*************** check_replaceable (temp_expr_table_p tab
*** 1584,1590 ****
    /* Add this expression to the dependency list for each use partition.  */
    FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
      {
!       add_dependance (tab, version, var);
      }
  
    /* If there are VUSES, add a dependence on virtual defs.  */
--- 1584,1591 ----
    /* Add this expression to the dependency list for each use partition.  */
    FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
      {
!       if (!TMP_NAME_P (var))
! 	add_dependance (tab, version, var);
      }
  
    /* If there are VUSES, add a dependence on virtual defs.  */
*************** rewrite_trees (var_map map, tree *values
*** 1902,1907 ****
--- 1903,1910 ----
  	  copy_use_p = NULL_USE_OPERAND_P;
  	  FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
  	    {
+ 	      if (TMP_NAME_P (USE_FROM_PTR (use_p)))
+ 		continue;
  	      if (replace_use_variable (map, use_p, values))
  		changed = true;
  	      copy_use_p = use_p;
*************** rewrite_trees (var_map map, tree *values
*** 1917,1923 ****
  	    {
  	      /* Mark this stmt for removal if it is the list of replaceable 
  		 expressions.  */
! 	      if (values && values[SSA_NAME_VERSION (DEF_FROM_PTR (def_p))])
  		remove = true;
  	      else
  		{
--- 1920,1928 ----
  	    {
  	      /* Mark this stmt for removal if it is the list of replaceable 
  		 expressions.  */
! 	      if (TMP_NAME_P (DEF_FROM_PTR (def_p)))
! 		;
! 	      else if (values && values[SSA_NAME_VERSION (DEF_FROM_PTR (def_p))])
  		remove = true;
  	      else
  		{
*************** rewrite_trees (var_map map, tree *values
*** 1935,1941 ****
  	    }
  	  else
  	    FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
! 	      if (replace_def_variable (map, def_p, NULL))
  		changed = true;
  
  	  /* Remove any stmts marked for removal.  */
--- 1940,1947 ----
  	    }
  	  else
  	    FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, iter, SSA_OP_DEF)
! 	      if (!TMP_NAME_P (DEF_FROM_PTR (def_p))
! 		  && replace_def_variable (map, def_p, NULL))
  		changed = true;
  
  	  /* Remove any stmts marked for removal.  */
*************** insert_backedge_copies (void)
*** 2489,2494 ****
--- 2495,2582 ----
      }
  }
  
+ /* Copy information from FROM_ANN to TO_ANN.  */
+ 
+ static void
+ copy_var_ann (var_ann_t to_ann, var_ann_t from_ann)
+ {
+   to_ann->type_mem_tag = from_ann->type_mem_tag;
+ 
+   if (from_ann->may_aliases)
+     {
+       unsigned i;
+       tree al;
+ 
+       to_ann->may_aliases = VEC_alloc (tree, gc,
+ 				       VEC_length (tree,
+ 						   from_ann->may_aliases));
+ 
+       for (i = 0; VEC_iterate (tree, from_ann->may_aliases, i, al); i++)
+ 	VEC_quick_push (tree, to_ann->may_aliases, al);
+     }
+ }
+ 
+ /* We would like to keep the ssa names for gimplifier temporaries.  Phi
+    nodes for gimplifier temporary ssa names are fairly rare, but they
+    may appear due to code duplication.  Persuading rest of out-of-ssa not
+    to create temporary variables for these ssa names is somewhat nontrivial,
+    so we avoid it -- we just create the new temporary variables for those
+    tmp ssa names that appear in phi nodes, and don't tell out-of-ssa about the
+    rest.  */
+ 
+ static void
+ eliminate_tmp_name_phis (void)
+ {
+   basic_block bb;
+   tree phi, name, var, old_var;
+   ssa_op_iter oi;
+   use_operand_p use;
+ 
+   FOR_EACH_BB (bb)
+     {
+       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ 	{
+ 	  if (!is_gimple_reg (PHI_RESULT (phi)))
+ 	    continue;
+ 
+ 	  var = NULL_TREE;
+ 	  old_var = NULL_TREE;
+ 	  name = PHI_RESULT (phi);
+ 
+ 	  if (TMP_NAME_P (name))
+ 	    {
+ 	      var = create_tmp_var (TREE_TYPE (name), NULL);
+ 	      old_var = SSA_NAME_VAR (name);
+ 
+ 	      SSA_NAME_VAR (name) = var;
+ 	    }
+ 	  FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
+ 	    {
+ 	      name = USE_FROM_PTR (use);
+ 
+ 	      if (!TMP_NAME_P (name))
+ 		continue;
+ 
+ 	      if (!var)
+ 		{
+ 		  var = create_tmp_var (TREE_TYPE (name), NULL);
+ 		  old_var = SSA_NAME_VAR (name);
+ 		}
+ 	      else
+ 		gcc_assert (SSA_NAME_VAR (name) == old_var);
+ 
+ 	      SSA_NAME_VAR (name) = var;
+ 	    }
+ 
+ 	  if (var)
+ 	    {
+ 	      add_referenced_tmp_var (var);
+ 	      copy_var_ann (var_ann (var), var_ann (old_var));
+ 	    }
+ 	}
+     }
+ }
+ 
  /* Take the current function out of SSA form, as described in
     R. Morgan, ``Building an Optimizing Compiler'',
     Butterworth-Heinemann, Boston, MA, 1998. pp 176-186.  */
*************** rewrite_out_of_ssa (void)
*** 2500,2505 ****
--- 2588,2595 ----
    int var_flags = 0;
    int ssa_flags = 0;
  
+   eliminate_tmp_name_phis ();
+ 
    /* If elimination of a PHI requires inserting a copy on a backedge,
       then we will have to split the backedge which has numerous
       undesirable performance effects.
Index: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 108807)
--- tree-cfg.c	(working copy)
*************** verify_expr (tree *tp, int *walk_subtree
*** 3250,3255 ****
--- 3250,3287 ----
  	}
        break;
  
+     case TARGET_MEM_REF:
+       /* Ignore TMR_ORIGINAL and TMR_TAG.  */
+       if (TMR_SYMBOL (t) && !DECL_P (TMR_SYMBOL (t)))
+ 	{
+ 	  error ("tmr symbol is not a decl");
+ 	  return t;
+ 	}
+ 
+       if (TMR_BASE (t) && !is_gimple_val (TMR_BASE (t)))
+ 	{
+ 	  error ("invalid tmr base");
+ 	  return t;
+ 	}
+       if (TMR_INDEX (t) && !is_gimple_val (TMR_INDEX (t)))
+ 	{
+ 	  error ("invalid tmr index");
+ 	  return t;
+ 	}
+       if (TMR_STEP (t) && TREE_CODE (TMR_STEP (t)) != INTEGER_CST)
+ 	{
+ 	  error ("invalid tmr step");
+ 	  return t;
+ 	}
+       if (TMR_OFFSET (t) && TREE_CODE (TMR_OFFSET (t)) != INTEGER_CST)
+ 	{
+ 	  error ("invalid tmr offset");
+ 	  return t;
+ 	}
+ 
+       *walk_subtrees = 0;
+       break;
+ 
      case NOP_EXPR:
      case CONVERT_EXPR:
      case FIX_TRUNC_EXPR:
Index: tree-ssanames.c
===================================================================
*** tree-ssanames.c	(revision 108807)
--- tree-ssanames.c	(working copy)
*************** make_ssa_name (tree var, tree stmt)
*** 123,130 ****
    tree t;
    use_operand_p imm;
  
!   gcc_assert (DECL_P (var)
! 	      || TREE_CODE (var) == INDIRECT_REF);
  
    gcc_assert (!stmt || EXPR_P (stmt) || TREE_CODE (stmt) == PHI_NODE);
  
--- 123,129 ----
    tree t;
    use_operand_p imm;
  
!   gcc_assert (DECL_P (var));
  
    gcc_assert (!stmt || EXPR_P (stmt) || TREE_CODE (stmt) == PHI_NODE);
  
*************** make_ssa_name (tree var, tree stmt)
*** 145,152 ****
    else
      {
        t = make_node (SSA_NAME);
!       SSA_NAME_VERSION (t) = num_ssa_names;
!       VEC_safe_push (tree, gc, ssa_names, t);
  #ifdef GATHER_STATISTICS
        ssa_name_nodes_created++;
  #endif
--- 144,162 ----
    else
      {
        t = make_node (SSA_NAME);
!       if (ssa_names)
! 	{
! 	  SSA_NAME_VERSION (t) = num_ssa_names;
! 	  VEC_safe_push (tree, gc, ssa_names, t);
! 	}
!       else
! 	{
! 	  /* The ssa name allocated from gimplification.  We won't assign it
! 	     a real version till the first time ssa form is built for the
! 	     function.  */
! 	  gcc_assert (TREE_CODE (var) == GVAR_DECL);
! 	  SSA_NAME_VERSION (t) = 0;
! 	}
  #ifdef GATHER_STATISTICS
        ssa_name_nodes_created++;
  #endif
*************** make_ssa_name (tree var, tree stmt)
*** 166,171 ****
--- 176,189 ----
    return t;
  }
  
+ /* Assign version and position in the list of ssa names to NAME.  */
+ 
+ void
+ register_tmp_ssa_name (tree name)
+ {
+   SSA_NAME_VERSION (name) = num_ssa_names;
+   VEC_safe_push (tree, gc, ssa_names, name);
+ }
  
  /* We no longer need the SSA_NAME expression VAR, release it so that
     it may be reused. 


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