OSDN Git Service

PR rtl-optimization/50249
[pf3gnuchains/gcc-fork.git] / gcc / gimple-fold.c
index 72dc42a..e345058 100644 (file)
@@ -294,42 +294,7 @@ fold_gimple_assign (gimple_stmt_iterator *si)
       {
         tree rhs = gimple_assign_rhs1 (stmt);
 
-        /* Try to fold a conditional expression.  */
-        if (TREE_CODE (rhs) == COND_EXPR)
-          {
-           tree op0 = COND_EXPR_COND (rhs);
-           tree tem;
-           bool set = false;
-           location_t cond_loc = EXPR_LOCATION (rhs);
-
-           if (COMPARISON_CLASS_P (op0))
-             {
-               fold_defer_overflow_warnings ();
-               tem = fold_binary_loc (cond_loc,
-                                  TREE_CODE (op0), TREE_TYPE (op0),
-                                  TREE_OPERAND (op0, 0),
-                                  TREE_OPERAND (op0, 1));
-               /* This is actually a conditional expression, not a GIMPLE
-                  conditional statement, however, the valid_gimple_rhs_p
-                  test still applies.  */
-               set = (tem && is_gimple_condexpr (tem)
-                      && valid_gimple_rhs_p (tem));
-               fold_undefer_overflow_warnings (set, stmt, 0);
-             }
-           else if (is_gimple_min_invariant (op0))
-             {
-               tem = op0;
-               set = true;
-             }
-           else
-             return NULL_TREE;
-
-           if (set)
-             result = fold_build3_loc (cond_loc, COND_EXPR, TREE_TYPE (rhs), tem,
-                                   COND_EXPR_THEN (rhs), COND_EXPR_ELSE (rhs));
-          }
-
-       else if (REFERENCE_CLASS_P (rhs))
+       if (REFERENCE_CLASS_P (rhs))
          return maybe_fold_reference (rhs, false);
 
        else if (TREE_CODE (rhs) == ADDR_EXPR)
@@ -469,11 +434,49 @@ fold_gimple_assign (gimple_stmt_iterator *si)
       break;
 
     case GIMPLE_TERNARY_RHS:
-      result = fold_ternary_loc (loc, subcode,
-                                TREE_TYPE (gimple_assign_lhs (stmt)),
-                                gimple_assign_rhs1 (stmt),
-                                gimple_assign_rhs2 (stmt),
-                                gimple_assign_rhs3 (stmt));
+      /* Try to fold a conditional expression.  */
+      if (gimple_assign_rhs_code (stmt) == COND_EXPR)
+       {
+         tree op0 = gimple_assign_rhs1 (stmt);
+         tree tem;
+         bool set = false;
+         location_t cond_loc = gimple_location (stmt);
+
+         if (COMPARISON_CLASS_P (op0))
+           {
+             fold_defer_overflow_warnings ();
+             tem = fold_binary_loc (cond_loc,
+                                    TREE_CODE (op0), TREE_TYPE (op0),
+                                    TREE_OPERAND (op0, 0),
+                                    TREE_OPERAND (op0, 1));
+             /* This is actually a conditional expression, not a GIMPLE
+                conditional statement, however, the valid_gimple_rhs_p
+                test still applies.  */
+             set = (tem && is_gimple_condexpr (tem)
+                    && valid_gimple_rhs_p (tem));
+             fold_undefer_overflow_warnings (set, stmt, 0);
+           }
+         else if (is_gimple_min_invariant (op0))
+           {
+             tem = op0;
+             set = true;
+           }
+         else
+           return NULL_TREE;
+
+         if (set)
+           result = fold_build3_loc (cond_loc, COND_EXPR,
+                                     TREE_TYPE (gimple_assign_lhs (stmt)), tem,
+                                     gimple_assign_rhs2 (stmt),
+                                     gimple_assign_rhs3 (stmt));
+       }
+
+      if (!result)
+       result = fold_ternary_loc (loc, subcode,
+                                  TREE_TYPE (gimple_assign_lhs (stmt)),
+                                  gimple_assign_rhs1 (stmt),
+                                  gimple_assign_rhs2 (stmt),
+                                  gimple_assign_rhs3 (stmt));
 
       if (result)
         {
@@ -548,6 +551,7 @@ gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
   reaching_vuse = gimple_vuse (stmt);
 
   push_gimplify_context (&gctx);
+  gctx.into_ssa = gimple_in_ssa_p (cfun);
 
   if (lhs == NULL_TREE)
     {
@@ -979,51 +983,6 @@ gimple_fold_builtin (gimple stmt)
   return result;
 }
 
-/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
-   is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
-   KNOWN_BINFO carries the binfo describing the true type of
-   OBJ_TYPE_REF_OBJECT(REF).  If a call to the function must be accompanied
-   with a this adjustment, the constant which should be added to this pointer
-   is stored to *DELTA.  If REFUSE_THUNKS is true, return NULL if the function
-   is a thunk (other than a this adjustment which is dealt with by DELTA). */
-
-tree
-gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo,
-                                 tree *delta)
-{
-  HOST_WIDE_INT i;
-  tree v, fndecl;
-
-  v = BINFO_VIRTUALS (known_binfo);
-  /* If there is no virtual methods leave the OBJ_TYPE_REF alone.  */
-  if (!v)
-    return NULL_TREE;
-  i = 0;
-  while (i != token)
-    {
-      i += (TARGET_VTABLE_USES_DESCRIPTORS
-           ? TARGET_VTABLE_USES_DESCRIPTORS : 1);
-      v = TREE_CHAIN (v);
-    }
-
-  /* If BV_VCALL_INDEX is non-NULL, give up.  */
-  if (TREE_TYPE (v))
-    return NULL_TREE;
-
-  fndecl = TREE_VALUE (v);
-
-  /* When cgraph node is missing and function is not public, we cannot
-     devirtualize.  This can happen in WHOPR when the actual method
-     ends up in other partition, because we found devirtualization
-     possibility too late.  */
-  if (!can_refer_decl_in_current_unit_p (TREE_VALUE (v)))
-    return NULL_TREE;
-
-  *delta = TREE_PURPOSE (v);
-  gcc_checking_assert (host_integerp (*delta, 0));
-  return fndecl;
-}
-
 /* Generate code adjusting the first parameter of a call statement determined
    by GSI by DELTA.  */
 
@@ -1146,7 +1105,7 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
   callee = gimple_call_fn (stmt);
   if (callee && TREE_CODE (callee) == OBJ_TYPE_REF)
     {
-      tree binfo, fndecl, delta, obj;
+      tree binfo, fndecl, obj;
       HOST_WIDE_INT token;
 
       if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE)
@@ -1160,10 +1119,9 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace)
       if (!binfo)
        return false;
       token = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee));
-      fndecl = gimple_get_virt_method_for_binfo (token, binfo, &delta);
+      fndecl = gimple_get_virt_method_for_binfo (token, binfo);
       if (!fndecl)
        return false;
-      gcc_assert (integer_zerop (delta));
       gimple_call_set_fndecl (stmt, fndecl);
       return true;
     }
@@ -1329,20 +1287,20 @@ fold_stmt (gimple_stmt_iterator *gsi)
   return fold_stmt_1 (gsi, false);
 }
 
-/* Perform the minimal folding on statement STMT.  Only operations like
+/* Perform the minimal folding on statement *GSI.  Only operations like
    *&x created by constant propagation are handled.  The statement cannot
    be replaced with a new one.  Return true if the statement was
    changed, false otherwise.
-   The statement STMT should be in valid gimple form but may
+   The statement *GSI should be in valid gimple form but may
    be in unfolded state as resulting from for example constant propagation
    which can produce *&x = 0.  */
 
 bool
-fold_stmt_inplace (gimple stmt)
+fold_stmt_inplace (gimple_stmt_iterator *gsi)
 {
-  gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
-  bool changed = fold_stmt_1 (&gsi, true);
-  gcc_assert (gsi_stmt (gsi) == stmt);
+  gimple stmt = gsi_stmt (*gsi);
+  bool changed = fold_stmt_1 (gsi, true);
+  gcc_assert (gsi_stmt (*gsi) == stmt);
   return changed;
 }
 
@@ -2962,6 +2920,9 @@ fold_const_aggregate_ref_1 (tree t, tree (*valueize) (tree))
   HOST_WIDE_INT offset, size, max_size;
   tree tem;
 
+  if (TREE_THIS_VOLATILE (t))
+    return NULL_TREE;
+
   if (TREE_CODE_CLASS (TREE_CODE (t)) == tcc_declaration)
     return get_symbol_constant_value (t);
 
@@ -3061,6 +3022,61 @@ fold_const_aggregate_ref (tree t)
   return fold_const_aggregate_ref_1 (t, NULL);
 }
 
+/* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN
+   is integer form of OBJ_TYPE_REF_TOKEN of the reference expression.
+   KNOWN_BINFO carries the binfo describing the true type of
+   OBJ_TYPE_REF_OBJECT(REF).  */
+
+tree
+gimple_get_virt_method_for_binfo (HOST_WIDE_INT token, tree known_binfo)
+{
+  unsigned HOST_WIDE_INT offset, size;
+  tree v, fn;
+
+  v = BINFO_VTABLE (known_binfo);
+  /* If there is no virtual methods table, leave the OBJ_TYPE_REF alone.  */
+  if (!v)
+    return NULL_TREE;
+
+  if (TREE_CODE (v) == POINTER_PLUS_EXPR)
+    {
+      offset = tree_low_cst (TREE_OPERAND (v, 1), 1) * BITS_PER_UNIT;
+      v = TREE_OPERAND (v, 0);
+    }
+  else
+    offset = 0;
+
+  if (TREE_CODE (v) != ADDR_EXPR)
+    return NULL_TREE;
+  v = TREE_OPERAND (v, 0);
+
+  if (TREE_CODE (v) != VAR_DECL
+      || !DECL_VIRTUAL_P (v)
+      || !DECL_INITIAL (v)
+      || DECL_INITIAL (v) == error_mark_node)
+    return NULL_TREE;
+  gcc_checking_assert (TREE_CODE (TREE_TYPE (v)) == ARRAY_TYPE);
+  size = tree_low_cst (TYPE_SIZE (TREE_TYPE (TREE_TYPE (v))), 1);
+  offset += token * size;
+  fn = fold_ctor_reference (TREE_TYPE (TREE_TYPE (v)), DECL_INITIAL (v),
+                           offset, size);
+  if (!fn)
+    return NULL_TREE;
+  gcc_assert (TREE_CODE (fn) == ADDR_EXPR
+             || TREE_CODE (fn) == FDESC_EXPR);
+  fn = TREE_OPERAND (fn, 0);
+  gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
+
+  /* When cgraph node is missing and function is not public, we cannot
+     devirtualize.  This can happen in WHOPR when the actual method
+     ends up in other partition, because we found devirtualization
+     possibility too late.  */
+  if (!can_refer_decl_in_current_unit_p (fn))
+    return NULL_TREE;
+
+  return fn;
+}
+
 /* Return true iff VAL is a gimple expression that is known to be
    non-negative.  Restricted to floating-point inputs.  */