OSDN Git Service

2010-12-02 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-ccp.c
index 8c42a63..30a0e14 100644 (file)
@@ -131,7 +131,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "target.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "dbgcnt.h"
 
 
@@ -168,6 +167,9 @@ static prop_value_t *const_val;
 
 static void canonicalize_float_value (prop_value_t *);
 static bool ccp_fold_stmt (gimple_stmt_iterator *);
+static tree fold_ctor_reference (tree type, tree ctor,
+                                unsigned HOST_WIDE_INT offset,
+                                unsigned HOST_WIDE_INT size);
 
 /* Dump constant propagation value VAL to file OUTF prefixed by PREFIX.  */
 
@@ -315,7 +317,14 @@ get_value (tree var)
 static inline tree
 get_constant_value (tree var)
 {
-  prop_value_t *val = get_value (var);
+  prop_value_t *val;
+  if (TREE_CODE (var) != SSA_NAME)
+    {
+      if (is_gimple_min_invariant (var))
+        return var;
+      return NULL_TREE;
+    }
+  val = get_value (var);
   if (val
       && val->lattice_val == CONSTANT
       && (TREE_CODE (val->value) != INTEGER_CST
@@ -509,9 +518,7 @@ get_value_from_alignment (tree expr)
   base = get_inner_reference (TREE_OPERAND (expr, 0),
                              &bitsize, &bitpos, &offset,
                              &mode, &align, &align, false);
-  if (TREE_CODE (base) == MISALIGNED_INDIRECT_REF)
-    val = get_value_for_expr (TREE_OPERAND (base, 0), true);
-  else if (TREE_CODE (base) == MEM_REF)
+  if (TREE_CODE (base) == MEM_REF)
     val = bit_value_binop (PLUS_EXPR, TREE_TYPE (expr),
                           TREE_OPERAND (base, 0), TREE_OPERAND (base, 1));
   else if (base
@@ -1310,170 +1317,374 @@ ccp_fold (gimple stmt)
     }
 }
 
-/* Return the tree representing the element referenced by T if T is an
-   ARRAY_REF or COMPONENT_REF into constant aggregates.  Return
-   NULL_TREE otherwise.  */
+/* See if we can find constructor defining value of BASE.
+   When we know the consructor with constant offset (such as
+   base is array[40] and we do know constructor of array), then
+   BIT_OFFSET is adjusted accordingly.
 
-tree
-fold_const_aggregate_ref (tree t)
+   As a special case, return error_mark_node when constructor
+   is not explicitly available, but it is known to be zero
+   such as 'static const int a;'.  */
+static tree
+get_base_constructor (tree base, HOST_WIDE_INT *bit_offset)
 {
-  tree base, ctor, idx, field;
-  unsigned HOST_WIDE_INT cnt;
-  tree cfield, cval;
-  tree tem;
+  HOST_WIDE_INT bit_offset2, size, max_size;
+  if (TREE_CODE (base) == MEM_REF)
+    {
+      if (!integer_zerop (TREE_OPERAND (base, 1)))
+       {
+         if (!host_integerp (TREE_OPERAND (base, 1), 0))
+           return NULL_TREE;
+         *bit_offset += (mem_ref_offset (base).low
+                         * BITS_PER_UNIT);
+       }
 
-  if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
-    return get_symbol_constant_value (t);
+      base = get_constant_value (TREE_OPERAND (base, 0));
+      if (!base || TREE_CODE (base) != ADDR_EXPR)
+        return NULL_TREE;
+      base = TREE_OPERAND (base, 0);
+    }
 
-  switch (TREE_CODE (t))
+  /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
+     DECL_INITIAL.  If BASE is a nested reference into another
+     ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
+     the inner reference.  */
+  switch (TREE_CODE (base))
     {
+    case VAR_DECL:
+      if (!const_value_known_p (base))
+       return NULL_TREE;
+
+      /* Fallthru.  */
+    case CONST_DECL:
+      if (!DECL_INITIAL (base)
+         && (TREE_STATIC (base) || DECL_EXTERNAL (base)))
+        return error_mark_node;
+      return DECL_INITIAL (base);
+
     case ARRAY_REF:
-      /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
-        DECL_INITIAL.  If BASE is a nested reference into another
-        ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
-        the inner reference.  */
-      base = TREE_OPERAND (t, 0);
-      switch (TREE_CODE (base))
-       {
-       case MEM_REF:
-         /* ???  We could handle this case.  */
-         if (!integer_zerop (TREE_OPERAND (base, 1)))
-           return NULL_TREE;
-         base = get_base_address (base);
-         if (!base
-             || TREE_CODE (base) != VAR_DECL)
-           return NULL_TREE;
+    case COMPONENT_REF:
+      base = get_ref_base_and_extent (base, &bit_offset2, &size, &max_size);
+      if (max_size == -1 || size != max_size)
+       return NULL_TREE;
+      *bit_offset +=  bit_offset2;
+      return get_base_constructor (base, bit_offset);
 
-         /* Fallthru.  */
-       case VAR_DECL:
-         if (!TREE_READONLY (base)
-             || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
-             || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
-                 && !varpool_get_node (base)->const_value_known))
-           return NULL_TREE;
+    case STRING_CST:
+    case CONSTRUCTOR:
+      return base;
 
-         ctor = DECL_INITIAL (base);
-         break;
+    default:
+      return NULL_TREE;
+    }
+}
 
-       case ARRAY_REF:
-       case COMPONENT_REF:
-         ctor = fold_const_aggregate_ref (base);
-         break;
+/* CTOR is STRING_CST.  Fold reference of type TYPE and size SIZE
+   to the memory at bit OFFSET.  
 
-       case STRING_CST:
-       case CONSTRUCTOR:
-         ctor = base;
-         break;
+   We do only simple job of folding byte accesses.  */
 
-       default:
-         return NULL_TREE;
-       }
+static tree
+fold_string_cst_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
+                               unsigned HOST_WIDE_INT size)
+{
+  if (INTEGRAL_TYPE_P (type)
+      && (TYPE_MODE (type)
+         == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+      && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
+         == MODE_INT)
+      && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
+      && size == BITS_PER_UNIT
+      && !(offset % BITS_PER_UNIT))
+    {
+      offset /= BITS_PER_UNIT;
+      if (offset < (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (ctor))
+       return build_int_cst_type (type, (TREE_STRING_POINTER (ctor)
+                                  [offset]));
+      /* Folding
+        const char a[20]="hello";
+        return a[10];
+
+        might lead to offset greater than string length.  In this case we
+        know value is either initialized to 0 or out of bounds.  Return 0
+        in both cases.  */
+      return build_zero_cst (type);
+    }
+  return NULL_TREE;
+}
 
-      if (ctor == NULL_TREE
-         || (TREE_CODE (ctor) != CONSTRUCTOR
-             && TREE_CODE (ctor) != STRING_CST)
-         || !TREE_STATIC (ctor))
-       return NULL_TREE;
+/* CTOR is CONSTRUCTOR of an array type.  Fold reference of type TYPE and size
+   SIZE to the memory at bit OFFSET.  */
 
-      /* Get the index.  If we have an SSA_NAME, try to resolve it
-        with the current lattice value for the SSA_NAME.  */
-      idx = TREE_OPERAND (t, 1);
-      switch (TREE_CODE (idx))
-       {
-       case SSA_NAME:
-         if ((tem = get_constant_value (idx))
-             && TREE_CODE (tem) == INTEGER_CST)
-           idx = tem;
-         else
-           return NULL_TREE;
-         break;
+static tree
+fold_array_ctor_reference (tree type, tree ctor,
+                          unsigned HOST_WIDE_INT offset,
+                          unsigned HOST_WIDE_INT size)
+{
+  unsigned HOST_WIDE_INT cnt;
+  tree cfield, cval;
+  double_int low_bound, elt_size;
+  double_int index, max_index;
+  double_int access_index;
+  tree domain_type = TYPE_DOMAIN (TREE_TYPE (ctor));
+  HOST_WIDE_INT inner_offset;
+
+  /* Compute low bound and elt size.  */
+  if (domain_type && TYPE_MIN_VALUE (domain_type))
+    {
+      /* Static constructors for variably sized objects makes no sense.  */
+      gcc_assert (TREE_CODE (TYPE_MIN_VALUE (domain_type)) == INTEGER_CST);
+      low_bound = tree_to_double_int (TYPE_MIN_VALUE (domain_type));
+    }
+  else
+    low_bound = double_int_zero;
+  /* Static constructors for variably sized objects makes no sense.  */
+  gcc_assert (TREE_CODE(TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))))
+             == INTEGER_CST);
+  elt_size =
+    tree_to_double_int (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor))));
+
+
+  /* We can handle only constantly sized accesses that are known to not
+     be larger than size of array element.  */
+  if (!TYPE_SIZE_UNIT (type)
+      || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST
+      || double_int_cmp (elt_size,
+                        tree_to_double_int (TYPE_SIZE_UNIT (type)), 0) < 0)
+    return NULL_TREE;
 
-       case INTEGER_CST:
-         break;
+  /* Compute the array index we look for.  */
+  access_index = double_int_udiv (uhwi_to_double_int (offset / BITS_PER_UNIT),
+                                 elt_size, TRUNC_DIV_EXPR);
+  access_index = double_int_add (access_index, low_bound);
 
-       default:
-         return NULL_TREE;
-       }
+  /* And offset within the access.  */
+  inner_offset = offset % (double_int_to_uhwi (elt_size) * BITS_PER_UNIT);
+
+  /* See if the array field is large enough to span whole access.  We do not
+     care to fold accesses spanning multiple array indexes.  */
+  if (inner_offset + size > double_int_to_uhwi (elt_size) * BITS_PER_UNIT)
+    return NULL_TREE;
 
-      /* Fold read from constant string.  */
-      if (TREE_CODE (ctor) == STRING_CST)
+  index = double_int_sub (low_bound, double_int_one);
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
+    {
+      /* Array constructor might explicitely set index, or specify range
+        or leave index NULL meaning that it is next index after previous
+        one.  */
+      if (cfield)
        {
-         if ((TYPE_MODE (TREE_TYPE (t))
-              == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-             && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-                 == MODE_INT)
-             && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
-             && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0)
-           return build_int_cst_type (TREE_TYPE (t),
-                                      (TREE_STRING_POINTER (ctor)
-                                       [TREE_INT_CST_LOW (idx)]));
-         return NULL_TREE;
+         if (TREE_CODE (cfield) == INTEGER_CST)
+           max_index = index = tree_to_double_int (cfield);
+         else
+           {
+             gcc_assert (TREE_CODE (cfield) == RANGE_EXPR);
+             index = tree_to_double_int (TREE_OPERAND (cfield, 0));
+             max_index = tree_to_double_int (TREE_OPERAND (cfield, 1));
+           }
        }
+      else
+       max_index = index = double_int_add (index, double_int_one);
 
-      /* Whoo-hoo!  I'll fold ya baby.  Yeah!  */
-      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
-       if (tree_int_cst_equal (cfield, idx))
-         {
-           STRIP_NOPS (cval);
-           if (TREE_CODE (cval) == ADDR_EXPR)
-             {
-               tree base = get_base_address (TREE_OPERAND (cval, 0));
-               if (base && TREE_CODE (base) == VAR_DECL)
-                 add_referenced_var (base);
-             }
-           return cval;
-         }
-      break;
+      /* Do we have match?  */
+      if (double_int_cmp (access_index, index, 1) >= 0
+         && double_int_cmp (access_index, max_index, 1) <= 0)
+       return fold_ctor_reference (type, cval, inner_offset, size);
+    }
+  /* When memory is not explicitely mentioned in constructor,
+     it is 0 (or out of range).  */
+  return build_zero_cst (type);
+}
 
-    case COMPONENT_REF:
-      /* Get a CONSTRUCTOR.  If BASE is a VAR_DECL, get its
-        DECL_INITIAL.  If BASE is a nested reference into another
-        ARRAY_REF or COMPONENT_REF, make a recursive call to resolve
-        the inner reference.  */
-      base = TREE_OPERAND (t, 0);
-      switch (TREE_CODE (base))
+/* CTOR is CONSTRUCTOR of an aggregate or vector.
+   Fold reference of type TYPE and size SIZE to the memory at bit OFFSET.  */
+
+static tree
+fold_nonarray_ctor_reference (tree type, tree ctor,
+                             unsigned HOST_WIDE_INT offset,
+                             unsigned HOST_WIDE_INT size)
+{
+  unsigned HOST_WIDE_INT cnt;
+  tree cfield, cval;
+
+  FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield,
+                           cval)
+    {
+      tree byte_offset = DECL_FIELD_OFFSET (cfield);
+      tree field_offset = DECL_FIELD_BIT_OFFSET (cfield);
+      tree field_size = DECL_SIZE (cfield);
+      double_int bitoffset;
+      double_int byte_offset_cst = tree_to_double_int (byte_offset);
+      double_int bits_per_unit_cst = uhwi_to_double_int (BITS_PER_UNIT);
+      double_int bitoffset_end;
+
+      /* Variable sized objects in static constructors makes no sense,
+        but field_size can be NULL for flexible array members.  */
+      gcc_assert (TREE_CODE (field_offset) == INTEGER_CST
+                 && TREE_CODE (byte_offset) == INTEGER_CST
+                 && (field_size != NULL_TREE
+                     ? TREE_CODE (field_size) == INTEGER_CST
+                     : TREE_CODE (TREE_TYPE (cfield)) == ARRAY_TYPE));
+
+      /* Compute bit offset of the field.  */
+      bitoffset = double_int_add (tree_to_double_int (field_offset),
+                                 double_int_mul (byte_offset_cst,
+                                                 bits_per_unit_cst));
+      /* Compute bit offset where the field ends.  */
+      if (field_size != NULL_TREE)
+       bitoffset_end = double_int_add (bitoffset,
+                                       tree_to_double_int (field_size));
+      else
+       bitoffset_end = double_int_zero;
+
+      /* Is OFFSET in the range (BITOFFSET, BITOFFSET_END)? */
+      if (double_int_cmp (uhwi_to_double_int (offset), bitoffset, 0) >= 0
+         && (field_size == NULL_TREE
+             || double_int_cmp (uhwi_to_double_int (offset),
+                                bitoffset_end, 0) < 0))
        {
-       case VAR_DECL:
-         if (!TREE_READONLY (base)
-             || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE
-             || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
-                 && !varpool_get_node (base)->const_value_known))
+         double_int access_end = double_int_add (uhwi_to_double_int (offset),
+                                                 uhwi_to_double_int (size));
+         double_int inner_offset = double_int_sub (uhwi_to_double_int (offset),
+                                                   bitoffset);
+         /* We do have overlap.  Now see if field is large enough to
+            cover the access.  Give up for accesses spanning multiple
+            fields.  */
+         if (double_int_cmp (access_end, bitoffset_end, 0) > 0)
            return NULL_TREE;
+         return fold_ctor_reference (type, cval,
+                                     double_int_to_uhwi (inner_offset), size);
+       }
+    }
+  /* When memory is not explicitely mentioned in constructor, it is 0.  */
+  return build_zero_cst (type);
+}
 
-         ctor = DECL_INITIAL (base);
-         break;
+/* CTOR is value initializing memory, fold reference of type TYPE and size SIZE
+   to the memory at bit OFFSET.  */
 
-       case ARRAY_REF:
-       case COMPONENT_REF:
-         ctor = fold_const_aggregate_ref (base);
-         break;
+static tree
+fold_ctor_reference (tree type, tree ctor, unsigned HOST_WIDE_INT offset,
+                    unsigned HOST_WIDE_INT size)
+{
+  tree ret;
+
+  /* We found the field with exact match.  */
+  if (useless_type_conversion_p (type, TREE_TYPE (ctor))
+      && !offset)
+    return canonicalize_constructor_val (ctor);
+
+  /* We are at the end of walk, see if we can view convert the
+     result.  */
+  if (!AGGREGATE_TYPE_P (TREE_TYPE (ctor)) && !offset
+      /* VIEW_CONVERT_EXPR is defined only for matching sizes.  */
+      && operand_equal_p (TYPE_SIZE (type),
+                         TYPE_SIZE (TREE_TYPE (ctor)), 0))
+    {
+      ret = canonicalize_constructor_val (ctor);
+      ret = fold_unary (VIEW_CONVERT_EXPR, type, ret);
+      if (ret)
+       STRIP_NOPS (ret);
+      return ret;
+    }
+  if (TREE_CODE (ctor) == STRING_CST)
+    return fold_string_cst_ctor_reference (type, ctor, offset, size);
+  if (TREE_CODE (ctor) == CONSTRUCTOR)
+    {
 
-       default:
-         return NULL_TREE;
-       }
+      if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE)
+       return fold_array_ctor_reference (type, ctor, offset, size);
+      else
+       return fold_nonarray_ctor_reference (type, ctor, offset, size);
+    }
+
+  return NULL_TREE;
+}
+
+/* Return the tree representing the element referenced by T if T is an
+   ARRAY_REF or COMPONENT_REF into constant aggregates.  Return
+   NULL_TREE otherwise.  */
 
-      if (ctor == NULL_TREE
-         || TREE_CODE (ctor) != CONSTRUCTOR
-         || !TREE_STATIC (ctor))
+tree
+fold_const_aggregate_ref (tree t)
+{
+  tree ctor, idx, base;
+  HOST_WIDE_INT offset, size, max_size;
+  tree tem;
+
+  if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
+    return get_symbol_constant_value (t);
+
+  tem = fold_read_from_constant_string (t);
+  if (tem)
+    return tem;
+
+  switch (TREE_CODE (t))
+    {
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      /* Constant indexes are handled well by get_base_constructor.
+        Only special case variable offsets.
+        FIXME: This code can't handle nested references with variable indexes
+        (they will be handled only by iteration of ccp).  Perhaps we can bring
+        get_ref_base_and_extent here and make it use get_constant_value.  */
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == SSA_NAME
+         && (idx = get_constant_value (TREE_OPERAND (t, 1)))
+         && host_integerp (idx, 0))
+       {
+         tree low_bound, unit_size;
+
+         /* If the resulting bit-offset is constant, track it.  */
+         if ((low_bound = array_ref_low_bound (t),
+              host_integerp (low_bound, 0))
+             && (unit_size = array_ref_element_size (t),
+                 host_integerp (unit_size, 1)))
+           {
+             offset = TREE_INT_CST_LOW (idx);
+             offset -= TREE_INT_CST_LOW (low_bound);
+             offset *= TREE_INT_CST_LOW (unit_size);
+             offset *= BITS_PER_UNIT;
+
+             base = TREE_OPERAND (t, 0);
+             ctor = get_base_constructor (base, &offset);
+             /* Empty constructor.  Always fold to 0. */
+             if (ctor == error_mark_node)
+               return build_zero_cst (TREE_TYPE (t));
+             /* Out of bound array access.  Value is undefined, but don't fold. */
+             if (offset < 0)
+               return NULL_TREE;
+             /* We can not determine ctor.  */
+             if (!ctor)
+               return NULL_TREE;
+             return fold_ctor_reference (TREE_TYPE (t), ctor, offset,
+                                         TREE_INT_CST_LOW (unit_size)
+                                         * BITS_PER_UNIT);
+           }
+       }
+      /* Fallthru.  */
+       
+    case COMPONENT_REF:
+    case BIT_FIELD_REF:
+    case TARGET_MEM_REF:
+    case MEM_REF:
+      base = get_ref_base_and_extent (t, &offset, &size, &max_size);
+      ctor = get_base_constructor (base, &offset);
+
+      /* Empty constructor.  Always fold to 0. */
+      if (ctor == error_mark_node)
+       return build_zero_cst (TREE_TYPE (t));
+      /* We do not know precise address.  */
+      if (max_size == -1 || max_size != size)
+       return NULL_TREE;
+      /* We can not determine ctor.  */
+      if (!ctor)
        return NULL_TREE;
 
-      field = TREE_OPERAND (t, 1);
+      /* Out of bound array access.  Value is undefined, but don't fold. */
+      if (offset < 0)
+       return NULL_TREE;
 
-      FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
-       if (cfield == field
-           /* FIXME: Handle bit-fields.  */
-           && ! DECL_BIT_FIELD (cfield))
-         {
-           STRIP_NOPS (cval);
-           if (TREE_CODE (cval) == ADDR_EXPR)
-             {
-               tree base = get_base_address (TREE_OPERAND (cval, 0));
-               if (base && TREE_CODE (base) == VAR_DECL)
-                 add_referenced_var (base);
-             }
-           return cval;
-         }
-      break;
+      return fold_ctor_reference (TREE_TYPE (t), ctor, offset, size);
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
@@ -1485,105 +1696,6 @@ fold_const_aggregate_ref (tree t)
        break;
       }
 
-    case MEM_REF:
-      /* Get the base object we are accessing.  */
-      base = TREE_OPERAND (t, 0);
-      if (TREE_CODE (base) == SSA_NAME
-         && (tem = get_constant_value (base)))
-       base = tem;
-      if (TREE_CODE (base) != ADDR_EXPR)
-       return NULL_TREE;
-      base = TREE_OPERAND (base, 0);
-      switch (TREE_CODE (base))
-       {
-       case VAR_DECL:
-         if (DECL_P (base)
-             && !AGGREGATE_TYPE_P (TREE_TYPE (base))
-             && integer_zerop (TREE_OPERAND (t, 1)))
-           {
-             tree res = get_symbol_constant_value (base);
-             if (res
-                 && !useless_type_conversion_p
-                       (TREE_TYPE (t), TREE_TYPE (res)))
-               res = fold_unary (VIEW_CONVERT_EXPR, TREE_TYPE (t), res);
-             return res;
-           }
-
-         if (!TREE_READONLY (base)
-             || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
-             || ((TREE_STATIC (base) || DECL_EXTERNAL (base))
-                 && !varpool_get_node (base)->const_value_known))
-           return NULL_TREE;
-
-         ctor = DECL_INITIAL (base);
-         break;
-
-       case STRING_CST:
-       case CONSTRUCTOR:
-         ctor = base;
-         break;
-
-       default:
-         return NULL_TREE;
-       }
-
-      if (ctor == NULL_TREE
-         || (TREE_CODE (ctor) != CONSTRUCTOR
-             && TREE_CODE (ctor) != STRING_CST)
-         || !TREE_STATIC (ctor))
-       return NULL_TREE;
-
-      /* Get the byte offset.  */
-      idx = TREE_OPERAND (t, 1);
-
-      /* Fold read from constant string.  */
-      if (TREE_CODE (ctor) == STRING_CST)
-       {
-         if ((TYPE_MODE (TREE_TYPE (t))
-              == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-             && (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-                 == MODE_INT)
-             && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor)))) == 1
-             && compare_tree_int (idx, TREE_STRING_LENGTH (ctor)) < 0)
-           return build_int_cst_type (TREE_TYPE (t),
-                                      (TREE_STRING_POINTER (ctor)
-                                       [TREE_INT_CST_LOW (idx)]));
-         return NULL_TREE;
-       }
-
-      /* ???  Implement byte-offset indexing into a non-array CONSTRUCTOR.  */
-      if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE
-         && (TYPE_MODE (TREE_TYPE (t))
-             == TYPE_MODE (TREE_TYPE (TREE_TYPE (ctor))))
-         && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t))) != 0
-         && integer_zerop
-              (int_const_binop
-                 (TRUNC_MOD_EXPR, idx,
-                  size_int (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t)))), 0)))
-       {
-         idx = int_const_binop (TRUNC_DIV_EXPR, idx,
-                                size_int (GET_MODE_SIZE
-                                            (TYPE_MODE (TREE_TYPE (t)))), 0);
-         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), cnt, cfield, cval)
-           if (tree_int_cst_equal (cfield, idx))
-             {
-               STRIP_NOPS (cval);
-               if (TREE_CODE (cval) == ADDR_EXPR)
-                 {
-                   tree base = get_base_address (TREE_OPERAND (cval, 0));
-                   if (base && TREE_CODE (base) == VAR_DECL)
-                     add_referenced_var (base);
-                 }
-               if (useless_type_conversion_p (TREE_TYPE (t), TREE_TYPE (cval)))
-                 return cval;
-               else if (CONSTANT_CLASS_P (cval))
-                 return fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (t), cval);
-               else
-                 return NULL_TREE;
-             }
-       }
-      break;
-
     default:
       break;
     }
@@ -2157,6 +2269,7 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi)
        tree lhs = gimple_call_lhs (stmt);
        tree val;
        tree argt;
+       tree callee;
        bool changed = false;
        unsigned i;
 
@@ -2197,6 +2310,25 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi)
              }
          }
 
+       callee = gimple_call_fn (stmt);
+       if (TREE_CODE (callee) == OBJ_TYPE_REF
+           && TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == SSA_NAME)
+         {
+           tree expr = OBJ_TYPE_REF_EXPR (callee);
+           OBJ_TYPE_REF_EXPR (callee) = valueize_op (expr);
+           if (TREE_CODE (OBJ_TYPE_REF_EXPR (callee)) == ADDR_EXPR)
+             {
+               tree t;
+               t = gimple_fold_obj_type_ref (callee, NULL_TREE);
+               if (t)
+                 {
+                   gimple_call_set_fn (stmt, t);
+                   changed = true;
+                 }
+             }
+           OBJ_TYPE_REF_EXPR (callee) = expr;
+         }
+
        return changed;
       }