}
}
}
+ else if (TREE_CODE (rhs) == CONSTRUCTOR
+ && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE
+ && (CONSTRUCTOR_NELTS (rhs)
+ == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs))))
+ {
+ unsigned i;
+ tree val, list;
+
+ list = NULL_TREE;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val)
+ {
+ if (TREE_CODE (val) == SSA_NAME
+ && get_value (val)->lattice_val == CONSTANT)
+ val = get_value (val)->value;
+ if (TREE_CODE (val) == INTEGER_CST
+ || TREE_CODE (val) == REAL_CST
+ || TREE_CODE (val) == FIXED_CST)
+ list = tree_cons (NULL_TREE, val, list);
+ else
+ return NULL_TREE;
+ }
+
+ return build_vector (TREE_TYPE (rhs), nreverse (list));
+ }
if (kind == tcc_reference)
{
if (TREE_CODE (base) == SSA_NAME
&& (value = get_value (base))
&& value->lattice_val == CONSTANT
- && TREE_CODE (value->value) == ADDR_EXPR)
+ && TREE_CODE (value->value) == ADDR_EXPR
+ && useless_type_conversion_p (TREE_TYPE (t),
+ TREE_TYPE (TREE_TYPE (value->value))))
return fold_const_aggregate_ref (TREE_OPERAND (value->value, 0));
break;
}
build_fold_addr_expr (tem));
}
+ else if (TREE_CODE (rhs) == CONSTRUCTOR
+ && TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE
+ && (CONSTRUCTOR_NELTS (rhs)
+ == TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs))))
+ {
+ /* Fold a constant vector CONSTRUCTOR to VECTOR_CST. */
+ unsigned i;
+ tree val;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), i, val)
+ if (TREE_CODE (val) != INTEGER_CST
+ && TREE_CODE (val) != REAL_CST
+ && TREE_CODE (val) != FIXED_CST)
+ return NULL_TREE;
+
+ return build_vector_from_ctor (TREE_TYPE (rhs),
+ CONSTRUCTOR_ELTS (rhs));
+ }
+
/* If we couldn't fold the RHS, hand over to the generic
fold routines. */
if (result == NULL_TREE)
return false;
}
-/* Fold the statement pointed to by GSI. In some cases, this function may
- replace the whole statement with a new one. Returns true iff folding
- makes any changes.
- The statement pointed to by 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. */
+/* Worker for both fold_stmt and fold_stmt_inplace. The INPLACE argument
+ distinguishes both cases. */
-bool
-fold_stmt (gimple_stmt_iterator *gsi)
+static bool
+fold_stmt_1 (gimple_stmt_iterator *gsi, bool inplace)
{
bool changed = false;
gimple stmt = gsi_stmt (*gsi);
+ unsigned i;
/* Fold the main computation performed by the statement. */
switch (gimple_code (stmt))
{
case GIMPLE_ASSIGN:
{
+ unsigned old_num_ops = gimple_num_ops (stmt);
tree new_rhs = fold_gimple_assign (gsi);
- if (new_rhs != NULL_TREE)
+ if (new_rhs != NULL_TREE
+ && (!inplace
+ || get_gimple_rhs_num_ops (TREE_CODE (new_rhs)) < old_num_ops))
{
gimple_assign_set_rhs_from_tree (gsi, new_rhs);
changed = true;
}
break;
}
+
case GIMPLE_COND:
changed |= fold_gimple_cond (stmt);
break;
+
case GIMPLE_CALL:
+ /* Fold *& in call arguments. */
+ for (i = 0; i < gimple_call_num_args (stmt); ++i)
+ if (REFERENCE_CLASS_P (gimple_call_arg (stmt, i)))
+ {
+ tree tmp = maybe_fold_reference (gimple_call_arg (stmt, i), false);
+ if (tmp)
+ {
+ gimple_call_set_arg (stmt, i, tmp);
+ changed = true;
+ }
+ }
/* The entire statement may be replaced in this case. */
- changed |= fold_gimple_call (gsi);
+ if (!inplace)
+ changed |= fold_gimple_call (gsi);
break;
- default:
- return changed;
+ case GIMPLE_ASM:
+ /* Fold *& in asm operands. */
+ for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+ {
+ tree link = gimple_asm_output_op (stmt, i);
+ tree op = TREE_VALUE (link);
+ if (REFERENCE_CLASS_P (op)
+ && (op = maybe_fold_reference (op, true)) != NULL_TREE)
+ {
+ TREE_VALUE (link) = op;
+ changed = true;
+ }
+ }
+ for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+ {
+ tree link = gimple_asm_input_op (stmt, i);
+ tree op = TREE_VALUE (link);
+ if (REFERENCE_CLASS_P (op)
+ && (op = maybe_fold_reference (op, false)) != NULL_TREE)
+ {
+ TREE_VALUE (link) = op;
+ changed = true;
+ }
+ }
break;
+
+ default:;
}
stmt = gsi_stmt (*gsi);
return changed;
}
+/* Fold the statement pointed to by GSI. In some cases, this function may
+ replace the whole statement with a new one. Returns true iff folding
+ makes any changes.
+ The statement pointed to by 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 (gimple_stmt_iterator *gsi)
+{
+ return fold_stmt_1 (gsi, false);
+}
+
/* Perform the minimal folding on statement STMT. 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
bool
fold_stmt_inplace (gimple stmt)
{
- gimple_stmt_iterator si;
- bool changed = false;
-
- /* Fold the main computation performed by the statement. */
- switch (gimple_code (stmt))
- {
- case GIMPLE_ASSIGN:
- {
- unsigned old_num_ops;
- tree new_rhs;
- old_num_ops = gimple_num_ops (stmt);
- si = gsi_for_stmt (stmt);
- new_rhs = fold_gimple_assign (&si);
- if (new_rhs != NULL_TREE
- && get_gimple_rhs_num_ops (TREE_CODE (new_rhs)) < old_num_ops)
- {
- gimple_assign_set_rhs_from_tree (&si, new_rhs);
- changed = true;
- }
- gcc_assert (gsi_stmt (si) == stmt);
- break;
- }
- case GIMPLE_COND:
- changed |= fold_gimple_cond (stmt);
- break;
-
- default:
- break;
- }
-
- /* Fold *& on the lhs. */
- if (gimple_has_lhs (stmt))
- {
- tree lhs = gimple_get_lhs (stmt);
- if (lhs && REFERENCE_CLASS_P (lhs))
- {
- tree new_lhs = maybe_fold_reference (lhs, true);
- if (new_lhs)
- {
- gimple_set_lhs (stmt, new_lhs);
- changed = true;
- }
- }
- }
-
+ gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
+ bool changed = fold_stmt_1 (&gsi, true);
+ gcc_assert (gsi_stmt (gsi) == stmt);
return changed;
}
return NULL_TREE;
stack_save_gsi = gsi_for_stmt (stack_save);
- push_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));
rhs = build_int_cst (TREE_TYPE (gimple_call_arg (call, 0)), 0);
if (!update_call_from_tree (&stack_save_gsi, rhs))
- {
- discard_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));
- return NULL_TREE;
- }
- pop_stmt_changes (gsi_stmt_ptr (&stack_save_gsi));
+ return NULL_TREE;
/* No effect, so the statement will be deleted. */
return integer_zero_node;
}
old_stmt = stmt;
- push_stmt_changes (gsi_stmt_ptr (&i));
-
if (!update_call_from_tree (&i, result))
{
gimplify_and_update_call_from_tree (&i, result);
}
stmt = gsi_stmt (i);
- pop_stmt_changes (gsi_stmt_ptr (&i));
+ update_stmt (stmt);
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt)
&& gimple_purge_dead_eh_edges (bb))