/* Gimple IR support functions.
- Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
Contributed by Aldy Hernandez <aldyh@redhat.com>
This file is part of GCC.
pt_solution_reset (gimple_call_clobber_set (s));
}
-/* Helper for gimple_build_call, gimple_build_call_vec and
- gimple_build_call_from_tree. Build the basic components of a
- GIMPLE_CALL statement to function FN with NARGS arguments. */
+/* Helper for gimple_build_call, gimple_build_call_valist,
+ gimple_build_call_vec and gimple_build_call_from_tree. Build the basic
+ components of a GIMPLE_CALL statement to function FN with NARGS
+ arguments. */
static inline gimple
gimple_build_call_1 (tree fn, unsigned nargs)
}
+/* Build a GIMPLE_CALL statement to function FN. NARGS is the number of
+ arguments. AP contains the arguments. */
+
+gimple
+gimple_build_call_valist (tree fn, unsigned nargs, va_list ap)
+{
+ gimple call;
+ unsigned i;
+
+ gcc_assert (TREE_CODE (fn) == FUNCTION_DECL || is_gimple_call_addr (fn));
+
+ call = gimple_build_call_1 (fn, nargs);
+
+ for (i = 0; i < nargs; i++)
+ gimple_call_set_arg (call, i, va_arg (ap, tree));
+
+ return call;
+}
+
+
/* Helper for gimple_build_call_internal and gimple_build_call_internal_vec.
Build the basic components of a GIMPLE_CALL statement to internal
function FN with NARGS arguments. */
/* 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
- && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA)
+ && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA
+ || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN))
gimple_call_set_alloca_for_var (call, CALL_ALLOCA_FOR_VAR_P (t));
else
gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t));
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.
}
+/* Build a new GIMPLE_DEBUG_SOURCE_BIND statement.
+
+ VAR is bound to VALUE; block and location are taken from STMT. */
+
+gimple
+gimple_build_debug_source_bind_stat (tree var, tree value,
+ gimple stmt MEM_STAT_DECL)
+{
+ gimple p = gimple_build_with_ops_stat (GIMPLE_DEBUG,
+ (unsigned)GIMPLE_DEBUG_SOURCE_BIND, 2
+ PASS_MEM_STAT);
+
+ gimple_debug_source_bind_set_var (p, var);
+ gimple_debug_source_bind_set_value (p, value);
+ if (stmt)
+ {
+ gimple_set_block (p, gimple_block (stmt));
+ gimple_set_location (p, gimple_location (stmt));
+ }
+
+ return p;
+}
+
+
/* Build a GIMPLE_OMP_CRITICAL statement.
BODY is the sequence of statements for which only one thread can execute.
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)
{
/* 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))
+ wi->val_only = !(is_gimple_mem_rhs (gimple_assign_rhs1 (stmt))
+ || TREE_CODE (gimple_assign_rhs1 (stmt))
+ == CONSTRUCTOR)
|| !gimple_assign_single_p (stmt);
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;
}
|| (SYM) == TRUTH_OR_EXPR \
|| (SYM) == TRUTH_XOR_EXPR) ? GIMPLE_BINARY_RHS \
: (SYM) == TRUTH_NOT_EXPR ? GIMPLE_UNARY_RHS \
- : ((SYM) == WIDEN_MULT_PLUS_EXPR \
+ : ((SYM) == COND_EXPR \
+ || (SYM) == WIDEN_MULT_PLUS_EXPR \
|| (SYM) == WIDEN_MULT_MINUS_EXPR \
|| (SYM) == DOT_PROD_EXPR \
|| (SYM) == REALIGN_LOAD_EXPR \
+ || (SYM) == VEC_COND_EXPR \
+ || (SYM) == VEC_PERM_EXPR \
|| (SYM) == FMA_EXPR) ? GIMPLE_TERNARY_RHS \
- : ((SYM) == COND_EXPR \
- || (SYM) == CONSTRUCTOR \
+ : ((SYM) == CONSTRUCTOR \
|| (SYM) == OBJ_TYPE_REF \
|| (SYM) == ASSERT_EXPR \
|| (SYM) == ADDR_EXPR \
|| (SYM) == WITH_SIZE_EXPR \
- || (SYM) == SSA_NAME \
- || (SYM) == VEC_COND_EXPR) ? GIMPLE_SINGLE_RHS \
+ || (SYM) == SSA_NAME) ? GIMPLE_SINGLE_RHS \
: GIMPLE_INVALID_RHS),
#define END_OF_BASE_TREE_CODES (unsigned char) GIMPLE_INVALID_RHS,
}
}
-/* 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;
+
+ 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 op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
+ return CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op);
}
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
}
-/* 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
{
/* Strip conversions around boolean operations. */
if (CONVERT_EXPR_P (t)
- && truth_value_p (TREE_CODE (TREE_OPERAND (t, 0))))
+ && (truth_value_p (TREE_CODE (TREE_OPERAND (t, 0)))
+ || TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0)))
+ == BOOLEAN_TYPE))
t = TREE_OPERAND (t, 0);
- /* For (bool)x use x != 0. */
- if (CONVERT_EXPR_P (t)
- && TREE_CODE (TREE_TYPE (t)) == BOOLEAN_TYPE)
- {
- tree top0 = TREE_OPERAND (t, 0);
- t = build2 (NE_EXPR, TREE_TYPE (t),
- top0, build_int_cst (TREE_TYPE (top0), 0));
- }
/* For !x use x == 0. */
- else if (TREE_CODE (t) == TRUTH_NOT_EXPR)
+ if (TREE_CODE (t) == TRUTH_NOT_EXPR)
{
tree top0 = TREE_OPERAND (t, 0);
t = build2 (EQ_EXPR, TREE_TYPE (t),
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);
/* 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. */
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (rhs)) == ADDR_EXPR)
ret |= visit_addr (stmt, TREE_OPERAND (OBJ_TYPE_REF_OBJECT (rhs),
0), data);
+ else if (TREE_CODE (rhs) == CONSTRUCTOR)
+ {
+ unsigned int ix;
+ tree val;
+
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (rhs), ix, val)
+ if (TREE_CODE (val) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (val, 0), data);
+ else if (TREE_CODE (val) == OBJ_TYPE_REF
+ && TREE_CODE (OBJ_TYPE_REF_OBJECT (val)) == ADDR_EXPR)
+ ret |= visit_addr (stmt,
+ TREE_OPERAND (OBJ_TYPE_REF_OBJECT (val),
+ 0), data);
+ }
lhs = gimple_assign_lhs (stmt);
if (TREE_CODE (lhs) == TARGET_MEM_REF
&& TREE_CODE (TMR_BASE (lhs)) == ADDR_EXPR)
|| 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))
{