summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-26 13:23:31 +0000
committeramacleod <amacleod@138bc75d-0d04-0410-961f-82ee72b054a4>2013-09-26 13:23:31 +0000
commit9a4a334838250399f91cb29d193efeb869ead77e (patch)
tree0bdac19cc1c197b2e326293eb4c1344554b4e7b5
parent688425e8fb82effae7a31357f9166c0cf10dbd7d (diff)
downloadgcc-9a4a334838250399f91cb29d193efeb869ead77e.tar.gz
2013-09-26 Andrew MacLeod <amacleod@redhat.com>
* gimple.c (gimple_replace_lhs): Move to tree-ssa.c and rename. (struct count_ptr_d, count_ptr_derefs, count_uses_and_derefs): Move to tree-ssa.c (create_gimple_tmp): Delete. (get_expr_type, build_assign, build_type_cast): Move to... * gimple-builder.c: New File. (get_expr_type): Relocate from gimple.c. (build_assign, build_type_cast): Change to only create ssanames. * gimple.h: Move prototypes to... * gimple-builder.h: New File. Here. * tree-ssa.h: And here. * tree-ssa.c (struct count_ptr_d, count_ptr_derefs, count_uses_and_derefs): Relocate from gimple.c. (gimple_replace_ssa_lhs): Renamed gimple_replace_ssa from gimple.c * tree-ssa-reassoc.c (repropagate_negates): Use gimple_replace_ssa_lhs. * tree-ssa-math-opts (execute_cse_reciprocals): Use gimple_replace_ssa_lhs. * asan.c: Include gimple-builder.h. * Makefile.in: Add gimple-builder.o. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@202945 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog22
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/asan.c1
-rw-r--r--gcc/gimple-builder.c118
-rw-r--r--gcc/gimple-builder.h34
-rw-r--r--gcc/gimple.c225
-rw-r--r--gcc/gimple.h15
-rw-r--r--gcc/tree-ssa-math-opts.c2
-rw-r--r--gcc/tree-ssa-reassoc.c2
-rw-r--r--gcc/tree-ssa.c129
-rw-r--r--gcc/tree-ssa.h3
11 files changed, 311 insertions, 241 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 7d5e2c5a259..eb83ea89323 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,25 @@
+2013-09-26 Andrew MacLeod <amacleod@redhat.com>
+
+ * gimple.c (gimple_replace_lhs): Move to tree-ssa.c and rename.
+ (struct count_ptr_d, count_ptr_derefs, count_uses_and_derefs): Move to
+ tree-ssa.c
+ (create_gimple_tmp): Delete.
+ (get_expr_type, build_assign, build_type_cast): Move to...
+ * gimple-builder.c: New File.
+ (get_expr_type): Relocate from gimple.c.
+ (build_assign, build_type_cast): Change to only create ssanames.
+ * gimple.h: Move prototypes to...
+ * gimple-builder.h: New File. Here.
+ * tree-ssa.h: And here.
+ * tree-ssa.c (struct count_ptr_d, count_ptr_derefs,
+ count_uses_and_derefs): Relocate from gimple.c.
+ (gimple_replace_ssa_lhs): Renamed gimple_replace_ssa from gimple.c
+ * tree-ssa-reassoc.c (repropagate_negates): Use gimple_replace_ssa_lhs.
+ * tree-ssa-math-opts (execute_cse_reciprocals): Use
+ gimple_replace_ssa_lhs.
+ * asan.c: Include gimple-builder.h.
+ * Makefile.in: Add gimple-builder.o.
+
2013-09-26 Richard Biener <rguenther@suse.de>
* tree-ssa-live.c (var_map_base_init): Handle SSA names with
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index d10e48a147a..f55f1d15a9c 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1220,6 +1220,7 @@ OBJS = \
gcse.o \
ggc-common.o \
gimple.o \
+ gimple-builder.o \
gimple-iterator.o \
gimple-fold.o \
gimple-low.o \
diff --git a/gcc/asan.c b/gcc/asan.c
index 32f183775cd..2e1fb0e4082 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "hash-table.h"
#include "alloc-pool.h"
#include "cfgloop.h"
+#include "gimple-builder.h"
/* AddressSanitizer finds out-of-bounds and use-after-free bugs
with <2x slowdown on average.
diff --git a/gcc/gimple-builder.c b/gcc/gimple-builder.c
new file mode 100644
index 00000000000..665c8020b93
--- /dev/null
+++ b/gcc/gimple-builder.c
@@ -0,0 +1,118 @@
+/* Functions for high level gimple building routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-ssa.h"
+
+
+/* Return the expression type to use based on the CODE and type of
+ the given operand OP. If the expression CODE is a comparison,
+ the returned type is boolean_type_node. Otherwise, it returns
+ the type of OP. */
+
+static tree
+get_expr_type (enum tree_code code, tree op)
+{
+ return (TREE_CODE_CLASS (code) == tcc_comparison)
+ ? boolean_type_node
+ : TREE_TYPE (op);
+}
+
+
+/* Build a new gimple assignment. The LHS of the assignment is a new
+ temporary whose type matches the given expression. MODE indicates
+ whether the LHS should be an SSA or a normal temporary. CODE is
+ the expression code for the RHS. OP1 is the first operand and VAL
+ is an integer value to be used as the second operand. */
+
+gimple
+build_assign (enum tree_code code, tree op1, int val, tree lhs)
+{
+ tree op2 = build_int_cst (TREE_TYPE (op1), val);
+ if (lhs == NULL_TREE)
+ lhs = make_ssa_name (get_expr_type (code, op1), NULL);
+ return gimple_build_assign_with_ops (code, lhs, op1, op2);
+}
+
+gimple
+build_assign (enum tree_code code, gimple g, int val, tree lhs )
+{
+ return build_assign (code, gimple_assign_lhs (g), val, lhs);
+}
+
+
+/* Build and return a new GIMPLE assignment. The new assignment will
+ have the opcode CODE and operands OP1 and OP2. The type of the
+ expression on the RHS is inferred to be the type of OP1.
+
+ The LHS of the statement will be an SSA name or a GIMPLE temporary
+ in normal form depending on the type of builder invoking this
+ function. */
+
+gimple
+build_assign (enum tree_code code, tree op1, tree op2, tree lhs)
+{
+ if (lhs == NULL_TREE)
+ lhs = make_ssa_name (get_expr_type (code, op1), NULL);
+ return gimple_build_assign_with_ops (code, lhs, op1, op2);
+}
+
+gimple
+build_assign (enum tree_code code, gimple op1, tree op2, tree lhs)
+{
+ return build_assign (code, gimple_assign_lhs (op1), op2, lhs);
+}
+
+gimple
+build_assign (enum tree_code code, tree op1, gimple op2, tree lhs)
+{
+ return build_assign (code, op1, gimple_assign_lhs (op2), lhs);
+}
+
+gimple
+build_assign (enum tree_code code, gimple op1, gimple op2, tree lhs)
+{
+ return build_assign (code, gimple_assign_lhs (op1), gimple_assign_lhs (op2),
+ lhs);
+}
+
+
+/* Create and return a type cast assignment. This creates a NOP_EXPR
+ that converts OP to TO_TYPE. */
+
+gimple
+build_type_cast (tree to_type, tree op, tree lhs)
+{
+ if (lhs == NULL_TREE)
+ lhs = make_ssa_name (to_type, NULL);
+ return gimple_build_assign_with_ops (NOP_EXPR, lhs, op, NULL_TREE);
+}
+
+gimple
+build_type_cast (tree to_type, gimple op, tree lhs)
+{
+ return build_type_cast (to_type, gimple_assign_lhs (op), lhs);
+}
+
+
+
diff --git a/gcc/gimple-builder.h b/gcc/gimple-builder.h
new file mode 100644
index 00000000000..532c04e2189
--- /dev/null
+++ b/gcc/gimple-builder.h
@@ -0,0 +1,34 @@
+/* Header file for high level statement building routines.
+ Copyright (C) 2013 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+
+#ifndef GCC_GIMPLE_BUILDER_H
+#define GCC_GIMPLE_BUILDER_H
+
+tree create_gimple_tmp (tree, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, tree, int, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, gimple, int, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, tree, tree, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, gimple, tree, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, tree, gimple, tree lhs = NULL_TREE);
+gimple build_assign (enum tree_code, gimple, gimple, tree lhs = NULL_TREE);
+gimple build_type_cast (tree, tree, tree lhs = NULL_TREE);
+gimple build_type_cast (tree, gimple, tree lhs = NULL_TREE);
+
+#endif /* GCC_GIMPLE_BUILDER_H */
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 59fcf4335a3..6a182700cfd 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "basic-block.h"
#include "gimple.h"
#include "diagnostic.h"
-#include "tree-ssa.h"
+#include "tree-flow.h"
#include "value-prof.h"
#include "flags.h"
#include "alias.h"
@@ -2156,39 +2156,6 @@ gimple_set_lhs (gimple stmt, tree lhs)
gcc_unreachable();
}
-/* Replace the LHS of STMT, an assignment, either a GIMPLE_ASSIGN or a
- GIMPLE_CALL, with NLHS, in preparation for modifying the RHS to an
- expression with a different value.
-
- This will update any annotations (say debug bind stmts) referring
- to the original LHS, so that they use the RHS instead. This is
- done even if NLHS and LHS are the same, for it is understood that
- the RHS will be modified afterwards, and NLHS will not be assigned
- an equivalent value.
-
- Adjusting any non-annotation uses of the LHS, if needed, is a
- responsibility of the caller.
-
- The effect of this call should be pretty much the same as that of
- inserting a copy of STMT before STMT, and then removing the
- original stmt, at which time gsi_remove() would have update
- annotations, but using this function saves all the inserting,
- copying and removing. */
-
-void
-gimple_replace_lhs (gimple stmt, tree nlhs)
-{
- if (MAY_HAVE_DEBUG_STMTS)
- {
- tree lhs = gimple_get_lhs (stmt);
-
- gcc_assert (SSA_NAME_DEF_STMT (lhs) == stmt);
-
- insert_debug_temp_for_var_def (NULL, lhs);
- }
-
- gimple_set_lhs (stmt, nlhs);
-}
/* Return a deep copy of statement STMT. All the operands from STMT
are reallocated and copied using unshare_expr. The DEF, USE, VDEF
@@ -3739,96 +3706,6 @@ gimple_get_alias_set (tree t)
}
-/* 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 (TREE_CODE (*tp) == MEM_REF && 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. */
@@ -4225,106 +4102,6 @@ gimple_asm_clobbers_memory_p (const_gimple stmt)
}
-/* Create and return an unnamed temporary. MODE indicates whether
- this should be an SSA or NORMAL temporary. TYPE is the type to use
- for the new temporary. */
-
-tree
-create_gimple_tmp (tree type, enum ssa_mode mode)
-{
- return (mode == M_SSA)
- ? make_ssa_name (type, NULL)
- : create_tmp_var (type, NULL);
-}
-
-
-/* Return the expression type to use based on the CODE and type of
- the given operand OP. If the expression CODE is a comparison,
- the returned type is boolean_type_node. Otherwise, it returns
- the type of OP. */
-
-static tree
-get_expr_type (enum tree_code code, tree op)
-{
- return (TREE_CODE_CLASS (code) == tcc_comparison)
- ? boolean_type_node
- : TREE_TYPE (op);
-}
-
-
-/* Build a new gimple assignment. The LHS of the assignment is a new
- temporary whose type matches the given expression. MODE indicates
- whether the LHS should be an SSA or a normal temporary. CODE is
- the expression code for the RHS. OP1 is the first operand and VAL
- is an integer value to be used as the second operand. */
-
-gimple
-build_assign (enum tree_code code, tree op1, int val, enum ssa_mode mode)
-{
- tree op2 = build_int_cst (TREE_TYPE (op1), val);
- tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
- return gimple_build_assign_with_ops (code, lhs, op1, op2);
-}
-
-gimple
-build_assign (enum tree_code code, gimple g, int val, enum ssa_mode mode)
-{
- return build_assign (code, gimple_assign_lhs (g), val, mode);
-}
-
-
-/* Build and return a new GIMPLE assignment. The new assignment will
- have the opcode CODE and operands OP1 and OP2. The type of the
- expression on the RHS is inferred to be the type of OP1.
-
- The LHS of the statement will be an SSA name or a GIMPLE temporary
- in normal form depending on the type of builder invoking this
- function. */
-
-gimple
-build_assign (enum tree_code code, tree op1, tree op2, enum ssa_mode mode)
-{
- tree lhs = create_gimple_tmp (get_expr_type (code, op1), mode);
- return gimple_build_assign_with_ops (code, lhs, op1, op2);
-}
-
-gimple
-build_assign (enum tree_code code, gimple op1, tree op2, enum ssa_mode mode)
-{
- return build_assign (code, gimple_assign_lhs (op1), op2, mode);
-}
-
-gimple
-build_assign (enum tree_code code, tree op1, gimple op2, enum ssa_mode mode)
-{
- return build_assign (code, op1, gimple_assign_lhs (op2), mode);
-}
-
-gimple
-build_assign (enum tree_code code, gimple op1, gimple op2, enum ssa_mode mode)
-{
- return build_assign (code, gimple_assign_lhs (op1), gimple_assign_lhs (op2),
- mode);
-}
-
-
-/* Create and return a type cast assignment. This creates a NOP_EXPR
- that converts OP to TO_TYPE. */
-
-gimple
-build_type_cast (tree to_type, tree op, enum ssa_mode mode)
-{
- tree lhs = create_gimple_tmp (to_type, mode);
- return gimple_build_assign_with_ops (NOP_EXPR, lhs, op, NULL_TREE);
-}
-
-gimple
-build_type_cast (tree to_type, gimple op, enum ssa_mode mode)
-{
- return build_type_cast (to_type, gimple_assign_lhs (op), mode);
-}
-
-
/* Return true if the conversion from INNER_TYPE to OUTER_TYPE is a
useless type conversion, otherwise return false.
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 5f1280586d2..3047ab4b667 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -730,19 +730,6 @@ union GTY ((desc ("gimple_statement_structure (&%h)"),
struct gimple_statement_transaction GTY((tag ("GSS_TRANSACTION"))) gimple_transaction;
};
-/* In gimple.c. */
-
-/* Helper functions to build GIMPLE statements. */
-tree create_gimple_tmp (tree, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, tree, int, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, gimple, int, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, tree, tree, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, gimple, tree, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, tree, gimple, enum ssa_mode = M_SSA);
-gimple build_assign (enum tree_code, gimple, gimple, enum ssa_mode = M_SSA);
-gimple build_type_cast (tree, tree, enum ssa_mode = M_SSA);
-gimple build_type_cast (tree, gimple, enum ssa_mode = M_SSA);
-
/* Offset in bytes to the location of the operand vector.
Zero if there is no operand vector for this tuple structure. */
extern size_t const gimple_ops_offset_[];
@@ -909,8 +896,6 @@ extern void free_gimple_type_tables (void);
extern tree gimple_unsigned_type (tree);
extern tree gimple_signed_type (tree);
extern alias_set_type gimple_get_alias_set (tree);
-extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
- unsigned *);
extern bool walk_stmt_load_store_addr_ops (gimple, void *,
bool (*)(gimple, tree, void *),
bool (*)(gimple, tree, void *),
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 54445beee7c..149e080ff19 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -608,7 +608,7 @@ execute_cse_reciprocals (void)
if (fail)
continue;
- gimple_replace_lhs (stmt1, arg1);
+ gimple_replace_ssa_lhs (stmt1, arg1);
gimple_call_set_fndecl (stmt1, fndecl);
update_stmt (stmt1);
reciprocal_stats.rfuncs_inserted++;
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 6dffe7e9a81..b378f57e8f5 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -3682,7 +3682,7 @@ repropagate_negates (void)
tree a = gimple_assign_rhs1 (feed);
tree rhs2 = gimple_assign_rhs2 (user);
gimple_stmt_iterator gsi = gsi_for_stmt (feed), gsi2;
- gimple_replace_lhs (feed, negate);
+ gimple_replace_ssa_lhs (feed, negate);
gimple_assign_set_rhs_with_ops (&gsi, PLUS_EXPR, a, rhs2);
update_stmt (gsi_stmt (gsi));
gsi2 = gsi_for_stmt (user);
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 8146e1fed1d..8c340ded1af 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -231,6 +231,135 @@ flush_pending_stmts (edge e)
redirect_edge_var_map_clear (e);
}
+
+/* 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 (TREE_CODE (*tp) == MEM_REF && 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);
+}
+
+
+/* Replace the LHS of STMT, an assignment, either a GIMPLE_ASSIGN or a
+ GIMPLE_CALL, with NLHS, in preparation for modifying the RHS to an
+ expression with a different value.
+
+ This will update any annotations (say debug bind stmts) referring
+ to the original LHS, so that they use the RHS instead. This is
+ done even if NLHS and LHS are the same, for it is understood that
+ the RHS will be modified afterwards, and NLHS will not be assigned
+ an equivalent value.
+
+ Adjusting any non-annotation uses of the LHS, if needed, is a
+ responsibility of the caller.
+
+ The effect of this call should be pretty much the same as that of
+ inserting a copy of STMT before STMT, and then removing the
+ original stmt, at which time gsi_remove() would have update
+ annotations, but using this function saves all the inserting,
+ copying and removing. */
+
+void
+gimple_replace_ssa_lhs (gimple stmt, tree nlhs)
+{
+ if (MAY_HAVE_DEBUG_STMTS)
+ {
+ tree lhs = gimple_get_lhs (stmt);
+
+ gcc_assert (SSA_NAME_DEF_STMT (lhs) == stmt);
+
+ insert_debug_temp_for_var_def (NULL, lhs);
+ }
+
+ gimple_set_lhs (stmt, nlhs);
+}
+
+
/* Given a tree for an expression for which we might want to emit
locations or values in debug information (generally a variable, but
we might deal with other kinds of trees in the future), return the
diff --git a/gcc/tree-ssa.h b/gcc/tree-ssa.h
index 1808b1c447a..7ffb332252b 100644
--- a/gcc/tree-ssa.h
+++ b/gcc/tree-ssa.h
@@ -42,6 +42,9 @@ extern edge_var_map_vector *redirect_edge_var_map_vector (edge);
extern void redirect_edge_var_map_destroy (void);
extern edge ssa_redirect_edge (edge, basic_block);
extern void flush_pending_stmts (edge);
+extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *,
+ unsigned *);
+extern void gimple_replace_ssa_lhs (gimple, tree);
extern tree target_for_debug_bind (tree);
extern void insert_debug_temp_for_var_def (gimple_stmt_iterator *, tree);
extern void insert_debug_temps_for_defs (gimple_stmt_iterator *);