OSDN Git Service

* defaults.h (CONSTANT_ADDRESS_P): Provide a default definition.
[pf3gnuchains/gcc-fork.git] / gcc / ipa-type-escape.c
index 3f61d4e..edfaab0 100644 (file)
@@ -1,12 +1,13 @@
 /* Type based alias analysis.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation,
+   Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* This pass determines which types in the program contain only
    instances that are completely encapsulated by the compilation unit.
@@ -43,11 +43,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tree-pass.h"
 #include "langhooks.h"
 #include "pointer-set.h"
+#include "splay-tree.h"
 #include "ggc.h"
 #include "ipa-utils.h"
 #include "ipa-type-escape.h"
-#include "c-common.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "cgraph.h"
 #include "output.h"
 #include "flags.h"
@@ -60,13 +60,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
    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;
@@ -135,17 +128,26 @@ static splay_tree uid_to_subtype_map;
    scan_for_refs.  */
 static struct pointer_set_t *visited_nodes;
 
+/* Visited stmts by walk_use_def_chains function because it's called
+   recursively.  */
+static struct pointer_set_t *visited_stmts;
+
 static bitmap_obstack ipa_obstack;
 
+/* Static functions from this file that are used 
+   before being defined.  */
+static unsigned int look_for_casts (tree);
+static bool is_cast_from_non_pointer (tree, gimple, void *);
+
 /* Get the name of TYPE or return the string "<UNNAMED>".  */
-static char*
+static const char*
 get_name_of_type (tree type)
 {
   tree name = TYPE_NAME (type);
   
   if (!name)
     /* Unnamed type, do what you like here.  */
-    return (char*)"<UNNAMED>";
+    return "<UNNAMED>";
   
   /* It will be a TYPE_DECL in the case of a typedef, otherwise, an
      identifier_node */
@@ -155,20 +157,20 @@ get_name_of_type (tree type)
          IDENTIFIER_NODE.  (Some decls, most often labels, may have
          zero as the DECL_NAME).  */
       if (DECL_NAME (name))
-       return (char*)IDENTIFIER_POINTER (DECL_NAME (name));
+       return IDENTIFIER_POINTER (DECL_NAME (name));
       else
        /* Unnamed type, do what you like here.  */
-       return (char*)"<UNNAMED>";
+       return "<UNNAMED>";
     }
   else if (TREE_CODE (name) == IDENTIFIER_NODE)
-    return (char*)IDENTIFIER_POINTER (name);
+    return IDENTIFIER_POINTER (name);
   else 
-    return (char*)"<UNNAMED>";
+    return "<UNNAMED>";
 }
 
 struct type_brand_s 
 {
-  char* name;
+  const char* name;
   int seq;
 };
 
@@ -194,8 +196,9 @@ compare_type_brand (splay_tree_key sk1, splay_tree_key sk2)
 /* This is a trivial algorithm for removing duplicate types.  This
    would not work for any language that used structural equivalence as
    the basis of its type system.  */
-/* Return either TYPE if this is first time TYPE has been seen an
-   compatible TYPE that has already been processed.  */ 
+/* Return TYPE if no type compatible with TYPE has been seen so far,
+   otherwise return a type compatible with TYPE that has already been
+   processed.  */
 
 static tree
 discover_unique_type (tree type)
@@ -216,7 +219,7 @@ discover_unique_type (tree type)
          /* Create an alias since this is just the same as
             other_type.  */
          tree other_type = (tree) result->value;
-         if (lang_hooks.types_compatible_p (type, other_type) == 1)
+         if (types_compatible_p (type, other_type))
            {
              free (brand);
              /* Insert this new type as an alias for other_type.  */
@@ -267,12 +270,12 @@ type_to_consider (tree type)
   switch (TREE_CODE (type))
     {
     case BOOLEAN_TYPE:
-    case CHAR_TYPE:
     case COMPLEX_TYPE:
     case ENUMERAL_TYPE:
     case INTEGER_TYPE:
     case QUAL_UNION_TYPE:
     case REAL_TYPE:
+    case FIXED_POINT_TYPE:
     case RECORD_TYPE:
     case UNION_TYPE:
     case VECTOR_TYPE:
@@ -305,7 +308,7 @@ get_canon_type (tree type, bool see_thru_ptrs, bool see_thru_arrays)
     while (POINTER_TYPE_P (type))
        type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
 
-  result = splay_tree_lookup(type_to_canon_type, (splay_tree_key) type);
+  result = splay_tree_lookup (type_to_canon_type, (splay_tree_key) type);
   
   if (result == NULL)
     return discover_unique_type (type);
@@ -395,7 +398,7 @@ ipa_type_escape_type_contained_p (tree type)
                        get_canon_type_uid (type, true, false));
 }
 
-/* Return true a modification to a field of type FIELD_TYPE cannot
+/* Return true if a modification to a field of type FIELD_TYPE cannot
    clobber a record of RECORD_TYPE.  */
 
 bool 
@@ -623,10 +626,15 @@ count_stars (tree* type_ptr)
 }
 
 enum cast_type {
-  CT_UP,
-  CT_DOWN,
-  CT_SIDEWAYS,
-  CT_USELESS
+  CT_UP = 0x1,
+  CT_DOWN = 0x2,
+  CT_SIDEWAYS = 0x4,
+  CT_USELESS = 0x8,
+  CT_FROM_P_BAD = 0x10,
+  CT_FROM_NON_P = 0x20,
+  CT_TO_NON_INTER = 0x40,
+  CT_FROM_MALLOC = 0x80,
+  CT_NO_CAST = 0x100
 };
 
 /* Check the cast FROM_TYPE to TO_TYPE.  This function requires that
@@ -649,17 +657,45 @@ check_cast_type (tree to_type, tree from_type)
   return CT_SIDEWAYS;
 }     
 
+/* This function returns nonzero if VAR is result of call 
+   to malloc function.  */
+
+static bool
+is_malloc_result (tree var)
+{
+  gimple def_stmt;
+
+  if (!var)
+    return false;
+  
+  if (SSA_NAME_IS_DEFAULT_DEF (var))
+    return false;
+
+  def_stmt = SSA_NAME_DEF_STMT (var);
+  
+  if (!is_gimple_call (def_stmt))
+    return false;
+
+  if (var != gimple_call_lhs (def_stmt))
+    return false;
+
+  return ((gimple_call_flags (def_stmt) & ECF_MALLOC) != 0);
+
+}
+
 /* Check a cast FROM this variable, TO_TYPE.  Mark the escaping types
-   if appropriate.  */ 
-static void
+   if appropriate. Returns cast_type as detected.  */
+static enum cast_type
 check_cast (tree to_type, tree from) 
 {
   tree from_type = get_canon_type (TREE_TYPE (from), false, false);
   bool to_interesting_type, from_interesting_type;
+  enum cast_type cast = CT_NO_CAST;
 
   to_type = get_canon_type (to_type, false, false);
   if (!from_type || !to_type || from_type == to_type)
-    return;
+    return cast;
 
   to_interesting_type = 
     ipa_type_escape_star_count_of_interesting_type (to_type) >= 0;
@@ -675,7 +711,8 @@ check_cast (tree to_type, tree from)
           both sides get marked as escaping.  Downcasts are not
           interesting here because if type is marked as escaping, all
           of its subtypes escape.  */
-       switch (check_cast_type (to_type, from_type)) 
+       cast = check_cast_type (to_type, from_type);
+       switch (cast) 
          {
          case CT_UP:
          case CT_USELESS:
@@ -686,17 +723,302 @@ check_cast (tree to_type, tree from)
            mark_type (to_type, FULL_ESCAPE);
            mark_type (from_type, FULL_ESCAPE);
            break;
+
+         default:
+           break;
          }
       }
     else
       {
-       /* 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);
+       /* This code excludes two cases from marking as escaped:
+          
+       1. if this is a cast of index of array of structures/unions
+       that happens before accessing array element, we should not 
+       mark it as escaped.
+       2. 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 (POINTER_TYPE_P (to_type) && !POINTER_TYPE_P (from_type))
+         cast = CT_FROM_NON_P;
+       else if (TREE_CODE (from) == SSA_NAME 
+                && is_malloc_result (from))
+         cast = CT_FROM_MALLOC;
+       else
+         {
+           cast = CT_FROM_P_BAD;
+           mark_type (to_type, FULL_ESCAPE);
+         }
       }
   else if (from_interesting_type)
-    mark_type (from_type, FULL_ESCAPE);
+    {
+      mark_type (from_type, FULL_ESCAPE);
+      cast = CT_TO_NON_INTER;
+    }
+
+  return cast;
+}
+
+
+/* Scan assignment statement S to see if there are any casts within it.  */
+
+static unsigned int
+look_for_casts_stmt (gimple s)
+{
+  unsigned int cast = 0;
+
+  gcc_assert (is_gimple_assign (s));
+
+  if (gimple_assign_cast_p (s))
+    {
+      tree castfromvar = gimple_assign_rhs1 (s);
+      cast |= check_cast (TREE_TYPE (gimple_assign_lhs (s)), castfromvar);
+    }
+  else
+    {
+      size_t i;
+      for (i = 0; i < gimple_num_ops (s); i++)
+       cast |= look_for_casts (gimple_op (s, i));
+    }
+
+  if (!cast)
+    cast = CT_NO_CAST;
+
+  return cast;
+} 
+
+
+typedef struct cast 
+{
+  int type;
+  gimple stmt;
+} cast_t;
+
+/* This function is a callback for walk_use_def_chains function called 
+   from is_array_access_through_pointer_and_index.  */
+
+static bool
+is_cast_from_non_pointer (tree var, gimple def_stmt, void *data)
+{
+  if (!def_stmt || !var)
+    return false;
+  
+  if (gimple_code (def_stmt) == GIMPLE_PHI)
+    return false;
+
+  if (SSA_NAME_IS_DEFAULT_DEF (var))
+      return false;
+
+  if (is_gimple_assign (def_stmt))
+    {
+      use_operand_p use_p; 
+      ssa_op_iter iter;
+      unsigned int cast = look_for_casts_stmt (def_stmt);
+
+      /* Check that only one cast happened, and it's of non-pointer
+        type.  */
+      if ((cast & CT_FROM_NON_P) == (CT_FROM_NON_P) 
+         && (cast & ~(CT_FROM_NON_P)) == 0)
+       {
+         ((cast_t *)data)->stmt = def_stmt;
+         ((cast_t *)data)->type++;
+
+         FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+           {
+             walk_use_def_chains (USE_FROM_PTR (use_p),
+                                  is_cast_from_non_pointer, data, false);
+             if (((cast_t*)data)->type == -1)
+               break;
+           }
+       }
+      /* Check that there is no cast, or cast is not harmful. */
+      else if ((cast & CT_NO_CAST) == (CT_NO_CAST)
+         || (cast & CT_DOWN) == (CT_DOWN)
+         || (cast & CT_UP) == (CT_UP)
+         || (cast & CT_USELESS) == (CT_USELESS)
+         || (cast & CT_FROM_MALLOC) == (CT_FROM_MALLOC))
+       {
+         FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+           {
+             walk_use_def_chains (USE_FROM_PTR (use_p),
+                                  is_cast_from_non_pointer, data, false);
+             if (((cast_t*)data)->type == -1)
+               break;
+           }       
+       }
+       /* The cast is harmful.  */
+       else
+         ((cast_t *)data)->type = -1;
+    }     
+
+  if (((cast_t*)data)->type == -1)
+    return true;
+  
+  return false;
+}
+
+/* When array element a_p[i] is accessed through the pointer a_p 
+   and index i, it's translated into the following sequence
+   in gimple:
+
+  i.1_5 = (unsigned int) i_1;
+  D.1605_6 = i.1_5 * 16;
+  D.1606_7 = (struct str_t *) D.1605_6;
+  a_p.2_8 = a_p;
+  D.1608_9 = D.1606_7 + a_p.2_8;
+
+  OP0 and OP1 are of the same pointer types and stand for 
+  D.1606_7 and a_p.2_8 or vise versa.
+
+  This function checks that:
+
+  1. one of OP0 and OP1 (D.1606_7) has passed only one cast from 
+  non-pointer type (D.1606_7 = (struct str_t *) D.1605_6;).
+
+  2. one of OP0 and OP1 which has passed the cast from 
+  non-pointer type (D.1606_7), is actually generated by multiplication of 
+  index by size of type to which both OP0 and OP1 point to
+  (in this case D.1605_6 = i.1_5 * 16; ).
+
+  3. an address of def of the var to which was made cast (D.1605_6) 
+  was not taken.(How can it happen?)
+
+  The following items are checked implicitly by the end of algorithm:
+
+  4. one of OP0 and OP1 (a_p.2_8) have never been cast 
+  (because if it was cast to pointer type, its type, that is also 
+  the type of OP0 and OP1, will be marked as escaped during 
+  analysis of casting stmt (when check_cast() is called 
+  from scan_for_refs for this stmt)).   
+
+  5. defs of OP0 and OP1 are not passed into externally visible function
+  (because if they are passed then their type, that is also the type of OP0
+  and OP1, will be marked and escaped during check_call function called from 
+  scan_for_refs with call stmt).
+
+  In total, 1-5 guaranty that it's an access to array by pointer and index. 
+
+*/
+
+bool
+is_array_access_through_pointer_and_index (enum tree_code code, tree op0, 
+                                          tree op1, tree *base, tree *offset,
+                                          gimple *offset_cast_stmt)
+{
+  tree before_cast;
+  gimple before_cast_def_stmt;
+  cast_t op0_cast, op1_cast;
+
+  *base = NULL;
+  *offset = NULL;
+  *offset_cast_stmt = NULL;
+
+  /* Check 1.  */
+  if (code == POINTER_PLUS_EXPR)
+    {
+      tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0));
+      tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
+
+      /* One of op0 and op1 is of pointer type and the other is numerical.  */
+      if (POINTER_TYPE_P (op0type) && NUMERICAL_TYPE_CHECK (op1type))
+       {
+         *base = op0;
+         *offset = op1;
+       }
+      else if (POINTER_TYPE_P (op1type) && NUMERICAL_TYPE_CHECK (op0type))
+       {
+         *base = op1;
+         *offset = op0;
+       }
+      else
+       return false;
+    }
+  else
+    {
+      /* Init data for walk_use_def_chains function.  */
+      op0_cast.type = op1_cast.type = 0;
+      op0_cast.stmt = op1_cast.stmt = NULL;
+
+      visited_stmts = pointer_set_create ();
+      walk_use_def_chains (op0, is_cast_from_non_pointer,(void *)(&op0_cast),
+                          false);
+      pointer_set_destroy (visited_stmts);
+
+      visited_stmts = pointer_set_create ();  
+      walk_use_def_chains (op1, is_cast_from_non_pointer,(void *)(&op1_cast),
+                          false);
+      pointer_set_destroy (visited_stmts);
+
+      if (op0_cast.type == 1 && op1_cast.type == 0)
+       {
+         *base = op1;
+         *offset = op0;
+         *offset_cast_stmt = op0_cast.stmt;
+       }
+      else if (op0_cast.type == 0 && op1_cast.type == 1)
+       {
+         *base = op0;
+         *offset = op1;      
+         *offset_cast_stmt = op1_cast.stmt;
+       }
+      else
+       return false;
+    }
+  
+  /* Check 2.  
+     offset_cast_stmt is of the form: 
+     D.1606_7 = (struct str_t *) D.1605_6;  */
+
+  if (*offset_cast_stmt)
+    {
+      before_cast = SINGLE_SSA_TREE_OPERAND (*offset_cast_stmt, SSA_OP_USE);
+      if (!before_cast)
+       return false;
+  
+      if (SSA_NAME_IS_DEFAULT_DEF (before_cast))
+       return false;
+  
+      before_cast_def_stmt = SSA_NAME_DEF_STMT (before_cast);
+      if (!before_cast_def_stmt)
+       return false;
+    }
+  else
+    before_cast_def_stmt = SSA_NAME_DEF_STMT (*offset);
+
+  /* before_cast_def_stmt should be of the form:
+     D.1605_6 = i.1_5 * 16; */
+  
+  if (is_gimple_assign (before_cast_def_stmt))
+    {
+      /* We expect temporary here.  */
+      if (!is_gimple_reg (gimple_assign_lhs (before_cast_def_stmt)))
+       return false;
+
+      if (gimple_assign_rhs_code (before_cast_def_stmt) == MULT_EXPR)
+       {
+         tree arg0 = gimple_assign_rhs1 (before_cast_def_stmt);
+         tree arg1 = gimple_assign_rhs2 (before_cast_def_stmt);
+         tree unit_size = 
+           TYPE_SIZE_UNIT (TREE_TYPE (TYPE_MAIN_VARIANT (TREE_TYPE (op0))));
+
+         if (!(CONSTANT_CLASS_P (arg0) 
+             && simple_cst_equal (arg0, unit_size))
+             && !(CONSTANT_CLASS_P (arg1) 
+             && simple_cst_equal (arg1, unit_size)))
+           return false;                          
+       }
+      else
+       return false;
+    }
+  else
+    return false;
+
+  /* Check 3.
+     check that address of D.1605_6 was not taken.
+     FIXME: if D.1605_6 is gimple reg than it cannot be addressable.  */
+
+  return true;
 }
 
 /* Register the parameter and return types of function FN.  The type
@@ -806,12 +1128,9 @@ check_operand (tree t)
 static void
 check_tree (tree t)
 {
-  if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR))
-    return;
-
-  while (TREE_CODE (t) == REALPART_EXPR 
-        || TREE_CODE (t) == IMAGPART_EXPR
-        || handled_component_p (t))
+  /* We want to catch here also REALPART_EXPR and IMAGEPART_EXPR,
+     but they already included in handled_component_p.  */
+  while (handled_component_p (t))
     {
       if (TREE_CODE (t) == ARRAY_REF)
        check_operand (TREE_OPERAND (t, 1));
@@ -823,7 +1142,11 @@ check_tree (tree t)
     check_tree (TREE_OPERAND (t, 0));
 
   if (SSA_VAR_P (t) || (TREE_CODE (t) == FUNCTION_DECL))
-    check_operand (t);
+    {
+      check_operand (t);
+      if (DECL_P (t) && DECL_INITIAL (t))
+       check_tree (DECL_INITIAL (t));
+    }
 }
 
 /* Create an address_of edge FROM_TYPE.TO_TYPE.  */
@@ -874,7 +1197,7 @@ mark_interesting_addressof (tree to_type, tree from_type)
                         to_uid, 
                         (splay_tree_value)type_map);
     }
-  bitmap_set_bit (type_map, TYPE_UID (to_type));
+  bitmap_set_bit (type_map, TYPE_UID (from_type)); 
 }
 
 /* Scan tree T to see if there are any addresses taken in within T.  */
@@ -910,37 +1233,37 @@ look_for_address_of (tree t)
 }
 
 
-/* Scan tree T to see if there are any casts within it.
-   LHS Is the LHS of the expression involving the cast.  */
+/* Scan tree T to see if there are any casts within it.  */
 
-static void 
-look_for_casts (tree lhs __attribute__((unused)), tree t)
+static unsigned int 
+look_for_casts (tree t)
 {
+  unsigned int cast = 0;
+
   if (is_gimple_cast (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR)
     {
       tree castfromvar = TREE_OPERAND (t, 0);
-      check_cast (TREE_TYPE (t), castfromvar);
+      cast = cast | check_cast (TREE_TYPE (t), castfromvar);
     }
-  else if (TREE_CODE (t) == COMPONENT_REF
-          || TREE_CODE (t) == INDIRECT_REF
-          || TREE_CODE (t) == BIT_FIELD_REF)
-    {
-      tree base = get_base_address (t);
-      while (t != base)
-       {
-         t = TREE_OPERAND (t, 0);
-         if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
-           {
-             /* This may be some part of a component ref.
-                IE it may be a.b.VIEW_CONVERT_EXPR<weird_type>(c).d, AFAIK.
-                castfromref will give you a.b.c, not a. */
-             tree castfromref = TREE_OPERAND (t, 0);
-             check_cast (TREE_TYPE (t), castfromref);
-           }
-         else if (TREE_CODE (t) == COMPONENT_REF)
-           get_canon_type (TREE_TYPE (TREE_OPERAND (t, 1)), false, false);
-       }
-    } 
+  else 
+    while (handled_component_p (t))
+      {
+       t = TREE_OPERAND (t, 0);
+       if (TREE_CODE (t) == VIEW_CONVERT_EXPR)
+         {
+           /* This may be some part of a component ref.
+              IE it may be a.b.VIEW_CONVERT_EXPR<weird_type>(c).d, AFAIK.
+              castfromref will give you a.b.c, not a. */
+           tree castfromref = TREE_OPERAND (t, 0);
+           cast = cast | check_cast (TREE_TYPE (t), castfromref);
+         }
+       else if (TREE_CODE (t) == COMPONENT_REF)
+         get_canon_type (TREE_TYPE (TREE_OPERAND (t, 1)), false, false);
+      }
+
+  if (!cast)
+    cast = CT_NO_CAST;
+  return cast;
 } 
 
 /* Check to see if T is a read or address of operation on a static var
@@ -950,7 +1273,7 @@ static void
 check_rhs_var (tree t)
 {
   look_for_address_of (t);
-  check_tree(t);
+  check_tree (t);
 }
 
 /* Check to see if T is an assignment to a static var we are
@@ -959,7 +1282,7 @@ check_rhs_var (tree t)
 static void
 check_lhs_var (tree t)
 {
-  check_tree(t);
+  check_tree (t);
 }
 
 /* This is a scaled down version of get_asm_expr_operands from
@@ -970,35 +1293,15 @@ check_lhs_var (tree t)
    analyzed and STMT is the actual asm statement.  */
 
 static void
-get_asm_expr_operands (tree stmt)
+check_asm (gimple stmt)
 {
-  int noutputs = list_length (ASM_OUTPUTS (stmt));
-  const char **oconstraints
-    = (const char **) alloca ((noutputs) * sizeof (const char *));
-  int i;
-  tree link;
-  const char *constraint;
-  bool allows_mem, allows_reg, is_inout;
-  
-  for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
-    {
-      oconstraints[i] = constraint
-       = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
-      parse_output_constraint (&constraint, i, 0, 0,
-                              &allows_mem, &allows_reg, &is_inout);
-      
-      check_lhs_var (TREE_VALUE (link));
-    }
+  size_t i;
 
-  for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link))
-    {
-      constraint
-       = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
-      parse_input_constraint (&constraint, 0, 0, noutputs, 0,
-                             oconstraints, &allows_mem, &allows_reg);
-      
-      check_rhs_var (TREE_VALUE (link));
-    }
+  for (i = 0; i < gimple_asm_noutputs (stmt); i++)
+    check_lhs_var (gimple_asm_output_op (stmt, i));
+
+  for (i = 0; i < gimple_asm_ninputs (stmt); i++)
+    check_rhs_var (gimple_asm_input_op (stmt, i));
   
   /* There is no code here to check for asm memory clobbers.  The
      casual maintainer might think that such code would be necessary,
@@ -1008,29 +1311,22 @@ get_asm_expr_operands (tree stmt)
      assumed to already escape.  So, we are protected here.  */
 }
 
-/* Check the parameters of a function call to CALL_EXPR to mark the
+
+/* Check the parameters of function call to CALL to mark the
    types that pass across the function boundary.  Also check to see if
    this is either an indirect call, a call outside the compilation
    unit.  */
 
-static bool
-check_call (tree call_expr) 
+static void
+check_call (gimple call)
 {
-  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);
-  tree argument;
+  tree callee_t = gimple_call_fndecl (call);
   struct cgraph_node* callee;
   enum availability avail = AVAIL_NOT_AVAILABLE;
+  size_t i;
 
-  for (operand = operand_list;
-       operand != NULL_TREE;
-       operand = TREE_CHAIN (operand))
-    {
-      tree argument = TREE_VALUE (operand);
-      check_rhs_var (argument);
-    }
+  for (i = 0; i < gimple_call_num_args (call); i++)
+    check_rhs_var (gimple_call_arg (call, i));
   
   if (callee_t)
     {
@@ -1043,17 +1339,15 @@ check_call (tree call_expr)
         parameters.  */
       if (TYPE_ARG_TYPES (TREE_TYPE (callee_t)))
        {
-         operand = operand_list;
-         for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t));
+         for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t)), i = 0;
               arg_type && TREE_VALUE (arg_type) != void_type_node;
-              arg_type = TREE_CHAIN (arg_type))
+              arg_type = TREE_CHAIN (arg_type), i++)
            {
+             tree operand = gimple_call_arg (call, i);
              if (operand)
                {
-                 argument = TREE_VALUE (operand);
                  last_arg_type = TREE_VALUE(arg_type);
-                 check_cast (last_arg_type, argument);
-                 operand = TREE_CHAIN (operand);
+                 check_cast (last_arg_type, operand);
                }
              else 
                /* The code reaches here for some unfortunate
@@ -1067,17 +1361,15 @@ check_call (tree call_expr)
          /* FIXME - According to Geoff Keating, we should never
             have to do this; the front ends should always process
             the arg list from the TYPE_ARG_LIST. */
-         operand = operand_list;
-         for (arg_type = DECL_ARGUMENTS (callee_t); 
+         for (arg_type = DECL_ARGUMENTS (callee_t), i = 0;
               arg_type;
-              arg_type = TREE_CHAIN (arg_type))
+              arg_type = TREE_CHAIN (arg_type), i++)
            {
+             tree operand = gimple_call_arg (call, i);
              if (operand)
                {
-                 argument = TREE_VALUE (operand);
-                 last_arg_type = TREE_TYPE(arg_type);
-                 check_cast (last_arg_type, argument);
-                 operand = TREE_CHAIN (operand);
+                 last_arg_type = TREE_TYPE (arg_type);
+                 check_cast (last_arg_type, operand);
                } 
              else 
                /* The code reaches here for some unfortunate
@@ -1090,13 +1382,11 @@ check_call (tree call_expr)
       /* In the case where we have a var_args function, we need to
         check the remaining parameters against the last argument.  */
       arg_type = last_arg_type;
-      for (;
-          operand != NULL_TREE;
-          operand = TREE_CHAIN (operand))
+      for ( ; i < gimple_call_num_args (call); i++)
        {
-         argument = TREE_VALUE (operand);
+         tree operand = gimple_call_arg (call, i);
          if (arg_type)
-           check_cast (arg_type, argument);
+           check_cast (arg_type, operand);
          else 
            {
              /* The code reaches here for some unfortunate
@@ -1104,7 +1394,7 @@ check_call (tree call_expr)
                 argument types.  Most of these functions have
                 been marked as having their parameters not
                 escape, but for the rest, the type is doomed.  */
-             tree type = get_canon_type (TREE_TYPE (argument), false, false);
+             tree type = get_canon_type (TREE_TYPE (operand), false, false);
              mark_interesting_type (type, FULL_ESCAPE);
            }
        }
@@ -1115,19 +1405,16 @@ check_call (tree call_expr)
      are any bits available for the callee (such as by declaration or
      because it is builtin) and process solely on the basis of those
      bits. */
-
   if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE)
     {
       /* If this is a direct call to an external function, mark all of
         the parameter and return types.  */
-      for (operand = operand_list;
-          operand != NULL_TREE;
-          operand = TREE_CHAIN (operand))
+      for (i = 0; i < gimple_call_num_args (call); i++)
        {
-         tree type = 
-           get_canon_type (TREE_TYPE (TREE_VALUE (operand)), false, false);
+         tree operand = gimple_call_arg (call, i);
+         tree type = get_canon_type (TREE_TYPE (operand), false, false);
          mark_interesting_type (type, EXPOSED_PARAMETER);
-    }
+       }
          
       if (callee_t) 
        {
@@ -1136,7 +1423,6 @@ check_call (tree call_expr)
          mark_interesting_type (type, EXPOSED_PARAMETER);
        }
     }
-  return (flags & ECF_MALLOC);
 }
 
 /* CODE is the operation on OP0 and OP1.  OP0 is the operand that we
@@ -1145,163 +1431,170 @@ static bool
 okay_pointer_operation (enum tree_code code, tree op0, tree op1)
 {
   tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0));
-  tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
-  if (POINTER_TYPE_P (op1type))
-    return false;
+
   switch (code)
     {
     case MULT_EXPR:
-    case PLUS_EXPR:
+      /* Multiplication does not change alignment.  */
+      return true;
+      break;
     case MINUS_EXPR:
-      /* TODO: Handle multiples of op0 size as well */
-      if (operand_equal_p (size_in_bytes (op0type), op1, 0))
-       return true;
-      /* fallthrough */
+    case PLUS_EXPR:
+    case POINTER_PLUS_EXPR:
+      {
+       tree base, offset;
+       gimple offset_cast_stmt;
+
+       if (POINTER_TYPE_P (op0type)
+           && TREE_CODE (op0) == SSA_NAME 
+           && TREE_CODE (op1) == SSA_NAME 
+           && is_array_access_through_pointer_and_index (code, op0, op1, 
+                                                         &base, 
+                                                         &offset, 
+                                                         &offset_cast_stmt))
+         return true;
+       else
+         {
+           tree size_of_op0_points_to = TYPE_SIZE_UNIT (TREE_TYPE (op0type));
+           
+           if (CONSTANT_CLASS_P (op1)
+               && size_of_op0_points_to
+               && multiple_of_p (TREE_TYPE (size_of_op0_points_to), 
+                                 op1, size_of_op0_points_to))
+             return true;
 
+           if (CONSTANT_CLASS_P (op0) 
+               && size_of_op0_points_to
+               && multiple_of_p (TREE_TYPE (size_of_op0_points_to), 
+                                 op0, size_of_op0_points_to))
+             return true;          
+         }
+      }
+      break;
     default:
       return false;
     }
   return false;
 }
 
-/* TP is the part of the tree currently under the microscope.
-   WALK_SUBTREES is part of the walk_tree api but is unused here.
-   DATA is cgraph_node of the function being walked.  */
 
-/* FIXME: When this is converted to run over SSA form, this code
-   should be converted to use the operand scanner.  */
 
-static tree
-scan_for_refs (tree *tp, int *walk_subtrees, void *data)
+/* Helper for scan_for_refs.  Check the operands of an assignment to
+   mark types that may escape.  */
+
+static void
+check_assign (gimple t)
 {
-  struct cgraph_node *fn = data;
-  tree t = *tp;
+  /* First look on the lhs and see what variable is stored to */
+  check_lhs_var (gimple_assign_lhs (t));
 
-  switch (TREE_CODE (t))  
+  /* For the purposes of figuring out what the cast affects */
+
+  /* Next check the operands on the rhs to see if they are ok. */
+  switch (TREE_CODE_CLASS (gimple_assign_rhs_code (t)))
     {
-    case VAR_DECL:
-      if (DECL_INITIAL (t))
-       walk_tree (&DECL_INITIAL (t), scan_for_refs, fn, visited_nodes);
-      *walk_subtrees = 0;
+    case tcc_binary:       
+      {
+       tree op0 = gimple_assign_rhs1 (t);
+       tree type0 = get_canon_type (TREE_TYPE (op0), false, false);
+       tree op1 = gimple_assign_rhs2 (t);
+       tree type1 = get_canon_type (TREE_TYPE (op1), false, false);
+
+       /* If this is pointer arithmetic of any bad sort, then
+           we need to mark the types as bad.  For binary
+           operations, no binary operator we currently support
+           is always "safe" in regard to what it would do to
+           pointers for purposes of determining which types
+           escape, except operations of the size of the type.
+           It is possible that min and max under the right set
+           of circumstances and if the moon is in the correct
+           place could be safe, but it is hard to see how this
+           is worth the effort.  */
+       if (type0 && POINTER_TYPE_P (type0)
+           && !okay_pointer_operation (gimple_assign_rhs_code (t), op0, op1))
+         mark_interesting_type (type0, FULL_ESCAPE);
+
+       if (type1 && POINTER_TYPE_P (type1)
+           && !okay_pointer_operation (gimple_assign_rhs_code (t), op1, op0))
+         mark_interesting_type (type1, FULL_ESCAPE);
+
+       look_for_casts (op0);
+       look_for_casts (op1);
+       check_rhs_var (op0);
+       check_rhs_var (op1);
+      }
       break;
 
-    case MODIFY_EXPR:
+    case tcc_unary:
       {
-       /* First look on the lhs and see what variable is stored to */
-       tree lhs = TREE_OPERAND (t, 0);
-       tree rhs = TREE_OPERAND (t, 1);
+       tree op0 = gimple_assign_rhs1 (t);
+       tree type0 = get_canon_type (TREE_TYPE (op0), false, false);
+
+       /* For unary operations, if the operation is NEGATE or ABS on
+          a pointer, this is also considered pointer arithmetic and
+          thus, bad for business.  */
+       if (type0
+           && POINTER_TYPE_P (type0)
+           && (TREE_CODE (op0) == NEGATE_EXPR
+             || TREE_CODE (op0) == ABS_EXPR))
+         mark_interesting_type (type0, FULL_ESCAPE);
+
+       check_rhs_var (op0);
+       look_for_casts (op0);
+      }
+      break;
 
-       check_lhs_var (lhs);
-       check_cast (TREE_TYPE (lhs), rhs);
+    case tcc_reference:
+      look_for_casts (gimple_assign_rhs1 (t));
+      check_rhs_var (gimple_assign_rhs1 (t));
+      break;
 
-       /* For the purposes of figuring out what the cast affects */
+    case tcc_declaration:
+      check_rhs_var (gimple_assign_rhs1 (t));
+      break;
 
-       /* Next check the operands on the rhs to see if they are ok. */
-       switch (TREE_CODE_CLASS (TREE_CODE (rhs))) 
-         {
-         case tcc_binary:          
-           {
-             tree op0 = TREE_OPERAND (rhs, 0);
-             tree type0 = get_canon_type (TREE_TYPE (op0), false, false);
-             tree op1 = TREE_OPERAND (rhs, 1);
-             tree type1 = get_canon_type (TREE_TYPE (op1), false, false);
-             /* If this is pointer arithmetic of any bad sort, then
-                we need to mark the types as bad.  For binary
-                operations, no binary operator we currently support
-                is always "safe" in regard to what it would do to
-                pointers for purposes of determining which types
-                escape, except operations of the size of the type.
-                It is possible that min and max under the right set
-                of circumstances and if the moon is in the correct
-                place could be safe, but it is hard to see how this
-                is worth the effort.  */
-             if (type0 && POINTER_TYPE_P (type0)
-                 && !okay_pointer_operation (TREE_CODE (rhs), op0, op1))
-               mark_interesting_type (type0, FULL_ESCAPE);
-             if (type1 && POINTER_TYPE_P (type1)
-                 && !okay_pointer_operation (TREE_CODE (rhs), op1, op0))
-               mark_interesting_type (type1, FULL_ESCAPE);
-             
-             look_for_casts (lhs, op0);
-             look_for_casts (lhs, op1);
-             check_rhs_var (op0);
-             check_rhs_var (op1);
-           }
-           break;
-         case tcc_unary:
-           {
-             tree op0 = TREE_OPERAND (rhs, 0);
-             tree type0 = get_canon_type (TREE_TYPE (op0), false, false);
-             /* For unary operations, if the operation is NEGATE or
-                ABS on a pointer, this is also considered pointer
-                arithmetic and thus, bad for business.  */
-             if (type0 && (TREE_CODE (op0) == NEGATE_EXPR
-                  || TREE_CODE (op0) == ABS_EXPR)
-                 && POINTER_TYPE_P (type0))
-               {
-                 mark_interesting_type (type0, FULL_ESCAPE);
-               }
-             check_rhs_var (op0);
-             look_for_casts (lhs, op0);
-             look_for_casts (lhs, rhs);
-           }
+    case tcc_expression:
+      if (gimple_assign_rhs_code (t) == ADDR_EXPR)
+       {
+         tree rhs = gimple_assign_rhs1 (t);
+         look_for_casts (TREE_OPERAND (rhs, 0));
+         check_rhs_var (rhs);
+       }
+      break;
 
-           break;
-         case tcc_reference:
-           look_for_casts (lhs, rhs);
-           check_rhs_var (rhs);
-           break;
-         case tcc_declaration:
-           check_rhs_var (rhs);
-           break;
-         case tcc_expression:
-           switch (TREE_CODE (rhs)) 
-             {
-             case ADDR_EXPR:
-               look_for_casts (lhs, TREE_OPERAND (rhs, 0));
-               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;
-             }
-           break;
-         default:
-           break;
-         }
-       *walk_subtrees = 0;
-      }
+    default:
       break;
+    }
+}
+
+
+/* Scan statement T for references to types and mark anything
+   interesting.  */
 
-    case ADDR_EXPR:
-      /* This case is here to find addresses on rhs of constructors in
-        decl_initial of static variables. */
-      check_rhs_var (t);
-      *walk_subtrees = 0;
+static void
+scan_for_refs (gimple t)
+{
+  switch (gimple_code (t))  
+    {
+    case GIMPLE_ASSIGN:
+      check_assign (t);
       break;
 
-    case CALL_EXPR: 
+    case GIMPLE_CALL: 
+      /* If this is a call to malloc, squirrel away the result so we
+        do mark the resulting cast as being bad.  */
       check_call (t);
-      *walk_subtrees = 0;
       break;
       
-    case ASM_EXPR:
-      get_asm_expr_operands (t);
-      *walk_subtrees = 0;
+    case GIMPLE_ASM:
+      check_asm (t);
       break;
       
     default:
       break;
     }
-  return NULL;
+
+  return;
 }
 
 
@@ -1314,7 +1607,6 @@ ipa_init (void)
   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);
@@ -1333,12 +1625,12 @@ ipa_init (void)
 
 /* Check out the rhs of a static or global initialization VNODE to see
    if any of them contain addressof operations.  Note that some of
-   these variables may  not even be referenced in the code in this
+   these variables may not even be referenced in the code in this
    compilation unit but their right hand sides may contain references
    to variables defined within this unit.  */
 
 static void 
-analyze_variable (struct cgraph_varpool_node *vnode)
+analyze_variable (struct varpool_node *vnode)
 {
   tree global = vnode->decl;
   tree type = get_canon_type (TREE_TYPE (global), false, false);
@@ -1352,7 +1644,7 @@ analyze_variable (struct cgraph_varpool_node *vnode)
   gcc_assert (TREE_CODE (global) == VAR_DECL);
 
   if (DECL_INITIAL (global))
-    walk_tree (&DECL_INITIAL (global), scan_for_refs, NULL, visited_nodes);
+    check_tree (DECL_INITIAL (global));
 }
 
 /* This is the main routine for finding the reference patterns for
@@ -1373,10 +1665,9 @@ analyze_function (struct cgraph_node *fn)
 
     FOR_EACH_BB_FN (this_block, this_cfun)
       {
-       block_stmt_iterator bsi;
-       for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
-         walk_tree (bsi_stmt_ptr (bsi), scan_for_refs, 
-                    fn, visited_nodes);
+       gimple_stmt_iterator gsi;
+       for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi))
+         scan_for_refs (gsi_stmt (gsi));
       }
   }
 
@@ -1384,7 +1675,7 @@ analyze_function (struct cgraph_node *fn)
   if (DECL_STRUCT_FUNCTION (decl))
     {
       tree step;
-      for (step = DECL_STRUCT_FUNCTION (decl)->unexpanded_var_list;
+      for (step = DECL_STRUCT_FUNCTION (decl)->local_decls;
           step;
           step = TREE_CHAIN (step))
        {
@@ -1392,8 +1683,7 @@ analyze_function (struct cgraph_node *fn)
          if (TREE_CODE (var) == VAR_DECL 
              && DECL_INITIAL (var)
              && !TREE_STATIC (var))
-           walk_tree (&DECL_INITIAL (var), scan_for_refs, 
-                      fn, visited_nodes);
+           check_tree (DECL_INITIAL (var));
          get_canon_type (TREE_TYPE (var), false, false);
        }
     }
@@ -1413,7 +1703,7 @@ type_for_uid (int uid)
   else return NULL;
 }
 
-/* Return the a bitmap with the subtypes of the type for UID.  If it
+/* Return a bitmap with the subtypes of the type for UID.  If it
    does not exist, return either NULL or a new bitmap depending on the
    value of CREATE.  */ 
 
@@ -1671,11 +1961,11 @@ close_addressof_down (int uid)
 \f
 /* The main entry point for type escape analysis.  */
 
-static void
+static unsigned int
 type_escape_execute (void)
 {
   struct cgraph_node *node;
-  struct cgraph_varpool_node *vnode;
+  struct varpool_node *vnode;
   unsigned int i;
   bitmap_iterator bi;
   splay_tree_node result;
@@ -1683,10 +1973,10 @@ type_escape_execute (void)
   ipa_init ();
 
   /* Process all of the variables first.  */
-  for (vnode = cgraph_varpool_nodes_queue; vnode; vnode = vnode->next_needed)
+  FOR_EACH_STATIC_VARIABLE (vnode)
     analyze_variable (vnode);
 
-  /* Process all of the functions. next
+  /* Process all of the functions next.
 
      We do not want to process any of the clones so we check that this
      is a master clone.  However, we do need to process any
@@ -1694,9 +1984,7 @@ type_escape_execute (void)
      they may cause a type variable to escape.  
   */
   for (node = cgraph_nodes; node; node = node->next)
-    if (node->analyzed 
-       && (cgraph_is_master_clone (node)
-           || (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE)))
+    if (node->analyzed)
       analyze_function (node);
 
 
@@ -1817,19 +2105,21 @@ type_escape_execute (void)
   BITMAP_FREE (global_types_exposed_parameter);
   BITMAP_FREE (been_there_done_that);
   BITMAP_FREE (bitmap_tmp);
-  BITMAP_FREE (results_of_malloc);
+  return 0;
 }
 
 static bool
 gate_type_escape_vars (void)
 {
-  return (flag_unit_at_a_time != 0 && flag_ipa_type_escape
+  return (flag_ipa_type_escape
          /* Don't bother doing anything if the program has errors.  */
          && !(errorcount || sorrycount));
 }
 
-struct tree_opt_pass pass_ipa_type_escape =
+struct simple_ipa_opt_pass pass_ipa_type_escape =
 {
+ {
+  SIMPLE_IPA_PASS,
   "type-escape-var",                   /* name */
   gate_type_escape_vars,               /* gate */
   type_escape_execute,                 /* execute */
@@ -1841,7 +2131,6 @@ struct tree_opt_pass pass_ipa_type_escape =
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                    /* letter */
+  0                                     /* todo_flags_finish */
+ }
 };
-