{
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)
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)
{
reaching_vuse = gimple_vuse (stmt);
push_gimplify_context (&gctx);
+ gctx.into_ssa = gimple_in_ssa_p (cfun);
if (lhs == NULL_TREE)
{
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. */
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)
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;
}
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;
}
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);
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. */