Commit ff2a63a7 by Andrew MacLeod Committed by Andrew Macleod

gimple.c (gimple_replace_lhs): Move to tree-ssa.c and rename.


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.

From-SVN: r202945
parent a2544177
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
......
......@@ -1220,6 +1220,7 @@ OBJS = \
gcse.o \
ggc-common.o \
gimple.o \
gimple-builder.o \
gimple-iterator.o \
gimple-fold.o \
gimple-low.o \
......
......@@ -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.
......
/* 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);
}
/* 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 */
......@@ -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.
......
......@@ -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 *),
......
......@@ -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++;
......
......@@ -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);
......
......@@ -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
......
......@@ -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 *);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment