2010-04-07 Richard Guenther <rguenther@suse.de>
+ * ipa-reference.c (mark_load): Use get_base_address.
+ (mark_store): Likewise.
+
+ * tree-ssa-ccp.c (gimplify_and_update_call_from_tree): Avoid
+ inserting GIMPLE_NOPs into the IL.
+ * tree-ssa-structalias.c (get_constraint_for_component_ref):
+ Explicitly strip handled components and indirect references.
+
+ * fold-const.c (fold_unary_loc): Do not strip qualifiers when
+ folding address expressions.
+ * gimple.c (gimple_ior_addresses_taken_1): Use get_base_address.
+ * tree-ssa-alias.c (decl_refs_may_alias_p): Do not use
+ operand_equal_p to compare decls.
+ (ptr_deref_may_alias_decl_p): Likewise.
+ * tree-ssa-operands.c (get_asm_expr_operands): Simplify
+ * tree-ssa-forwprop.c (forward_propagate_into_gimple_cond):
+ Handle reversed comparison ops.
+ * tree-sra.c (asm_visit_addr): Use get_base_address.
+ * ipa-prop.c (visit_store_addr_for_mod_analysis): Use
+ get_base_address.
+ * ipa-reference.c (mark_address): Use get_base_address.
+
+2010-04-07 Richard Guenther <rguenther@suse.de>
+
* tree-ssa-forwprop.c (forward_propagate_addr_expr):
Propagate constants everywhere.
return true;
}
+/* Mark tree T as having address taken. */
+
+static void
+mark_address_taken (tree x)
+{
+ if (TREE_CODE (x) == VAR_DECL
+ && module_statics_escape && has_proper_scope_for_analysis (x))
+ bitmap_set_bit (module_statics_escape, DECL_UID (x));
+}
+
+/* Wrapper around mark_address_taken for the stmt walker. */
+
+static bool
+mark_address (gimple stmt ATTRIBUTE_UNUSED, tree addr,
+ void *data ATTRIBUTE_UNUSED)
+{
+ addr = get_base_address (addr);
+ if (addr)
+ mark_address_taken (addr);
+ return false;
+}
+
+/* Mark load of T. */
+
+static bool
+mark_load (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
+{
+ ipa_reference_local_vars_info_t local = (ipa_reference_local_vars_info_t)data;
+ t = get_base_address (t);
+ if (t && TREE_CODE (t) == VAR_DECL
+ && has_proper_scope_for_analysis (t))
+ bitmap_set_bit (local->statics_read, DECL_UID (t));
+ return false;
+}
+
+/* Mark store of T. */
+
+static bool
+mark_store (gimple stmt ATTRIBUTE_UNUSED, tree t, void *data)
+{
+ ipa_reference_local_vars_info_t local = (ipa_reference_local_vars_info_t)data;
+ t = get_base_address (t);
+ if (t && TREE_CODE (t) == VAR_DECL
+ && has_proper_scope_for_analysis (t))
+ {
+ if (local)
+ bitmap_set_bit (local->statics_written, DECL_UID (t));
+ /* Mark the write so we can tell which statics are
+ readonly. */
+ if (module_statics_written)
+ bitmap_set_bit (module_statics_written, DECL_UID (t));
+ }
+ return false;
+}
+
+/* Look for memory clobber and set read_all/write_all if present. */
+
+static void
+check_asm_memory_clobber (ipa_reference_local_vars_info_t local, gimple stmt)
+{
+ size_t i;
+ tree op;
+
+ for (i = 0; i < gimple_asm_nclobbers (stmt); i++)
+ {
+ op = gimple_asm_clobber_op (stmt, i);
+ if (simple_cst_equal(TREE_VALUE (op), memory_identifier_string) == 1)
+ {
+ /* Abandon all hope, ye who enter here. */
+ local->calls_read_all = true;
+ local->calls_write_all = true;
+ }
+ }
+}
+
+/* Look for external calls and set read_all/write_all correspondingly. */
+
+static void
+check_call (ipa_reference_local_vars_info_t local, gimple stmt)
+{
+ int flags = gimple_call_flags (stmt);
+ tree callee_t = gimple_call_fndecl (stmt);
+
+ /* Process indirect calls. All direct calles are handled at propagation
+ time. */
+ if (!callee_t)
+ {
+ if (flags & ECF_CONST)
+ ;
+ else if (flags & ECF_PURE)
+ local->calls_read_all = true;
+ else
+ {
+ local->calls_read_all = true;
+ /* When function does not reutrn, it is safe to ignore anythign it writes
+ to, because the effect will never happen. */
+ if ((flags & (ECF_NOTHROW | ECF_NORETURN))
+ != (ECF_NOTHROW | ECF_NORETURN))
+ local->calls_write_all = true;
+ }
+ }
+}
+
+/* TP is the part of the tree currently under the microscope.
+ WALK_SUBTREES is part of the walk_tree api but is unused here.
+ DATA is cgraph_node of the function being walked. */
+
+static tree
+scan_stmt_for_static_refs (gimple_stmt_iterator *gsip,
+ struct cgraph_node *fn)
+{
+ gimple stmt = gsi_stmt (*gsip);
+ ipa_reference_local_vars_info_t local = NULL;
+
+ if (is_gimple_debug (stmt))
+ return NULL;
+
+ if (fn)
+ local = get_reference_vars_info (fn)->local;
+
+ /* Look for direct loads and stores. */
+ walk_stmt_load_store_addr_ops (stmt, local, mark_load, mark_store,
+ mark_address);
+
+ if (is_gimple_call (stmt))
+ check_call (local, stmt);
+ else if (gimple_code (stmt) == GIMPLE_ASM)
+ check_asm_memory_clobber (local, stmt);
+
+ return NULL;
+}
+
+/* Call-back to scan variable initializers for static references.
+ Called using walk_tree. */
+
+static tree
+scan_initializer_for_static_refs (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
+{
+ tree t = *tp;
+
+ if (TREE_CODE (t) == ADDR_EXPR)
+ {
+ mark_address_taken (get_base_var (t));
+ *walk_subtrees = 0;
+ }
+ /* Save some cycles by not walking types and declaration as we
+ won't find anything useful there anyway. */
+ else if (IS_TYPE_OR_DECL_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL;
+}
+
+/* Lookup the tree node for the static variable that has UID. */
+static tree
+get_static_decl (int index)
+{
+ splay_tree_node stn =
+ splay_tree_lookup (reference_vars_to_consider, index);
+ if (stn)
+ return (tree)stn->value;
+ return NULL;
+}
+
/* Lookup the tree node for the static variable that has UID and
convert the name to a string for debugging. */
}
}
+/* Convert EXPR into a GIMPLE value suitable for substitution on the
+ RHS of an assignment. Insert the necessary statements before
+ iterator *SI_P. The statement at *SI_P, which must be a GIMPLE_CALL
+ is replaced. If the call is expected to produces a result, then it
+ is replaced by an assignment of the new RHS to the result variable.
+ If the result is to be ignored, then the call is replaced by a
+ GIMPLE_NOP. */
+
+static void
+gimplify_and_update_call_from_tree (gimple_stmt_iterator *si_p, tree expr)
+{
+ tree lhs;
+ tree tmp = NULL_TREE; /* Silence warning. */
+ gimple stmt, new_stmt;
+ gimple_stmt_iterator i;
+ gimple_seq stmts = gimple_seq_alloc();
+ struct gimplify_ctx gctx;
+ gimple last = NULL;
+
+ stmt = gsi_stmt (*si_p);
+
+ gcc_assert (is_gimple_call (stmt));
+
+ lhs = gimple_call_lhs (stmt);
+
+ push_gimplify_context (&gctx);
+
+ if (lhs == NULL_TREE)
+ gimplify_and_add (expr, &stmts);
+ else
+ tmp = get_initialized_tmp_var (expr, &stmts, NULL);
+
+ pop_gimplify_context (NULL);
+
+ if (gimple_has_location (stmt))
+ annotate_all_with_location (stmts, gimple_location (stmt));
+
+ /* The replacement can expose previously unreferenced variables. */
+ for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
+ {
+ if (last)
+ {
+ gsi_insert_before (si_p, last, GSI_NEW_STMT);
+ gsi_next (si_p);
+ }
+ new_stmt = gsi_stmt (i);
+ find_new_referenced_vars (new_stmt);
+ mark_symbols_for_renaming (new_stmt);
+ last = new_stmt;
+ }
+
+ if (lhs == NULL_TREE)
+ {
+ unlink_stmt_vdef (stmt);
+ release_defs (stmt);
+ new_stmt = last;
+ }
+ else
+ {
+ if (last)
+ {
+ gsi_insert_before (si_p, last, GSI_NEW_STMT);
+ gsi_next (si_p);
+ }
+ new_stmt = gimple_build_assign (lhs, tmp);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ move_ssa_defining_stmt_for_defs (new_stmt, stmt);
+ }
+
+ gimple_set_location (new_stmt, gimple_location (stmt));
+ gsi_replace (si_p, new_stmt, false);
+}
+
/* A simple pass that attempts to fold all builtin functions. This pass
is run after we've propagated as many constants as we can. */