/* Gimple IR support functions.
- Copyright 2007, 2008 Free Software Foundation, Inc.
+ Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Aldy Hernandez <aldyh@redhat.com>
This file is part of GCC.
#include "tm.h"
#include "tree.h"
#include "ggc.h"
-#include "errors.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "gimple.h"
+#include "toplev.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "value-prof.h"
operands vector the size of the structure minus the size of the 1
element tree array at the end (see gimple_ops). */
#define DEFGSCODE(SYM, NAME, STRUCT) (sizeof (STRUCT) - sizeof (tree)),
-const size_t gimple_ops_offset_[] = {
+EXPORTED_CONST size_t gimple_ops_offset_[] = {
#include "gimple.def"
};
#undef DEFGSCODE
case GIMPLE_COND:
case GIMPLE_GOTO:
case GIMPLE_LABEL:
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
case GIMPLE_SWITCH: return GSS_WITH_OPS;
case GIMPLE_ASM: return GSS_ASM;
case GIMPLE_BIND: return GSS_BIND;
return sizeof (struct gimple_statement_omp_atomic_store);
case GIMPLE_WITH_CLEANUP_EXPR:
return sizeof (struct gimple_statement_wce);
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
- return sizeof (struct gimple_statement_with_ops);
case GIMPLE_PREDICT:
return sizeof (struct gimple_statement_base);
default:
gimple
gimple_build_return (tree retval)
{
- gimple s = gimple_build_with_ops (GIMPLE_RETURN, 0, 1);
+ gimple s = gimple_build_with_ops (GIMPLE_RETURN, ERROR_MARK, 1);
if (retval)
gimple_return_set_retval (s, retval);
return s;
static inline gimple
gimple_build_call_1 (tree fn, unsigned nargs)
{
- gimple s = gimple_build_with_ops (GIMPLE_CALL, 0, nargs + 3);
+ gimple s = gimple_build_with_ops (GIMPLE_CALL, ERROR_MARK, nargs + 3);
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ fn = build_fold_addr_expr (fn);
gimple_set_op (s, 1, fn);
return s;
}
gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t));
gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t));
gimple_call_set_va_arg_pack (call, CALL_EXPR_VA_ARG_PACK (t));
+ gimple_set_no_warning (call, TREE_NO_WARNING (t));
return call;
}
This function returns the newly created GIMPLE_ASSIGN tuple. */
-inline gimple
+gimple
gimplify_assign (tree dst, tree src, gimple_seq *seq_p)
{
tree t = build2 (MODIFY_EXPR, TREE_TYPE (dst), dst, src);
gimple_cond_get_ops_from_tree (tree cond, enum tree_code *code_p,
tree *lhs_p, tree *rhs_p)
{
+ location_t loc = EXPR_LOCATION (cond);
gcc_assert (TREE_CODE_CLASS (TREE_CODE (cond)) == tcc_comparison
|| TREE_CODE (cond) == TRUTH_NOT_EXPR
|| is_gimple_min_invariant (cond)
{
*code_p = EQ_EXPR;
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
- *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+ *rhs_p = fold_convert_loc (loc, TREE_TYPE (*lhs_p), integer_zero_node);
}
/* Canonicalize conditionals of the form 'if (VAL)' */
else if (TREE_CODE_CLASS (*code_p) != tcc_comparison)
{
*code_p = NE_EXPR;
gcc_assert (*lhs_p && *rhs_p == NULL_TREE);
- *rhs_p = fold_convert (TREE_TYPE (*lhs_p), integer_zero_node);
+ *rhs_p = fold_convert_loc (loc, TREE_TYPE (*lhs_p), integer_zero_node);
}
}
gimple
gimple_build_label (tree label)
{
- gimple p = gimple_build_with_ops (GIMPLE_LABEL, 0, 1);
+ gimple p = gimple_build_with_ops (GIMPLE_LABEL, ERROR_MARK, 1);
gimple_label_set_label (p, label);
return p;
}
gimple
gimple_build_goto (tree dest)
{
- gimple p = gimple_build_with_ops (GIMPLE_GOTO, 0, 1);
+ gimple p = gimple_build_with_ops (GIMPLE_GOTO, ERROR_MARK, 1);
gimple_goto_set_dest (p, dest);
return p;
}
gimple p;
int size = strlen (string);
- p = gimple_build_with_ops (GIMPLE_ASM, 0, ninputs + noutputs + nclobbers);
+ p = gimple_build_with_ops (GIMPLE_ASM, ERROR_MARK,
+ ninputs + noutputs + nclobbers);
p->gimple_asm.ni = ninputs;
p->gimple_asm.no = noutputs;
gimple_build_switch_1 (unsigned nlabels, tree index, tree default_label)
{
/* nlabels + 1 default label + 1 index. */
- gimple p = gimple_build_with_ops (GIMPLE_SWITCH, 0, nlabels + 1 + 1);
+ gimple p = gimple_build_with_ops (GIMPLE_SWITCH, ERROR_MARK,
+ nlabels + 1 + 1);
gimple_switch_set_index (p, index);
gimple_switch_set_default_label (p, default_label);
return p;
}
-/* Build a GIMPLE_CHANGE_DYNAMIC_TYPE statement. TYPE is the new type
- for the location PTR. */
-
-gimple
-gimple_build_cdt (tree type, tree ptr)
-{
- gimple p = gimple_build_with_ops (GIMPLE_CHANGE_DYNAMIC_TYPE, 0, 2);
- gimple_cdt_set_new_type (p, type);
- gimple_cdt_set_location (p, ptr);
-
- return p;
-}
-
-
/* Build a GIMPLE_OMP_ATOMIC_LOAD statement. */
gimple
{
gimple p = gimple_alloc (GIMPLE_PREDICT, 0);
/* Ensure all the predictors fit into the lower bits of the subcode. */
- gcc_assert (END_PREDICTORS <= GF_PREDICT_TAKEN);
+ gcc_assert ((int) END_PREDICTORS <= GF_PREDICT_TAKEN);
gimple_predict_set_predictor (p, predictor);
gimple_predict_set_outcome (p, outcome);
return p;
return gss_for_code (gimple_code (gs));
}
-#if defined ENABLE_GIMPLE_CHECKING && (GCC_VERSION >= 2007)
+#if defined ENABLE_GIMPLE_CHECKING
/* Complain of a gimple type mismatch and die. */
void
: "",
function, trim_filename (file), line);
}
-
-
-/* Similar to gimple_check_failed, except that instead of specifying a
- dozen codes, use the knowledge that they're all sequential. */
-
-void
-gimple_range_check_failed (const_gimple gs, const char *file, int line,
- const char *function, enum gimple_code c1,
- enum gimple_code c2)
-{
- char *buffer;
- unsigned length = 0;
- enum gimple_code c;
-
- for (c = c1; c <= c2; ++c)
- length += 4 + strlen (gimple_code_name[c]);
-
- length += strlen ("expected ");
- buffer = XALLOCAVAR (char, length);
- length = 0;
-
- for (c = c1; c <= c2; ++c)
- {
- const char *prefix = length ? " or " : "expected ";
-
- strcpy (buffer + length, prefix);
- length += strlen (prefix);
- strcpy (buffer + length, gimple_code_name[c]);
- length += strlen (gimple_code_name[c]);
- }
-
- internal_error ("gimple check: %s, have %s in %s, at %s:%d",
- buffer, gimple_code_name[gimple_code (gs)],
- function, trim_filename (file), line);
-}
#endif /* ENABLE_GIMPLE_CHECKING */
/* Walk the RHS operands. A formal temporary LHS may use a
COMPONENT_REF RHS. */
if (wi)
- wi->val_only = !is_gimple_formal_tmp_var (gimple_assign_lhs (stmt));
+ wi->val_only = !is_gimple_reg (gimple_assign_lhs (stmt))
+ || !gimple_assign_single_p (stmt);
for (i = 1; i < gimple_num_ops (stmt); i++)
{
return ret;
break;
- case GIMPLE_CHANGE_DYNAMIC_TYPE:
- ret = walk_tree (gimple_cdt_location_ptr (stmt), callback_op, wi, pset);
- if (ret)
- return ret;
-
- ret = walk_tree (gimple_cdt_new_type_ptr (stmt), callback_op, wi, pset);
- if (ret)
- return ret;
- break;
-
case GIMPLE_ASM:
ret = walk_gimple_asm (stmt, callback_op, wi);
if (ret)
return fn ? fn->gimple_body : NULL;
}
+/* Return true when FNDECL has Gimple body either in unlowered
+ or CFG form. */
+bool
+gimple_has_body_p (tree fndecl)
+{
+ struct function *fn = DECL_STRUCT_FUNCTION (fndecl);
+ return (gimple_body (fndecl) || (fn && fn->cfg));
+}
/* Detect flags from a GIMPLE_CALL. This is just like
call_expr_flags, but for gimple tuples. */
gimple_assign_unary_nop_p (gimple gs)
{
return (gimple_code (gs) == GIMPLE_ASSIGN
- && (gimple_assign_rhs_code (gs) == NOP_EXPR
- || gimple_assign_rhs_code (gs) == CONVERT_EXPR
+ && (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (gs))
|| gimple_assign_rhs_code (gs) == NON_LVALUE_EXPR)
&& gimple_assign_rhs1 (gs) != error_mark_node
&& (TYPE_MODE (TREE_TYPE (gimple_assign_lhs (gs)))
LABEL_DECL_UID (t) = uid = cfun->cfg->last_label_uid++;
if (old_len <= (unsigned) uid)
{
- unsigned new_len = 3 * uid / 2;
+ unsigned new_len = 3 * uid / 2 + 1;
VEC_safe_grow_cleared (basic_block, gc, label_to_block_map,
new_len);
tree
gimple_fold (const_gimple stmt)
{
+ location_t loc = gimple_location (stmt);
switch (gimple_code (stmt))
{
case GIMPLE_COND:
- return fold_binary (gimple_cond_code (stmt),
+ return fold_binary_loc (loc, gimple_cond_code (stmt),
boolean_type_node,
gimple_cond_lhs (stmt),
gimple_cond_rhs (stmt));
switch (get_gimple_rhs_class (gimple_assign_rhs_code (stmt)))
{
case GIMPLE_UNARY_RHS:
- return fold_unary (gimple_assign_rhs_code (stmt),
+ return fold_unary_loc (loc, gimple_assign_rhs_code (stmt),
TREE_TYPE (gimple_assign_lhs (stmt)),
gimple_assign_rhs1 (stmt));
case GIMPLE_BINARY_RHS:
- return fold_binary (gimple_assign_rhs_code (stmt),
+ return fold_binary_loc (loc, gimple_assign_rhs_code (stmt),
TREE_TYPE (gimple_assign_lhs (stmt)),
gimple_assign_rhs1 (stmt),
gimple_assign_rhs2 (stmt));
tree
gimple_get_lhs (const_gimple stmt)
{
- enum tree_code code = gimple_code (stmt);
+ enum gimple_code code = gimple_code (stmt);
if (code == GIMPLE_ASSIGN)
return gimple_assign_lhs (stmt);
void
gimple_set_lhs (gimple stmt, tree lhs)
{
- enum tree_code code = gimple_code (stmt);
+ enum gimple_code code = gimple_code (stmt);
if (code == GIMPLE_ASSIGN)
gimple_assign_set_lhs (stmt, lhs);
for (i = 0; i < num_ops; i++)
gimple_set_op (copy, i, unshare_expr (gimple_op (stmt, i)));
- /* Clear out SSA operand vectors on COPY. Note that we cannot
- call the API functions for setting addresses_taken, stores
- and loads. These functions free the previous values, and we
- cannot do that on COPY as it will affect the original
- statement. */
+ /* Clear out SSA operand vectors on COPY. */
if (gimple_has_ops (stmt))
{
gimple_set_def_ops (copy, NULL);
gimple_set_use_ops (copy, NULL);
- copy->gsops.opbase.addresses_taken = NULL;
}
if (gimple_has_mem_ops (stmt))
{
- gimple_set_vdef_ops (copy, NULL);
- gimple_set_vuse_ops (copy, NULL);
- copy->gsmem.membase.stores = NULL;
- copy->gsmem.membase.loads = NULL;
+ gimple_set_vdef (copy, gimple_vdef (stmt));
+ gimple_set_vuse (copy, gimple_vuse (stmt));
}
- update_stmt (copy);
+ /* SSA operands need to be updated. */
+ gimple_set_modified (copy, true);
}
return copy;
}
-/* Deep copy SYMS into the set of symbols stored by STMT. If SYMS is
- NULL or empty, the storage used is freed up. */
-
-void
-gimple_set_stored_syms (gimple stmt, bitmap syms, bitmap_obstack *obs)
-{
- gcc_assert (gimple_has_mem_ops (stmt));
-
- if (syms == NULL || bitmap_empty_p (syms))
- BITMAP_FREE (stmt->gsmem.membase.stores);
- else
- {
- if (stmt->gsmem.membase.stores == NULL)
- stmt->gsmem.membase.stores = BITMAP_ALLOC (obs);
-
- bitmap_copy (stmt->gsmem.membase.stores, syms);
- }
-}
-
-
-/* Deep copy SYMS into the set of symbols loaded by STMT. If SYMS is
- NULL or empty, the storage used is freed up. */
-
-void
-gimple_set_loaded_syms (gimple stmt, bitmap syms, bitmap_obstack *obs)
-{
- gcc_assert (gimple_has_mem_ops (stmt));
-
- if (syms == NULL || bitmap_empty_p (syms))
- BITMAP_FREE (stmt->gsmem.membase.loads);
- else
- {
- if (stmt->gsmem.membase.loads == NULL)
- stmt->gsmem.membase.loads = BITMAP_ALLOC (obs);
-
- bitmap_copy (stmt->gsmem.membase.loads, syms);
- }
-}
-
-
/* Return the number of operands needed on the RHS of a GIMPLE
assignment for an expression with tree code CODE. */
return op && get_gimple_rhs_class (TREE_CODE (op)) == GIMPLE_SINGLE_RHS;
}
-
-/* Return true if T is a GIMPLE RHS for an assignment to a temporary. */
-
-bool
-is_gimple_formal_tmp_rhs (tree t)
-{
- if (is_gimple_lvalue (t) || is_gimple_val (t))
- return true;
-
- return get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS;
-}
-
/* Returns true iff T is a valid RHS for an assignment to a renamed
user -- or front-end generated artificial -- variable. */
bool
is_gimple_reg_rhs (tree t)
{
- /* If the RHS of the MODIFY_EXPR may throw or make a nonlocal goto
- and the LHS is a user variable, then we need to introduce a formal
- temporary. This way the optimizers can determine that the user
- variable is only modified if evaluation of the RHS does not throw.
-
- Don't force a temp of a non-renamable type; the copy could be
- arbitrarily expensive. Instead we will generate a VDEF for
- the assignment. */
-
- if (is_gimple_reg_type (TREE_TYPE (t)) && tree_could_throw_p (t))
- return false;
-
- return is_gimple_formal_tmp_rhs (t);
+ return get_gimple_rhs_class (TREE_CODE (t)) != GIMPLE_INVALID_RHS;
}
/* Returns true iff T is a valid RHS for an assignment to an un-renamed
if (is_gimple_reg_type (TREE_TYPE (t)))
return is_gimple_val (t);
else
- return is_gimple_formal_tmp_rhs (t);
+ return is_gimple_val (t) || is_gimple_lvalue (t);
}
/* Return true if T is a valid LHS for a GIMPLE assignment expression. */
}
}
-/* Return true if T is a gimple invariant address. */
+/* Strip out all handled components that produce invariant
+ offsets. */
-bool
-is_gimple_invariant_address (const_tree t)
+static const_tree
+strip_invariant_refs (const_tree op)
{
- tree op;
-
- if (TREE_CODE (t) != ADDR_EXPR)
- return false;
-
- op = TREE_OPERAND (t, 0);
while (handled_component_p (op))
{
switch (TREE_CODE (op))
if (!is_gimple_constant (TREE_OPERAND (op, 1))
|| TREE_OPERAND (op, 2) != NULL_TREE
|| TREE_OPERAND (op, 3) != NULL_TREE)
- return false;
+ return NULL;
break;
case COMPONENT_REF:
if (TREE_OPERAND (op, 2) != NULL_TREE)
- return false;
+ return NULL;
break;
default:;
op = TREE_OPERAND (op, 0);
}
- return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
+ return op;
+}
+
+/* Return true if T is a gimple invariant address. */
+
+bool
+is_gimple_invariant_address (const_tree t)
+{
+ const_tree op;
+
+ if (TREE_CODE (t) != ADDR_EXPR)
+ return false;
+
+ op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+ return op && (CONSTANT_CLASS_P (op) || decl_address_invariant_p (op));
+}
+
+/* Return true if T is a gimple invariant address at IPA level
+ (so addresses of variables on stack are not allowed). */
+
+bool
+is_gimple_ip_invariant_address (const_tree t)
+{
+ const_tree op;
+
+ if (TREE_CODE (t) != ADDR_EXPR)
+ return false;
+
+ op = strip_invariant_refs (TREE_OPERAND (t, 0));
+
+ return op && (CONSTANT_CLASS_P (op) || decl_address_ip_invariant_p (op));
}
/* Return true if T is a GIMPLE minimal invariant. It's a restricted
return is_gimple_constant (t);
}
+/* Return true if T is a GIMPLE interprocedural invariant. It's a restricted
+ form of gimple minimal invariant. */
+
+bool
+is_gimple_ip_invariant (const_tree t)
+{
+ if (TREE_CODE (t) == ADDR_EXPR)
+ return is_gimple_ip_invariant_address (t);
+
+ return is_gimple_constant (t);
+}
+
/* Return true if T looks like a valid GIMPLE statement. */
bool
case TRY_FINALLY_EXPR:
case EH_FILTER_EXPR:
case CATCH_EXPR:
- case CHANGE_DYNAMIC_TYPE_EXPR:
case ASM_EXPR:
case RESX_EXPR:
case STATEMENT_LIST:
bool
is_gimple_reg_type (tree type)
{
- /* In addition to aggregate types, we also exclude complex types if not
- optimizing because they can be subject to partial stores in GNU C by
- means of the __real__ and __imag__ operators and we cannot promote
- them to total stores (see gimplify_modify_expr_complex_part). */
- return !(AGGREGATE_TYPE_P (type)
- || (TREE_CODE (type) == COMPLEX_TYPE && !optimize));
-
+ return !AGGREGATE_TYPE_P (type);
}
/* Return true if T is a non-aggregate register variable. */
if (TREE_CODE (t) == SSA_NAME)
t = SSA_NAME_VAR (t);
- if (MTAG_P (t))
- return false;
-
if (!is_gimple_variable (t))
return false;
}
-/* Returns true if T is a GIMPLE formal temporary variable. */
-
-bool
-is_gimple_formal_tmp_var (tree t)
-{
- if (TREE_CODE (t) == SSA_NAME)
- return true;
-
- return TREE_CODE (t) == VAR_DECL && DECL_GIMPLE_FORMAL_TEMP_P (t);
-}
-
-/* Returns true if T is a GIMPLE formal temporary register variable. */
-
-bool
-is_gimple_formal_tmp_reg (tree t)
-{
- /* The intent of this is to get hold of a value that won't change.
- An SSA_NAME qualifies no matter if its of a user variable or not. */
- if (TREE_CODE (t) == SSA_NAME)
- return true;
-
- /* We don't know the lifetime characteristics of user variables. */
- if (!is_gimple_formal_tmp_var (t))
- return false;
-
- /* Finally, it must be capable of being placed in a register. */
- return is_gimple_reg (t);
-}
-
/* Return true if T is a GIMPLE variable whose address is not needed. */
bool
bool
is_gimple_min_lval (tree t)
{
+ if (!(t = CONST_CAST_TREE (strip_invariant_refs (t))))
+ return false;
return (is_gimple_id (t) || TREE_CODE (t) == INDIRECT_REF);
}
}
break;
+ case tcc_constant:
+ /* No side-effects. */
+ return;
+
default:
- /* Can never be used with non-expressions. */
gcc_unreachable ();
}
}
return NULL_TREE;
}
+/* Build a GIMPLE_CALL identical to STMT but skipping the arguments in
+ the positions marked by the set ARGS_TO_SKIP. */
+
+gimple
+gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip)
+{
+ int i;
+ tree fn = gimple_call_fn (stmt);
+ int nargs = gimple_call_num_args (stmt);
+ VEC(tree, heap) *vargs = VEC_alloc (tree, heap, nargs);
+ gimple new_stmt;
+
+ for (i = 0; i < nargs; i++)
+ if (!bitmap_bit_p (args_to_skip, i))
+ VEC_quick_push (tree, vargs, gimple_call_arg (stmt, i));
+
+ new_stmt = gimple_build_call_vec (fn, vargs);
+ VEC_free (tree, heap, vargs);
+ if (gimple_call_lhs (stmt))
+ gimple_call_set_lhs (new_stmt, gimple_call_lhs (stmt));
+
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+
+ gimple_set_block (new_stmt, gimple_block (stmt));
+ if (gimple_has_location (stmt))
+ gimple_set_location (new_stmt, gimple_location (stmt));
+
+ /* Carry all the flags to the new GIMPLE_CALL. */
+ gimple_call_set_chain (new_stmt, gimple_call_chain (stmt));
+ gimple_call_set_tail (new_stmt, gimple_call_tail_p (stmt));
+ gimple_call_set_cannot_inline (new_stmt, gimple_call_cannot_inline_p (stmt));
+ gimple_call_set_return_slot_opt (new_stmt, gimple_call_return_slot_opt_p (stmt));
+ gimple_call_set_from_thunk (new_stmt, gimple_call_from_thunk_p (stmt));
+ gimple_call_set_va_arg_pack (new_stmt, gimple_call_va_arg_pack_p (stmt));
+
+ gimple_set_modified (new_stmt, true);
+
+ return new_stmt;
+}
+
+
+/* Data structure used to count the number of dereferences to PTR
+ inside an expression. */
+struct count_ptr_d
+{
+ tree ptr;
+ unsigned num_stores;
+ unsigned num_loads;
+};
+
+/* Helper for count_uses_and_derefs. Called by walk_tree to look for
+ (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA. */
+
+static tree
+count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
+{
+ struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data;
+ struct count_ptr_d *count_p = (struct count_ptr_d *) wi_p->info;
+
+ /* Do not walk inside ADDR_EXPR nodes. In the expression &ptr->fld,
+ pointer 'ptr' is *not* dereferenced, it is simply used to compute
+ the address of 'fld' as 'ptr + offsetof(fld)'. */
+ if (TREE_CODE (*tp) == ADDR_EXPR)
+ {
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
+ if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
+ {
+ if (wi_p->is_lhs)
+ count_p->num_stores++;
+ else
+ count_p->num_loads++;
+ }
+
+ return NULL_TREE;
+}
+
+/* Count the number of direct and indirect uses for pointer PTR in
+ statement STMT. The number of direct uses is stored in
+ *NUM_USES_P. Indirect references are counted separately depending
+ on whether they are store or load operations. The counts are
+ stored in *NUM_STORES_P and *NUM_LOADS_P. */
+
+void
+count_uses_and_derefs (tree ptr, gimple stmt, unsigned *num_uses_p,
+ unsigned *num_loads_p, unsigned *num_stores_p)
+{
+ ssa_op_iter i;
+ tree use;
+
+ *num_uses_p = 0;
+ *num_loads_p = 0;
+ *num_stores_p = 0;
+
+ /* Find out the total number of uses of PTR in STMT. */
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
+ if (use == ptr)
+ (*num_uses_p)++;
+
+ /* Now count the number of indirect references to PTR. This is
+ truly awful, but we don't have much choice. There are no parent
+ pointers inside INDIRECT_REFs, so an expression like
+ '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
+ find all the indirect and direct uses of x_1 inside. The only
+ shortcut we can take is the fact that GIMPLE only allows
+ INDIRECT_REFs inside the expressions below. */
+ if (is_gimple_assign (stmt)
+ || gimple_code (stmt) == GIMPLE_RETURN
+ || gimple_code (stmt) == GIMPLE_ASM
+ || is_gimple_call (stmt))
+ {
+ struct walk_stmt_info wi;
+ struct count_ptr_d count;
+
+ count.ptr = ptr;
+ count.num_stores = 0;
+ count.num_loads = 0;
+
+ memset (&wi, 0, sizeof (wi));
+ wi.info = &count;
+ walk_gimple_op (stmt, count_ptr_derefs, &wi);
+
+ *num_stores_p = count.num_stores;
+ *num_loads_p = count.num_loads;
+ }
+
+ gcc_assert (*num_uses_p >= *num_loads_p + *num_stores_p);
+}
+
+/* From a tree operand OP return the base of a load or store operation
+ or NULL_TREE if OP is not a load or a store. */
+
+static tree
+get_base_loadstore (tree op)
+{
+ while (handled_component_p (op))
+ op = TREE_OPERAND (op, 0);
+ if (DECL_P (op)
+ || INDIRECT_REF_P (op)
+ || TREE_CODE (op) == TARGET_MEM_REF)
+ return op;
+ return NULL_TREE;
+}
+
+/* For the statement STMT call the callbacks VISIT_LOAD, VISIT_STORE and
+ VISIT_ADDR if non-NULL on loads, store and address-taken operands
+ passing the STMT, the base of the operand and DATA to it. The base
+ will be either a decl, an indirect reference (including TARGET_MEM_REF)
+ or the argument of an address expression.
+ Returns the results of these callbacks or'ed. */
+
+bool
+walk_stmt_load_store_addr_ops (gimple stmt, void *data,
+ bool (*visit_load)(gimple, tree, void *),
+ bool (*visit_store)(gimple, tree, void *),
+ bool (*visit_addr)(gimple, tree, void *))
+{
+ bool ret = false;
+ unsigned i;
+ if (gimple_assign_single_p (stmt))
+ {
+ tree lhs, rhs;
+ if (visit_store)
+ {
+ lhs = get_base_loadstore (gimple_assign_lhs (stmt));
+ if (lhs)
+ ret |= visit_store (stmt, lhs, data);
+ }
+ rhs = gimple_assign_rhs1 (stmt);
+ while (handled_component_p (rhs))
+ rhs = TREE_OPERAND (rhs, 0);
+ if (visit_addr)
+ {
+ if (TREE_CODE (rhs) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data);
+ else if (TREE_CODE (rhs) == TARGET_MEM_REF
+ && TMR_BASE (rhs) != NULL_TREE
+ && TREE_CODE (TMR_BASE (rhs)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (rhs), 0), data);
+ else if (TREE_CODE (rhs) == OBJ_TYPE_REF
+ && TREE_CODE (OBJ_TYPE_REF_OBJECT (rhs)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (OBJ_TYPE_REF_OBJECT (rhs),
+ 0), data);
+ lhs = gimple_assign_lhs (stmt);
+ if (TREE_CODE (lhs) == TARGET_MEM_REF
+ && TMR_BASE (lhs) != NULL_TREE
+ && TREE_CODE (TMR_BASE (lhs)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (TMR_BASE (lhs), 0), data);
+ }
+ if (visit_load)
+ {
+ rhs = get_base_loadstore (rhs);
+ if (rhs)
+ ret |= visit_load (stmt, rhs, data);
+ }
+ }
+ else if (visit_addr
+ && (is_gimple_assign (stmt)
+ || 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);
+ }
+ else if (is_gimple_call (stmt))
+ {
+ if (visit_store)
+ {
+ tree lhs = gimple_call_lhs (stmt);
+ if (lhs)
+ {
+ lhs = get_base_loadstore (lhs);
+ if (lhs)
+ ret |= visit_store (stmt, lhs, data);
+ }
+ }
+ if (visit_load || visit_addr)
+ for (i = 0; i < gimple_call_num_args (stmt); ++i)
+ {
+ tree rhs = gimple_call_arg (stmt, i);
+ if (visit_addr
+ && TREE_CODE (rhs) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (rhs, 0), data);
+ else if (visit_load)
+ {
+ rhs = get_base_loadstore (rhs);
+ if (rhs)
+ ret |= visit_load (stmt, rhs, data);
+ }
+ }
+ if (visit_addr
+ && gimple_call_chain (stmt)
+ && TREE_CODE (gimple_call_chain (stmt)) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (gimple_call_chain (stmt), 0),
+ data);
+ if (visit_addr
+ && gimple_call_return_slot_opt_p (stmt)
+ && gimple_call_lhs (stmt) != NULL_TREE
+ && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
+ ret |= visit_addr (stmt, gimple_call_lhs (stmt), data);
+ }
+ else if (gimple_code (stmt) == GIMPLE_ASM)
+ {
+ unsigned noutputs;
+ const char *constraint;
+ const char **oconstraints;
+ bool allows_mem, allows_reg, is_inout;
+ noutputs = gimple_asm_noutputs (stmt);
+ oconstraints = XALLOCAVEC (const char *, noutputs);
+ if (visit_store || visit_addr)
+ for (i = 0; i < gimple_asm_noutputs (stmt); ++i)
+ {
+ tree link = gimple_asm_output_op (stmt, i);
+ tree op = get_base_loadstore (TREE_VALUE (link));
+ if (op && visit_store)
+ ret |= visit_store (stmt, op, data);
+ if (visit_addr)
+ {
+ constraint = TREE_STRING_POINTER
+ (TREE_VALUE (TREE_PURPOSE (link)));
+ oconstraints[i] = constraint;
+ parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+ &allows_reg, &is_inout);
+ if (op && !allows_reg && allows_mem)
+ ret |= visit_addr (stmt, op, data);
+ }
+ }
+ if (visit_load || visit_addr)
+ for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+ {
+ tree link = gimple_asm_input_op (stmt, i);
+ tree op = TREE_VALUE (link);
+ if (visit_addr
+ && TREE_CODE (op) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data);
+ else if (visit_load || visit_addr)
+ {
+ op = get_base_loadstore (op);
+ if (op)
+ {
+ if (visit_load)
+ ret |= visit_load (stmt, op, data);
+ if (visit_addr)
+ {
+ constraint = TREE_STRING_POINTER
+ (TREE_VALUE (TREE_PURPOSE (link)));
+ parse_input_constraint (&constraint, 0, 0, noutputs,
+ 0, oconstraints,
+ &allows_mem, &allows_reg);
+ if (!allows_reg && allows_mem)
+ ret |= visit_addr (stmt, op, data);
+ }
+ }
+ }
+ }
+ }
+ else if (gimple_code (stmt) == GIMPLE_RETURN)
+ {
+ tree op = gimple_return_retval (stmt);
+ if (op)
+ {
+ if (visit_addr
+ && TREE_CODE (op) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data);
+ else if (visit_load)
+ {
+ op = get_base_loadstore (op);
+ if (op)
+ ret |= visit_load (stmt, op, data);
+ }
+ }
+ }
+ else if (visit_addr
+ && gimple_code (stmt) == GIMPLE_PHI)
+ {
+ for (i = 0; i < gimple_phi_num_args (stmt); ++i)
+ {
+ tree op = PHI_ARG_DEF (stmt, i);
+ if (TREE_CODE (op) == ADDR_EXPR)
+ ret |= visit_addr (stmt, TREE_OPERAND (op, 0), data);
+ }
+ }
+
+ return ret;
+}
+
+/* Like walk_stmt_load_store_addr_ops but with NULL visit_addr. IPA-CP
+ should make a faster clone for this case. */
+
+bool
+walk_stmt_load_store_ops (gimple stmt, void *data,
+ bool (*visit_load)(gimple, tree, void *),
+ bool (*visit_store)(gimple, tree, void *))
+{
+ return walk_stmt_load_store_addr_ops (stmt, data,
+ visit_load, visit_store, NULL);
+}
+
+/* Helper for gimple_ior_addresses_taken_1. */
+
+static bool
+gimple_ior_addresses_taken_1 (gimple stmt ATTRIBUTE_UNUSED,
+ tree addr, void *data)
+{
+ bitmap addresses_taken = (bitmap)data;
+ while (handled_component_p (addr))
+ addr = TREE_OPERAND (addr, 0);
+ if (DECL_P (addr))
+ {
+ bitmap_set_bit (addresses_taken, DECL_UID (addr));
+ return true;
+ }
+ return false;
+}
+
+/* Set the bit for the uid of all decls that have their address taken
+ in STMT in the ADDRESSES_TAKEN bitmap. Returns true if there
+ were any in this stmt. */
+
+bool
+gimple_ior_addresses_taken (bitmap addresses_taken, gimple stmt)
+{
+ return walk_stmt_load_store_addr_ops (stmt, addresses_taken, NULL, NULL,
+ gimple_ior_addresses_taken_1);
+}
+
#include "gt-gimple.h"