#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "ggc.h"
#include "tree.h"
#include "tree-flow.h"
#include "hashtab.h"
#include "langhooks.h"
#include "tree-pass.h"
#include "tree-dump.h"
#include "diagnostic.h"
static htab_t value_table;
typedef struct val_expr_pair_d
{
tree v;
tree e;
vuse_optype vuses;
hashval_t hashcode;
} *val_expr_pair_t;
static void set_value_handle (tree e, tree v);
static tree
make_value_handle (tree type)
{
static unsigned int id = 0;
tree vh;
vh = build0 (VALUE_HANDLE, type);
VALUE_HANDLE_ID (vh) = id++;
return vh;
}
hashval_t
vn_compute (tree expr, hashval_t val, vuse_optype vuses)
{
size_t i;
gcc_assert (expr);
gcc_assert (!expr->common.ann
|| expr->common.ann->common.type != STMT_ANN);
val = iterative_hash_expr (expr, val);
for (i = 0; i < NUM_VUSES (vuses); i++)
val = iterative_hash_expr (VUSE_OP (vuses, i), val);
return val;
}
bool
expressions_equal_p (tree e1, tree e2)
{
tree te1, te2;
if (e1 == e2)
return true;
te1 = TREE_TYPE (e1);
te2 = TREE_TYPE (e2);
if (TREE_CODE (e1) == TREE_CODE (e2)
&& (te1 == te2 || lang_hooks.types_compatible_p (te1, te2))
&& operand_equal_p (e1, e2, OEP_PURE_SAME))
return true;
return false;
}
static hashval_t
val_expr_pair_hash (const void *p)
{
const val_expr_pair_t ve = (val_expr_pair_t) p;
return ve->hashcode;
}
static int
val_expr_pair_expr_eq (const void *p1, const void *p2)
{
const val_expr_pair_t ve1 = (val_expr_pair_t) p1;
const val_expr_pair_t ve2 = (val_expr_pair_t) p2;
size_t i;
if (! expressions_equal_p (ve1->e, ve2->e))
return false;
if (NUM_VUSES (ve1->vuses) != NUM_VUSES (ve2->vuses))
return false;
for (i = 0; i < NUM_VUSES (ve1->vuses); i++)
if (! expressions_equal_p (VUSE_OP (ve1->vuses, i),
VUSE_OP (ve2->vuses, i)))
return false;
return true;
}
static void
set_value_handle (tree e, tree v)
{
if (TREE_CODE (e) == SSA_NAME)
SSA_NAME_VALUE (e) = v;
else if (EXPR_P (e) || DECL_P (e))
get_tree_ann (e)->common.value_handle = v;
else
gcc_assert (is_gimple_min_invariant (e));
}
void
vn_add (tree expr, tree val, vuse_optype vuses)
{
void **slot;
val_expr_pair_t new_pair;
new_pair = xmalloc (sizeof (struct val_expr_pair_d));
new_pair->e = expr;
new_pair->v = val;
new_pair->vuses = vuses;
new_pair->hashcode = vn_compute (expr, 0, vuses);
slot = htab_find_slot_with_hash (value_table, new_pair, new_pair->hashcode,
INSERT);
if (*slot)
free (*slot);
*slot = (void *) new_pair;
set_value_handle (expr, val);
add_to_value (val, expr);
}
tree
vn_lookup (tree expr, vuse_optype vuses)
{
void **slot;
struct val_expr_pair_d vep = {NULL, NULL, NULL, 0};
if (is_gimple_min_invariant (expr))
return expr;
vep.e = expr;
vep.vuses = vuses;
vep.hashcode = vn_compute (expr, 0, vuses);
slot = htab_find_slot_with_hash (value_table, &vep, vep.hashcode, NO_INSERT);
if (!slot)
return NULL_TREE;
else
return ((val_expr_pair_t) *slot)->v;
}
tree
vn_lookup_or_add (tree expr, vuse_optype vuses)
{
tree v = vn_lookup (expr, vuses);
if (v == NULL_TREE)
{
v = make_value_handle (TREE_TYPE (expr));
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Created value ");
print_generic_expr (dump_file, v, dump_flags);
fprintf (dump_file, " for ");
print_generic_expr (dump_file, expr, dump_flags);
fprintf (dump_file, "\n");
}
vn_add (expr, v, vuses);
}
set_value_handle (expr, v);
return v;
}
tree
get_value_handle (tree expr)
{
if (is_gimple_min_invariant (expr))
return expr;
if (TREE_CODE (expr) == SSA_NAME)
return SSA_NAME_VALUE (expr);
else if (EXPR_P (expr) || DECL_P (expr))
{
tree_ann_t ann = tree_ann (expr);
return ((ann) ? ann->common.value_handle : NULL_TREE);
}
else
gcc_unreachable ();
}
void
vn_init (void)
{
value_table = htab_create (511, val_expr_pair_hash,
val_expr_pair_expr_eq, free);
}
void
vn_delete (void)
{
htab_delete (value_table);
value_table = NULL;
}