tree-alias-common.c [plain text]
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "ggc.h"
#include "tree-alias-type.h"
#include "bitmap.h"
#include "tree-alias-common.h"
#ifdef HAVE_BANSHEE
#include "tree-alias-ander.h"
#endif
#include "flags.h"
#include "rtl.h"
#include "tm_p.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "output.h"
#include "errors.h"
#include "expr.h"
#include "diagnostic.h"
#include "tree.h"
#include "c-common.h"
#include "tree-flow.h"
#include "tree-inline.h"
#include "varray.h"
#include "c-tree.h"
#include "tree-gimple.h"
#include "hashtab.h"
#include "function.h"
#include "cgraph.h"
#include "tree-pass.h"
#include "timevar.h"
#define FIELD_BASED 0
static GTY((param_is (union alias_var_def))) varray_type alias_vars = NULL;
struct tree_alias_ops *current_alias_ops;
static GTY(()) varray_type local_alias_vars;
static GTY(()) varray_type local_alias_varnums;
tree pta_global_var;
static bitmap addrargs;
static alias_var get_alias_var_decl (tree);
static alias_var get_alias_var (tree);
static void find_func_aliases (tree);
static void deal_with_call_aliasing (tree, alias_var);
static alias_var create_fun_alias_var_ptf (tree, tree);
static alias_var create_fun_alias_var (tree, int);
static alias_var create_alias_var (tree);
static void intra_function_call (varray_type);
static void get_values_from_constructor (tree, varray_type *, bitmap, int *);
static bool call_may_clobber (tree);
static bool call_may_return (tree);
static bool
call_may_clobber (tree expr)
{
int flags;
if (TREE_CODE (expr) != CALL_EXPR)
return false;
flags = call_expr_flags (expr);
return (! (flags & (ECF_CONST | ECF_PURE | ECF_NORETURN)));
}
static bool
call_may_return (tree expr)
{
int flags;
if (TREE_CODE (expr) != CALL_EXPR)
return false;
flags = call_expr_flags (expr);
return ! (flags & ECF_NORETURN);
}
static alias_var
get_alias_var_decl (tree decl)
{
alias_var newvar;
if (TREE_CODE (decl) == FIELD_DECL)
abort ();
if (DECL_P (decl))
{
if (DECL_PTA_ALIASVAR (decl))
return DECL_PTA_ALIASVAR (decl);
}
if (TREE_CODE (decl) == FUNCTION_DECL)
newvar = create_fun_alias_var (decl, 0);
else
{
newvar = create_alias_var (decl);
if ((DECL_CONTEXT (decl) == NULL
|| TREE_PUBLIC (decl)
|| TREE_STATIC (decl)
|| decl_function_context (decl) == NULL)
&& decl != pta_global_var)
{
current_alias_ops->addr_assign (current_alias_ops,
get_alias_var (pta_global_var),
newvar);
if (DECL_INITIAL (decl))
find_func_aliases (decl);
}
}
if (!current_alias_ops->ip)
{
if (!current_alias_ops->ip_partial
|| (TREE_CODE (decl) != FUNCTION_DECL
&& TREE_CODE (decl) != PARM_DECL))
{
VARRAY_PUSH_INT (local_alias_varnums, ALIAS_VAR_VARNUM (newvar));
VARRAY_PUSH_TREE (local_alias_vars, decl);
}
}
return newvar;
}
static alias_var
get_alias_var (tree expr)
{
if (DECL_P (expr))
return get_alias_var_decl (expr);
if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
return NULL;
switch (TREE_CODE (expr))
{
case ARRAY_REF:
{
tree p;
for (p = expr; TREE_CODE (p) == ARRAY_REF;
p = TREE_OPERAND (p, 0));
return get_alias_var (p);
}
break;
case COMPONENT_REF:
{
#if FIELD_BASED
bool safe = true;
tree p;
for (p = expr;
TREE_CODE (p) == COMPONENT_REF || TREE_CODE (p) == INDIRECT_REF;
p = TREE_OPERAND (p, 0))
{
if (TREE_CODE (TREE_TYPE (p)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (p)) == QUAL_UNION_TYPE)
{
safe = false;
break;
}
}
if (!safe)
{
for (p = expr; TREE_CODE (p) == COMPONENT_REF;
p = TREE_OPERAND (p, 0));
return get_alias_var (p);
}
else
{
return get_alias_var (TREE_OPERAND (expr, 1));
}
#else
tree p;
for (p = expr; TREE_CODE (p) == COMPONENT_REF;
p = TREE_OPERAND (p, 0));
return get_alias_var (p);
#endif
}
break;
case REALPART_EXPR:
case IMAGPART_EXPR:
case NOP_EXPR:
case CONVERT_EXPR:
case FIX_TRUNC_EXPR:
case FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case ADDR_EXPR:
case INDIRECT_REF:
case BIT_FIELD_REF:
return get_alias_var (TREE_OPERAND (expr, 0));
break;
default:
return NULL;
}
}
static void
intra_function_call (varray_type args)
{
size_t l = VARRAY_ACTIVE_SIZE (args);
size_t i;
alias_var av = get_alias_var (pta_global_var);
for (i = 0; i < l; i++)
{
alias_var argi = VARRAY_GENERIC_PTR (args, i);
size_t j;
for (j = 0; j < l; j++)
{
alias_var argj;
if (i == j)
continue;
argj = VARRAY_GENERIC_PTR (args, j);
if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argi)))
|| !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argj))))
if (alias_sets_conflict_p (get_alias_set (ALIAS_VAR_DECL (argi)),
get_alias_set (ALIAS_VAR_DECL (argj))))
current_alias_ops->simple_assign (current_alias_ops, argi, argj);
}
}
for (i = 0; i < l; i++)
{
alias_var argav = VARRAY_GENERIC_PTR (args, i);
if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argav)))
|| !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (av))))
{
current_alias_ops->simple_assign (current_alias_ops, argav, av);
}
}
}
static void
get_values_from_constructor (tree constructor, varray_type *vals,
bitmap addrargs, int *i)
{
tree elt_list;
switch (TREE_CODE (constructor))
{
case CONSTRUCTOR:
{
for (elt_list = CONSTRUCTOR_ELTS (constructor);
elt_list;
elt_list = TREE_CHAIN (elt_list))
{
tree value = TREE_VALUE (elt_list);
if (TREE_CODE (value) == TREE_LIST
|| TREE_CODE (value) == CONSTRUCTOR)
{
get_values_from_constructor (value, vals, addrargs, i); }
else
{
alias_var aav;
aav = get_alias_var (value);
if (aav)
VARRAY_PUSH_GENERIC_PTR (*vals, aav);
if (TREE_CODE (value) == ADDR_EXPR)
bitmap_set_bit (addrargs, *i);
*i = *i + 1;
}
}
}
break;
case TREE_LIST:
for (elt_list = constructor;
elt_list;
elt_list = TREE_CHAIN (elt_list))
{
get_values_from_constructor (TREE_VALUE (elt_list), vals, addrargs, i);
}
break;
default:
abort();
}
}
static void
deal_with_call_aliasing (tree callargs, alias_var lhsAV)
{
tree arg, argp;
for (argp = callargs;
argp;
argp = TREE_CHAIN (argp))
{
arg = TREE_VALUE (argp);
if (TREE_CODE (arg) == ADDR_EXPR)
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
get_alias_var (arg));
else if (POINTER_TYPE_P (TREE_TYPE (arg)))
{
alias_var argtv = get_alias_var (arg);
if (argtv)
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
argtv);
}
}
}
static tree
find_op_of_decl (tree cref)
{
while (!DECL_P (TREE_OPERAND (cref, 0)))
{
cref = TREE_OPERAND (cref, 0);
}
return cref;
}
static void
find_func_aliases (tree stp)
{
if (TREE_CODE (stp) == RETURN_EXPR)
{
stp = TREE_OPERAND (stp, 0);
if (!stp)
return;
}
if (TREE_CODE (stp) == MODIFY_EXPR
|| (DECL_P (stp) && DECL_INITIAL (stp) != NULL_TREE ))
{
tree op0, op1;
alias_var lhsAV = NULL;
alias_var rhsAV = NULL;
if (DECL_P (stp))
{
op0 = stp;
op1 = DECL_INITIAL (stp);
}
else
{
op0 = TREE_OPERAND (stp, 0);
op1 = TREE_OPERAND (stp, 1);
}
lhsAV = get_alias_var (op0);
if (!lhsAV)
return;
rhsAV = get_alias_var (op1);
#if !FIELD_BASED
while (TREE_CODE (op1) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (op1, 0)) == COMPONENT_REF)
{
op1 = TREE_OPERAND (op1, 0);
}
while (TREE_CODE (op1) == BIT_FIELD_REF)
{
op1 = TREE_OPERAND (op1, 0);
}
if (TREE_CODE (op1) == COMPONENT_REF)
op1 = find_op_of_decl (op1);
#endif
if (is_gimple_variable (op0))
{
if (is_gimple_variable (op1))
{
if (rhsAV != NULL)
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if (TREE_CODE (op1) == COMPONENT_REF
&& DECL_P (TREE_OPERAND (op1, 0)))
{
if (rhsAV != NULL)
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if (is_gimple_cast (op1))
{
tree stripped_op1 = op1;
STRIP_NOPS (stripped_op1);
if (rhsAV != NULL)
{
if (TREE_CODE (stripped_op1) == ADDR_EXPR)
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
rhsAV);
else
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
rhsAV);
}
}
else if (TREE_CODE (op1) == INDIRECT_REF
|| TREE_CODE (op1) == ARRAY_REF
|| (TREE_CODE (op1) == COMPONENT_REF
&& TREE_CODE (TREE_OPERAND (op1, 0)) == INDIRECT_REF))
{
if (rhsAV != NULL)
current_alias_ops->ptr_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if (TREE_CODE (op1) == ADDR_EXPR)
{
if (rhsAV != NULL)
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if (TREE_CODE (op1) == CALL_EXPR)
{
if (0)
{}
else
{
if (call_may_return (op1))
{
varray_type args;
tree arg;
tree callop0, callop1;
int argnum;
VARRAY_GENERIC_PTR_INIT (args, 1, "Arguments");
bitmap_clear (addrargs);
callop1 = TREE_OPERAND (op1, 1);
callop0 = TREE_OPERAND (op1, 0);
for (arg = callop1, argnum = 0;
arg;
arg = TREE_CHAIN (arg), argnum++)
{
alias_var aav = get_alias_var (TREE_VALUE (arg));
if (aav)
{
VARRAY_PUSH_GENERIC_PTR (args, aav);
if (TREE_CODE (TREE_VALUE (arg)) == ADDR_EXPR)
bitmap_set_bit (addrargs, argnum);
}
}
if (current_alias_ops->function_call (current_alias_ops, lhsAV,
get_alias_var (callop0),
args, addrargs))
{
if (call_may_clobber (op1)
&& !current_alias_ops->ip
&& flag_argument_noalias != 2)
{
intra_function_call (args);
}
if (POINTER_TYPE_P (TREE_TYPE (op0)))
deal_with_call_aliasing (callop1, lhsAV);
}
}
}
}
else
{
bitmap_clear (addrargs);
if (TREE_CODE (op1) == CONSTRUCTOR)
{
varray_type ops;
int i = 0;
VARRAY_GENERIC_PTR_INIT (ops, 1, "Operands");
get_values_from_constructor (op1, &ops, addrargs, &i);
current_alias_ops->op_assign (current_alias_ops, lhsAV,
ops, op1, addrargs);
}
else
switch (TREE_CODE_CLASS (TREE_CODE (op1)))
{
case 'e':
case 's':
case '<':
case '1':
case 'r':
case '2':
{
tree op;
varray_type ops;
int i;
VARRAY_GENERIC_PTR_INIT (ops, 1, "Operands");
for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (op1)); i++)
{
alias_var aav;
op = TREE_OPERAND (op1, i);
aav = get_alias_var (op);
if (aav)
VARRAY_PUSH_GENERIC_PTR (ops, aav);
if (TREE_CODE (op) == ADDR_EXPR)
bitmap_set_bit (addrargs, i);
}
current_alias_ops->op_assign (current_alias_ops, lhsAV,
ops, op1, addrargs);
}
break;
default:
break;
}
}
}
else
{
if ((TREE_CODE (op0) == COMPONENT_REF
|| TREE_CODE (op0) == BIT_FIELD_REF)
&& is_gimple_variable (op1))
{
if (rhsAV != NULL)
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if (TREE_CODE (op0) == COMPONENT_REF
&& TREE_CODE (op1) == ADDR_EXPR)
{
if (rhsAV != NULL)
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
rhsAV);
}
else if ((TREE_CODE (op0) == INDIRECT_REF
|| TREE_CODE (op0) == ARRAY_REF)
&& TREE_CODE (TREE_OPERAND (op0, 0)) == COMPONENT_REF
&& is_gimple_variable (op1))
{
if (rhsAV != NULL)
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
rhsAV);
}
else if ((TREE_CODE (op0) == INDIRECT_REF
|| TREE_CODE (op0) == ARRAY_REF)
&& TREE_CODE (op1) == ADDR_EXPR)
{
alias_var tempvar;
tree temp = create_tmp_var_raw (void_type_node, "aliastmp");
tempvar = current_alias_ops->add_var (current_alias_ops, temp);
current_alias_ops->addr_assign (current_alias_ops, tempvar,
rhsAV);
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
tempvar);
}
else if ((TREE_CODE (op0) == INDIRECT_REF
|| TREE_CODE (op0) == ARRAY_REF)
&& (TREE_CODE (op1) == INDIRECT_REF
|| TREE_CODE (op1) == ARRAY_REF))
{
alias_var tempvar;
tree temp;
temp = create_tmp_var_raw (void_type_node, "aliastmp");
tempvar = current_alias_ops->add_var (current_alias_ops, temp);
current_alias_ops->ptr_assign (current_alias_ops, tempvar,
rhsAV);
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
tempvar);
}
else if ((TREE_CODE (op0) == INDIRECT_REF
|| TREE_CODE (op0) == ARRAY_REF)
&& is_gimple_cast (op1))
{
if (rhsAV != NULL)
{
alias_var tempvar;
tree temp;
temp = create_tmp_var_raw (void_type_node, "aliastmp");
tempvar = current_alias_ops->add_var (current_alias_ops,
temp);
current_alias_ops->simple_assign (current_alias_ops,
tempvar, rhsAV);
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
tempvar);
}
}
else
{
if (rhsAV != NULL)
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
rhsAV);
}
}
}
else if (TREE_CODE (stp) == CALL_EXPR)
{
alias_var callvar;
varray_type args;
tree arg;
callvar = get_alias_var (TREE_OPERAND (stp, 0));
if (callvar != NULL)
{
if (call_may_clobber (stp))
{
int argnum;
VARRAY_GENERIC_PTR_INIT (args, 1, "Arguments");
bitmap_clear (addrargs);
for (arg = TREE_OPERAND (stp, 1), argnum=0;
arg;
arg = TREE_CHAIN (arg), argnum++)
{
alias_var aav = get_alias_var (TREE_VALUE (arg));
if (aav)
{
VARRAY_PUSH_GENERIC_PTR (args, aav);
if (TREE_CODE (TREE_VALUE (arg)) == ADDR_EXPR)
bitmap_set_bit (addrargs, argnum);
}
}
if (current_alias_ops->function_call (current_alias_ops, NULL,
callvar, args, addrargs))
if (!current_alias_ops->ip && flag_argument_noalias != 2)
intra_function_call (args);
}
}
}
}
static alias_var
create_fun_alias_var (tree decl, int force)
{
alias_var avar, retvar;
tree rdecl;
varray_type params = NULL;
if (!force)
{
if (DECL_PTA_ALIASVAR (decl))
return DECL_PTA_ALIASVAR (decl);
}
VARRAY_GENERIC_PTR_INIT (params, 1, "Arguments");
if (DECL_ARGUMENTS (decl) != NULL)
{
tree arg;
for (arg = DECL_ARGUMENTS (decl); arg; arg = TREE_CHAIN (arg))
{
alias_var var = get_alias_var (arg);
VARRAY_PUSH_GENERIC_PTR (params, var);
if (POINTER_TYPE_P (TREE_TYPE (arg))
&& !current_alias_ops->ip
&& (!current_alias_ops->ip_partial
|| !cgraph_local_info (decl)->local))
current_alias_ops->simple_assign (current_alias_ops, var,
get_alias_var (pta_global_var));
}
}
else if (TYPE_ARG_TYPES (TREE_TYPE (decl)) != NULL)
{
tree arg;
for (arg = TYPE_ARG_TYPES (TREE_TYPE (decl));
arg && TREE_VALUE (arg) != void_type_node;
arg = TREE_CHAIN (arg))
{
tree fakedecl = create_tmp_var_raw (TREE_VALUE (arg), "normarg");
alias_var var;
DECL_CONTEXT (fakedecl) = current_function_decl;
var = get_alias_var (fakedecl);
VARRAY_PUSH_GENERIC_PTR (params, var);
if (POINTER_TYPE_P (TREE_TYPE (fakedecl))
&& !current_alias_ops->ip
&& (!current_alias_ops->ip_partial
|| !TREE_STATIC (decl)
|| TREE_PUBLIC (decl)))
current_alias_ops->simple_assign (current_alias_ops, var,
get_alias_var (pta_global_var));
}
}
else
{
tree fakedecl = create_tmp_var_raw (void_type_node, "fakearg");
alias_var fakevar;
DECL_CONTEXT (fakedecl) = current_function_decl;
fakevar = get_alias_var (fakedecl);
VARRAY_PUSH_GENERIC_PTR (params, fakevar);
}
if (!DECL_RESULT (decl))
{
rdecl = create_tmp_var_raw (TREE_TYPE (TREE_TYPE (decl)), "_rv_");
retvar = current_alias_ops->add_var (current_alias_ops, rdecl);
DECL_PTA_ALIASVAR (rdecl) = retvar;
}
else
{
retvar = current_alias_ops->add_var (current_alias_ops,
DECL_RESULT (decl));
DECL_PTA_ALIASVAR (DECL_RESULT (decl)) = retvar;
}
VARRAY_PUSH_GENERIC_PTR (alias_vars, retvar);
ALIAS_VAR_VARNUM (retvar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
avar = current_alias_ops->add_var (current_alias_ops, decl);
VARRAY_PUSH_GENERIC_PTR (alias_vars, avar);
ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
current_alias_ops->function_def (current_alias_ops, avar, params, retvar);
DECL_PTA_ALIASVAR (decl) = avar;
return avar;
}
static alias_var
create_fun_alias_var_ptf (tree decl, tree type)
{
alias_var avar, retvar;
tree rdecl;
varray_type params = NULL;
if (DECL_PTA_ALIASVAR (decl))
return DECL_PTA_ALIASVAR (decl);
VARRAY_GENERIC_PTR_INIT (params, 1, "Arguments");
if (TYPE_ARG_TYPES (type) != NULL)
{
tree arg;
for (arg = TYPE_ARG_TYPES (type);
arg && TREE_VALUE (arg) != void_type_node;
arg = TREE_CHAIN (arg))
{
tree fakedecl = create_tmp_var_raw (TREE_VALUE (arg), "ptfarg");
alias_var var;
DECL_CONTEXT (fakedecl) = DECL_CONTEXT (decl);
var = get_alias_var (fakedecl);
VARRAY_PUSH_GENERIC_PTR (params, var);
}
}
else
{
tree fakedecl = create_tmp_var_raw (void_type_node, "fakearg");
alias_var fakevar;
DECL_CONTEXT (fakedecl) = DECL_CONTEXT (decl);
fakevar = get_alias_var (fakedecl);
VARRAY_PUSH_GENERIC_PTR (params, fakevar);
}
rdecl = create_tmp_var_raw (TREE_TYPE (type), "_rv_");
retvar = current_alias_ops->add_var (current_alias_ops, rdecl);
VARRAY_PUSH_GENERIC_PTR (alias_vars, retvar);
ALIAS_VAR_VARNUM (retvar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
avar = current_alias_ops->add_var (current_alias_ops, decl);
VARRAY_PUSH_GENERIC_PTR (alias_vars, avar);
ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
current_alias_ops->function_def (current_alias_ops, avar, params, retvar);
DECL_PTA_ALIASVAR (decl) = avar;
return avar;
}
static alias_var
create_alias_var (tree decl)
{
alias_var avar;
if (!DECL_P (decl))
abort ();
if (DECL_P (decl))
{
if (DECL_PTA_ALIASVAR (decl))
return DECL_PTA_ALIASVAR (decl);
}
if (POINTER_TYPE_P (TREE_TYPE (decl))
&& TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == FUNCTION_TYPE)
{
avar = create_fun_alias_var_ptf (decl, TREE_TYPE (TREE_TYPE (decl)));
}
else
avar = current_alias_ops->add_var (current_alias_ops, decl);
if (DECL_P (decl))
{
DECL_PTA_ALIASVAR (decl) = avar;
}
VARRAY_PUSH_GENERIC_PTR (alias_vars, avar);
ALIAS_VAR_VARNUM (avar) = VARRAY_ACTIVE_SIZE (alias_vars) - 1;
return avar;
}
static void
create_alias_vars (void)
{
basic_block bb;
#ifdef HAVE_BANSHEE
if (flag_tree_points_to == PTA_ANDERSEN)
current_alias_ops = andersen_alias_ops;
else
#endif
{
current_alias_ops = NULL;
flag_tree_points_to = PTA_NONE;
return;
}
pta_global_var = build_decl (VAR_DECL, get_identifier (".pta_global_var"),
size_type_node);
DECL_ARTIFICIAL (pta_global_var) = 1;
TREE_READONLY (pta_global_var) = 1;
DECL_EXTERNAL (pta_global_var) = 0;
TREE_STATIC (pta_global_var) = 1;
TREE_USED (pta_global_var) = 1;
DECL_CONTEXT (pta_global_var) = current_function_decl;
TREE_THIS_VOLATILE (pta_global_var) = 1;
TREE_ADDRESSABLE (pta_global_var) = 0;
init_alias_vars ();
DECL_PTA_ALIASVAR (current_function_decl) = NULL;
get_alias_var (current_function_decl);
if (cfun->unexpanded_var_list)
{
tree vars, var;
for (vars = cfun->unexpanded_var_list; vars; vars = TREE_CHAIN (vars))
{
var = TREE_VALUE (vars);
if (TREE_CODE (var) != LABEL_DECL
&& decl_function_context (var) == NULL
&& DECL_INITIAL (var))
find_func_aliases (var);
}
}
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
find_func_aliases (bsi_stmt (bsi));
}
pta_global_var = NULL_TREE;
}
struct tree_opt_pass pass_build_pta =
{
"pta",
NULL,
create_alias_vars,
NULL,
NULL,
0,
TV_TREE_PTA,
PROP_cfg,
PROP_pta,
0,
0,
0
};
static void
delete_alias_vars (void)
{
size_t i;
if (flag_tree_points_to != PTA_ANDERSEN)
return;
for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_vars); i++)
{
tree key = VARRAY_TREE (local_alias_vars, i);
if (DECL_P (key))
DECL_PTA_ALIASVAR (key) = NULL;
else
abort ();
}
for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_varnums); i ++)
VARRAY_GENERIC_PTR (alias_vars, VARRAY_INT (local_alias_varnums, i)) = NULL;
if (!current_alias_ops->ip && !current_alias_ops->ip_partial)
{
VARRAY_CLEAR (local_alias_vars);
VARRAY_CLEAR (local_alias_varnums);
}
BITMAP_XFREE (addrargs);
current_alias_ops->cleanup (current_alias_ops);
}
struct tree_opt_pass pass_del_pta =
{
"pta",
NULL,
delete_alias_vars,
NULL,
NULL,
0,
TV_TREE_PTA,
PROP_pta,
0,
PROP_pta,
0,
0
};
void
init_alias_vars (void)
{
current_alias_ops->init (current_alias_ops);
addrargs = BITMAP_XMALLOC ();
VARRAY_TREE_INIT (local_alias_vars, 10, "Local alias vars");
VARRAY_INT_INIT (local_alias_varnums, 10, "Local alias varnums");
if ((!current_alias_ops->ip && !current_alias_ops->ip_partial)
|| alias_vars == NULL)
VARRAY_GENERIC_PTR_INIT (alias_vars, 10, "Alias vars");
}
bool
empty_points_to_set (tree ptr)
{
alias_var ptrtv;
#if !FIELD_BASED
#else
if (TREE_CODE (ptr) == COMPONENT_REF)
ptr = TREE_OPERAND (ptr, 1);
#endif
if (DECL_P (ptr))
{
ptrtv = DECL_PTA_ALIASVAR (ptr);
if (!ptrtv)
return true;
}
else
abort ();
return current_alias_ops->empty_points_to_set (current_alias_ops, ptrtv);
}
bool
same_points_to_set (tree ptr, tree var)
{
alias_var ptrtv, vartv;
#if !FIELD_BASED
#else
if (TREE_CODE (ptr) == COMPONENT_REF)
ptr = TREE_OPERAND (ptr, 1);
if (TREE_CODE (var) == COMPONENT_REF)
var = TREE_OPERAND (var, 1);
#endif
if (ptr == var)
return true;
if (DECL_P (ptr))
{
ptrtv = DECL_PTA_ALIASVAR (ptr);
if (!ptrtv)
return false;
}
else
abort ();
if (DECL_P (var))
{
vartv = DECL_PTA_ALIASVAR (var);
if (!vartv)
return false;
}
else
abort ();
return current_alias_ops->same_points_to_set (current_alias_ops, vartv, ptrtv);
}
bool
ptr_may_alias_var (tree ptr, tree var)
{
alias_var ptrtv, vartv;
#if !FIELD_BASED
#else
if (TREE_CODE (ptr) == COMPONENT_REF)
ptr = TREE_OPERAND (ptr, 1);
if (TREE_CODE (var) == COMPONENT_REF)
var = TREE_OPERAND (var, 1);
#endif
if (ptr == var)
return true;
if (DECL_P (ptr))
{
ptrtv = DECL_PTA_ALIASVAR (ptr);
if (!ptrtv)
return false;
}
else
abort ();
if (DECL_P (var))
{
vartv = DECL_PTA_ALIASVAR (var);
if (!vartv)
return false;
}
else
abort ();
return current_alias_ops->may_alias (current_alias_ops, ptrtv, vartv);
}
#define MASK_POINTER(P) ((unsigned)((unsigned long)(P) & 0xffff))
const char *
alias_get_name (tree t)
{
const char *name;
#if FIELD_BASED
if (TREE_CODE (t) == FIELD_DECL)
{
const char *fieldname = IDENTIFIER_POINTER (DECL_NAME (t));
const char *prefix = alias_get_name (DECL_CONTEXT (t));
char *smashed;
size_t neededlen = strlen (fieldname) + strlen (prefix) + 2;
smashed = ggc_alloc (neededlen);
sprintf (smashed, "%s.%s", prefix, fieldname);
name = smashed;
}
else if (TYPE_P (t))
{
if (TYPE_NAME (t) && IDENTIFIER_POINTER (TYPE_NAME (t)))
name = IDENTIFIER_POINTER (TYPE_NAME (t));
else
name = "<unnamed type>";
}
else
#endif
{
if (TREE_CODE (t) == FUNCTION_DECL)
name = IDENTIFIER_POINTER (DECL_NAME (t));
else if (TREE_CODE (t) == RESULT_DECL)
name = "<return value>";
else
name = get_name (t);
}
if (!name)
{
char *namep;
namep = ggc_alloc (2 + 4 + 2 + 1);
sprintf (namep, "<UV%x>", MASK_POINTER (t));
return namep;
}
return name;
}
#include "gt-tree-alias-common.h"