/* Carry all the CALL_EXPR flags to the new GIMPLE_CALL. */
gimple_call_set_chain (call, CALL_EXPR_STATIC_CHAIN (t));
gimple_call_set_tail (call, CALL_EXPR_TAILCALL (t));
- gimple_call_set_cannot_inline (call, CALL_CANNOT_INLINE_P (t));
gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t));
if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
return p;
}
+/* Build a GIMPLE_EH_ELSE statement. */
+
+gimple
+gimple_build_eh_else (gimple_seq n_body, gimple_seq e_body)
+{
+ gimple p = gimple_alloc (GIMPLE_EH_ELSE, 0);
+ gimple_eh_else_set_n_body (p, n_body);
+ gimple_eh_else_set_e_body (p, e_body);
+ return p;
+}
+
/* Build a GIMPLE_TRY statement.
EVAL is the expression to evaluate.
return p;
}
+/* Build a GIMPLE_TRANSACTION statement. */
+
+gimple
+gimple_build_transaction (gimple_seq body, tree label)
+{
+ gimple p = gimple_alloc (GIMPLE_TRANSACTION, 0);
+ gimple_transaction_set_body (p, body);
+ gimple_transaction_set_label (p, label);
+ return p;
+}
+
/* Build a GIMPLE_PREDICT statement. PREDICT is one of the predictors from
predict.def, OUTCOME is NOT_TAKEN or TAKEN. */
/* Walk all the statements in the sequence SEQ calling walk_gimple_stmt
on each one. WI is as in walk_gimple_stmt.
- If walk_gimple_stmt returns non-NULL, the walk is stopped, the
- value is stored in WI->CALLBACK_RESULT and the statement that
- produced the value is returned.
+ If walk_gimple_stmt returns non-NULL, the walk is stopped, and the
+ value is stored in WI->CALLBACK_RESULT. Also, the statement that
+ produced the value is returned if this statement has not been
+ removed by a callback (wi->removed_stmt). If the statement has
+ been removed, NULL is returned.
Otherwise, all the statements are walked and NULL returned. */
{
gimple_stmt_iterator gsi;
- for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
+ for (gsi = gsi_start (seq); !gsi_end_p (gsi); )
{
tree ret = walk_gimple_stmt (&gsi, callback_stmt, callback_op, wi);
if (ret)
to hold it. */
gcc_assert (wi);
wi->callback_result = ret;
- return gsi_stmt (gsi);
+
+ return wi->removed_stmt ? NULL : gsi_stmt (gsi);
}
+
+ if (!wi->removed_stmt)
+ gsi_next (&gsi);
}
if (wi)
tree lhs = gimple_assign_lhs (stmt);
wi->val_only
= (is_gimple_reg_type (TREE_TYPE (lhs)) && !is_gimple_reg (lhs))
- || !gimple_assign_single_p (stmt);
+ || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS;
}
for (i = 1; i < gimple_num_ops (stmt); i++)
if (wi)
{
/* If the RHS has more than 1 operand, it is not appropriate
- for the memory. */
- wi->val_only = !is_gimple_mem_rhs (gimple_assign_rhs1 (stmt))
- || !gimple_assign_single_p (stmt);
+ for the memory.
+ ??? A lhs always requires an lvalue, checking the val_only flag
+ does not make any sense, so we should be able to avoid computing
+ it here. */
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ wi->val_only = !(is_gimple_mem_rhs (rhs1)
+ || TREE_CODE (rhs1) == CONSTRUCTOR)
+ || gimple_assign_rhs_class (stmt) != GIMPLE_SINGLE_RHS;
wi->is_lhs = true;
}
return ret;
break;
+ case GIMPLE_TRANSACTION:
+ ret = walk_tree (gimple_transaction_label_ptr (stmt), callback_op,
+ wi, pset);
+ if (ret)
+ return ret;
+ break;
+
/* Tuples that do not have operands. */
case GIMPLE_NOP:
case GIMPLE_RESX:
gimple stmt = gsi_stmt (*gsi);
if (wi)
- wi->gsi = *gsi;
+ {
+ wi->gsi = *gsi;
+ wi->removed_stmt = false;
- if (wi && wi->want_locations && gimple_has_location (stmt))
- input_location = gimple_location (stmt);
+ if (wi->want_locations && gimple_has_location (stmt))
+ input_location = gimple_location (stmt);
+ }
ret = NULL;
a value to return. */
gcc_assert (tree_ret == NULL);
+ if (wi && wi->removed_stmt)
+ return NULL;
+
/* Re-read stmt in case the callback changed it. */
stmt = gsi_stmt (*gsi);
}
return wi->callback_result;
break;
+ case GIMPLE_EH_ELSE:
+ ret = walk_gimple_seq (gimple_eh_else_n_body (stmt),
+ callback_stmt, callback_op, wi);
+ if (ret)
+ return wi->callback_result;
+ ret = walk_gimple_seq (gimple_eh_else_e_body (stmt),
+ callback_stmt, callback_op, wi);
+ if (ret)
+ return wi->callback_result;
+ break;
+
case GIMPLE_TRY:
ret = walk_gimple_seq (gimple_try_eval (stmt), callback_stmt, callback_op,
wi);
case GIMPLE_OMP_TASK:
case GIMPLE_OMP_SECTIONS:
case GIMPLE_OMP_SINGLE:
- ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt, callback_op,
- wi);
+ ret = walk_gimple_seq (gimple_omp_body (stmt), callback_stmt,
+ callback_op, wi);
if (ret)
return wi->callback_result;
break;
return wi->callback_result;
break;
+ case GIMPLE_TRANSACTION:
+ ret = walk_gimple_seq (gimple_transaction_body (stmt),
+ callback_stmt, callback_op, wi);
+ if (ret)
+ return wi->callback_result;
+ break;
+
default:
gcc_assert (!gimple_has_substatements (stmt));
break;
gimple_eh_filter_set_types (copy, t);
break;
+ case GIMPLE_EH_ELSE:
+ new_seq = gimple_seq_copy (gimple_eh_else_n_body (stmt));
+ gimple_eh_else_set_n_body (copy, new_seq);
+ new_seq = gimple_seq_copy (gimple_eh_else_e_body (stmt));
+ gimple_eh_else_set_e_body (copy, new_seq);
+ break;
+
case GIMPLE_TRY:
new_seq = gimple_seq_copy (gimple_try_eval (stmt));
gimple_try_set_eval (copy, new_seq);
gimple_omp_set_body (copy, new_seq);
break;
+ case GIMPLE_TRANSACTION:
+ new_seq = gimple_seq_copy (gimple_transaction_body (stmt));
+ gimple_transaction_set_body (copy, new_seq);
+ break;
+
case GIMPLE_WITH_CLEANUP_EXPR:
new_seq = gimple_seq_copy (gimple_wce_cleanup (stmt));
gimple_wce_set_cleanup (copy, new_seq);
bool
gimple_has_side_effects (const_gimple s)
{
- unsigned i;
-
if (is_gimple_debug (s))
return false;
if (is_gimple_call (s))
{
- unsigned nargs = gimple_call_num_args (s);
- tree fn;
+ int flags = gimple_call_flags (s);
- if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE)))
- return true;
- else if (gimple_call_flags (s) & ECF_LOOPING_CONST_OR_PURE)
- /* An infinite loop is considered a side effect. */
+ /* An infinite loop is considered a side effect. */
+ if (!(flags & (ECF_CONST | ECF_PURE))
+ || (flags & ECF_LOOPING_CONST_OR_PURE))
return true;
- if (gimple_call_lhs (s)
- && TREE_SIDE_EFFECTS (gimple_call_lhs (s)))
- {
- gcc_checking_assert (gimple_has_volatile_ops (s));
- return true;
- }
-
- fn = gimple_call_fn (s);
- if (fn && TREE_SIDE_EFFECTS (fn))
- return true;
-
- for (i = 0; i < nargs; i++)
- if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i)))
- {
- gcc_checking_assert (gimple_has_volatile_ops (s));
- return true;
- }
-
- return false;
- }
- else
- {
- for (i = 0; i < gimple_num_ops (s); i++)
- {
- tree op = gimple_op (s, i);
- if (op && TREE_SIDE_EFFECTS (op))
- {
- gcc_checking_assert (gimple_has_volatile_ops (s));
- return true;
- }
- }
- }
-
- return false;
-}
-
-/* Return true if the RHS of statement S has side effects.
- We may use it to determine if it is admissable to replace
- an assignment or call with a copy of a previously-computed
- value. In such cases, side-effects due to the LHS are
- preserved. */
-
-bool
-gimple_rhs_has_side_effects (const_gimple s)
-{
- unsigned i;
-
- if (is_gimple_call (s))
- {
- unsigned nargs = gimple_call_num_args (s);
- tree fn;
-
- if (!(gimple_call_flags (s) & (ECF_CONST | ECF_PURE)))
- return true;
-
- /* We cannot use gimple_has_volatile_ops here,
- because we must ignore a volatile LHS. */
- fn = gimple_call_fn (s);
- if (fn && (TREE_SIDE_EFFECTS (fn) || TREE_THIS_VOLATILE (fn)))
- {
- gcc_assert (gimple_has_volatile_ops (s));
- return true;
- }
-
- for (i = 0; i < nargs; i++)
- if (TREE_SIDE_EFFECTS (gimple_call_arg (s, i))
- || TREE_THIS_VOLATILE (gimple_call_arg (s, i)))
- return true;
-
return false;
}
- else if (is_gimple_assign (s))
- {
- /* Skip the first operand, the LHS. */
- for (i = 1; i < gimple_num_ops (s); i++)
- if (TREE_SIDE_EFFECTS (gimple_op (s, i))
- || TREE_THIS_VOLATILE (gimple_op (s, i)))
- {
- gcc_assert (gimple_has_volatile_ops (s));
- return true;
- }
- }
- else if (is_gimple_debug (s))
- return false;
- else
- {
- /* For statements without an LHS, examine all arguments. */
- for (i = 0; i < gimple_num_ops (s); i++)
- if (TREE_SIDE_EFFECTS (gimple_op (s, i))
- || TREE_THIS_VOLATILE (gimple_op (s, i)))
- {
- gcc_assert (gimple_has_volatile_ops (s));
- return true;
- }
- }
return false;
}
}
}
-/* Strip out all handled components that produce invariant
- offsets. */
-
-static const_tree
-strip_invariant_refs (const_tree op)
-{
- while (handled_component_p (op))
- {
- switch (TREE_CODE (op))
- {
- case ARRAY_REF:
- case ARRAY_RANGE_REF:
- if (!is_gimple_constant (TREE_OPERAND (op, 1))
- || TREE_OPERAND (op, 2) != NULL_TREE
- || TREE_OPERAND (op, 3) != NULL_TREE)
- return NULL;
- break;
-
- case COMPONENT_REF:
- if (TREE_OPERAND (op, 2) != NULL_TREE)
- return NULL;
- break;
-
- default:;
- }
- op = TREE_OPERAND (op, 0);
- }
-
- return op;
-}
-
/* Return true if T is a gimple invariant address. */
bool
return false;
op = strip_invariant_refs (TREE_OPERAND (t, 0));
+ if (!op)
+ return false;
- return op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
+ if (TREE_CODE (op) == MEM_REF)
+ {
+ const_tree op0 = TREE_OPERAND (op, 0);
+ return (TREE_CODE (op0) == ADDR_EXPR
+ && (CONSTANT_CLASS_P (TREE_OPERAND (op0, 0))
+ || decl_address_ip_invariant_p (TREE_OPERAND (op0, 0))));
+ }
+
+ return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
}
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
|| TREE_CODE (t) == STRING_CST);
}
-/* Return true if TYPE is a suitable type for a scalar register variable. */
-
-bool
-is_gimple_reg_type (tree type)
-{
- return !AGGREGATE_TYPE_P (type);
-}
-
/* Return true if T is a non-aggregate register variable. */
bool
}
-/* Return true if T is a GIMPLE variable whose address is not needed. */
-
-bool
-is_gimple_non_addressable (tree t)
-{
- if (TREE_CODE (t) == SSA_NAME)
- t = SSA_NAME_VAR (t);
-
- return (is_gimple_variable (t) && ! needs_to_live_in_memory (t));
-}
-
/* Return true if T is a GIMPLE rvalue, i.e. an identifier or a constant. */
bool
|| decl_address_invariant_p (TREE_OPERAND (t, 0)))));
}
-/* If T makes a function call, return the corresponding CALL_EXPR operand.
- Otherwise, return NULL_TREE. */
-
-tree
-get_call_expr_in (tree t)
-{
- if (TREE_CODE (t) == MODIFY_EXPR)
- t = TREE_OPERAND (t, 1);
- if (TREE_CODE (t) == WITH_SIZE_EXPR)
- t = TREE_OPERAND (t, 0);
- if (TREE_CODE (t) == CALL_EXPR)
- return t;
- return NULL_TREE;
-}
-
/* Given a memory reference expression T, return its base address.
The base address of a memory reference expression is the main
tree name1 = TYPE_NAME (t1);
tree name2 = TYPE_NAME (t2);
- if (name1 && TREE_CODE (name1) == TYPE_DECL)
+ if ((name1 != NULL_TREE) != (name2 != NULL_TREE))
+ return false;
+
+ if (name1 == NULL_TREE)
+ return true;
+
+ /* Either both should be a TYPE_DECL or both an IDENTIFIER_NODE. */
+ if (TREE_CODE (name1) != TREE_CODE (name2))
+ return false;
+
+ if (TREE_CODE (name1) == TYPE_DECL)
name1 = DECL_NAME (name1);
gcc_checking_assert (!name1 || TREE_CODE (name1) == IDENTIFIER_NODE);
- if (name2 && TREE_CODE (name2) == TYPE_DECL)
+ if (TREE_CODE (name2) == TYPE_DECL)
name2 = DECL_NAME (name2);
gcc_checking_assert (!name2 || TREE_CODE (name2) == IDENTIFIER_NODE);
if (!compare_type_names_p (t1, t2))
goto different_types;
+ /* We may not merge typedef types to the same type in different
+ contexts. */
+ if (TYPE_NAME (t1)
+ && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL
+ && DECL_CONTEXT (TYPE_NAME (t1))
+ && TYPE_P (DECL_CONTEXT (TYPE_NAME (t1))))
+ {
+ if (!gtc_visit (DECL_CONTEXT (TYPE_NAME (t1)),
+ DECL_CONTEXT (TYPE_NAME (t2)),
+ state, sccstack, sccstate, sccstate_obstack))
+ goto different_types;
+ }
+
/* If their attributes are not the same they can't be the same type. */
if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2)))
goto different_types;
{
if (!name)
return v;
+ v = iterative_hash_hashval_t (TREE_CODE (name), v);
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
if (!name)
only existing types having the same features as the new type will be
checked. */
v = iterative_hash_name (TYPE_NAME (type), 0);
+ if (TYPE_NAME (type)
+ && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_CONTEXT (TYPE_NAME (type))
+ && TYPE_P (DECL_CONTEXT (TYPE_NAME (type))))
+ v = visit (DECL_CONTEXT (TYPE_NAME (type)), state, v,
+ sccstack, sccstate, sccstate_obstack);
v = iterative_hash_hashval_t (TREE_CODE (type), v);
v = iterative_hash_hashval_t (TYPE_QUALS (type), v);
v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v);
v = iterative_hash_hashval_t (na, v);
}
- if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE
- || TREE_CODE (type) == QUAL_UNION_TYPE)
+ if (RECORD_OR_UNION_TYPE_P (type))
{
unsigned nf;
tree f;
v = iterative_hash_hashval_t (na, v);
}
- if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE
- || TREE_CODE (type) == QUAL_UNION_TYPE)
+ if (RECORD_OR_UNION_TYPE_P (type))
{
unsigned nf;
tree f;
/* For aggregate types, all the fields must be the same. */
for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2);
- f1 && f2;
+ f1 || f2;
f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2))
{
/* Skip non-fields. */
|| gimple_code (stmt) == GIMPLE_COND))
{
for (i = 0; i < gimple_num_ops (stmt); ++i)
- if (gimple_op (stmt, i)
- && TREE_CODE (gimple_op (stmt, i)) == ADDR_EXPR)
- ret |= visit_addr (stmt, TREE_OPERAND (gimple_op (stmt, i), 0), data);
+ {
+ tree op = gimple_op (stmt, i);
+ if (op == NULL_TREE)
+ ;
+ else if (TREE_CODE (op) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data);
+ /* COND_EXPR and VCOND_EXPR rhs1 argument is a comparison
+ tree with two operands. */
+ else if (i == 1 && COMPARISON_CLASS_P (op))
+ {
+ if (TREE_CODE (TREE_OPERAND (op, 0)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (TREE_OPERAND (op, 0),
+ 0), data);
+ if (TREE_CODE (TREE_OPERAND (op, 1)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (TREE_OPERAND (op, 1),
+ 0), data);
+ }
+ }
}
else if (is_gimple_call (stmt))
{