9cf737f89f
* bb-reorder.c, builtins.c, c-common.c, c-gimplify.c, c-incpath.c, cgraphunit.c, ddg.c, defaults.h, dwarf2out.c, expmed.c, flags.h, gcc.c, gensupport.c, gimplify.c, global.c, passes.c, reg-stack.c, target.h, toplev.c, tree-alias-ander.c, tree-alias-common.c, tree-cfg.c, tree-complex.c, tree-dfa.c, tree-eh.c, tree-mudflap.c, tree-mudflap.h, tree-outof-ssa.c, tree-phinodes.c, tree-pretty-print.c, tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-live.c, tree-ssa-live.h, tree-ssa-pre.c, tree.h, value-prof.h, varasm.c: Fix comment formatting. From-SVN: r82463
1265 lines
34 KiB
C
1265 lines
34 KiB
C
/* Tree based points-to analysis
|
|
Copyright (C) 2002, 2003 Free Software Foundation, Inc.
|
|
Contributed by Daniel Berlin <dberlin@dberlin.org>
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, 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; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#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"
|
|
/* If we have andersen's points-to analysis, include it. */
|
|
#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"
|
|
|
|
/* Reduce ifdefery later. */
|
|
#ifndef HAVE_BANSHEE
|
|
#define HAVE_BANSHEE 0
|
|
#endif
|
|
|
|
/* This file contains the implementation of the common parts of the
|
|
tree points-to analysis infrastructure.
|
|
|
|
Overview:
|
|
|
|
This file contains the points-to analysis driver. It does two main things:
|
|
1. Keeps track of the PTA data for each variable (IE the data each
|
|
specific PTA implementation wants to keep associated with a
|
|
variable).
|
|
2. Walks the function trees, calling the appropriate functions that
|
|
each PTA implementation has implemented.
|
|
|
|
In order to speed up PTA queries, the PTA specific data is stored
|
|
in the tree for *_DECL's, in DECL_PTA_ALIASVAR. This way, we only
|
|
need to use the hash table for non-DECL's. */
|
|
#define FIELD_BASED 0
|
|
|
|
/* Array of all created alias_vars.
|
|
Note that this should contain all the alias_vars we wanted
|
|
marked during GC. */
|
|
static GTY((param_is (union alias_var_def))) varray_type alias_vars = NULL;
|
|
struct tree_alias_ops *current_alias_ops;
|
|
|
|
/* Array of local (to a function) alias_vars.
|
|
Note that this should contain all the alias_vars that are
|
|
local to this function. We delete these from alias_vars before
|
|
collection. */
|
|
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);
|
|
|
|
/* Return true if a EXPR, which is a CALL_EXPR, may clobber variables. */
|
|
|
|
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)));
|
|
}
|
|
|
|
/* Return true if a EXPR, which is a CALL_EXPR, may return. */
|
|
|
|
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);
|
|
}
|
|
|
|
/* Get the alias_var for DECL.
|
|
Creates the alias_var if it does not exist already. Also
|
|
handles FUNCTION_DECL properly. */
|
|
|
|
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);
|
|
/* Assign globals to global var for purposes of intraprocedural
|
|
analysis. */
|
|
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 the global has some DECL_INITIAL, we need to process
|
|
it here. */
|
|
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;
|
|
}
|
|
|
|
/* Get the alias_var for an expression EXPR.
|
|
Note that this function expects to only be handed a RHS or LHS, not
|
|
a MODIFY_EXPR. */
|
|
|
|
static alias_var
|
|
get_alias_var (tree expr)
|
|
{
|
|
/* If it's a decl, get the alias var of the decl. We farm this off
|
|
to get_alias_var_decl so it can abort if the alias var doesn't
|
|
exist, and in case something else *knows* it has a decl, and
|
|
wants the alias var. */
|
|
|
|
if (DECL_P (expr))
|
|
return get_alias_var_decl (expr);
|
|
|
|
/* True constants have no aliases (unless modifiable strings are on,
|
|
in which case i don't think we'll end up with a STRING_CST anyway) */
|
|
if (TREE_CODE_CLASS (TREE_CODE (expr)) == 'c')
|
|
return NULL;
|
|
|
|
|
|
switch (TREE_CODE (expr))
|
|
{
|
|
case ARRAY_REF:
|
|
{
|
|
/* Find the first non-array ref, and return it's alias
|
|
variable */
|
|
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
|
|
/* Find the first non-component ref, and return its alias variable. */
|
|
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:
|
|
/* If it's a ref or cast or conversion of something, get the
|
|
alias var of the something. */
|
|
return get_alias_var (TREE_OPERAND (expr, 0));
|
|
break;
|
|
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* Perform conservative aliasing for an intraprocedural mode function
|
|
call. ARGS are the arguments that were passed to that function
|
|
call. */
|
|
|
|
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);
|
|
|
|
/* We assume assignments among the actual parameters. */
|
|
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);
|
|
/* Restricted pointers can't be aliased with other
|
|
restricted pointers. */
|
|
if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argi)))
|
|
|| !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argj))))
|
|
/* Do a bit of TBAA to avoid pointless assignments. */
|
|
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);
|
|
}
|
|
}
|
|
/* We assume that an actual parameter can point to any global. */
|
|
for (i = 0; i < l; i++)
|
|
{
|
|
alias_var argav = VARRAY_GENERIC_PTR (args, i);
|
|
/* Restricted pointers can't be aliased with other
|
|
restricted pointers. */
|
|
if (!TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (argav)))
|
|
|| !TYPE_RESTRICT (TREE_TYPE (ALIAS_VAR_DECL (av))))
|
|
{
|
|
/* Arguments can alias globals, and whatever they point to
|
|
can point to a global as well. */
|
|
current_alias_ops->simple_assign (current_alias_ops, argav, av);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Put all pointers in a constructor in an array. */
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
/* Deal with the possible return values of a call that we don't have
|
|
actual PTA info about. */
|
|
|
|
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 we take the address of a variable directly in the
|
|
argument, the return value could be the address of that
|
|
variable. */
|
|
if (TREE_CODE (arg) == ADDR_EXPR)
|
|
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
|
|
get_alias_var (arg));
|
|
/* If we pass in a pointer, we could return that pointer. */
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Find the operand of the component ref that actually is doing
|
|
something to the DECL */
|
|
static tree
|
|
find_op_of_decl (tree cref)
|
|
{
|
|
while (!DECL_P (TREE_OPERAND (cref, 0)))
|
|
{
|
|
cref = TREE_OPERAND (cref, 0);
|
|
}
|
|
return cref;
|
|
}
|
|
|
|
|
|
/* Tree walker that is the heart of the aliasing infrastructure.
|
|
TP is a pointer to the current tree.
|
|
WALK_SUBTREES specifies whether to continue traversing subtrees or
|
|
not.
|
|
Returns NULL_TREE when we should stop.
|
|
|
|
This function is the main part of the aliasing infrastructure. It
|
|
walks the trees, calling the appropriate alias analyzer functions to process
|
|
various statements. */
|
|
|
|
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 should always have an alias variable */
|
|
lhsAV = get_alias_var (op0);
|
|
if (!lhsAV)
|
|
return;
|
|
/* rhsAV might not have one, c.f. c = 5 */
|
|
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);
|
|
}
|
|
/* Take care of fact that we may have multi-level component
|
|
refs. */
|
|
if (TREE_CODE (op1) == COMPONENT_REF)
|
|
op1 = find_op_of_decl (op1);
|
|
#endif
|
|
|
|
/* You would think we could test rhsAV at the top, rather than
|
|
50 separate times, but we can't, because it can be NULL for
|
|
operator assignments, where we'd still collect the individual
|
|
alias vars for the operator. */
|
|
|
|
/* Note that structures are treated as a single alias
|
|
variable, since we can disambiguate based on TBAA first,
|
|
and fall back on points-to. */
|
|
/* x = <something> */
|
|
if (is_gimple_variable (op0))
|
|
{
|
|
/* x = y */
|
|
if (is_gimple_variable (op1))
|
|
{
|
|
if (rhsAV != NULL)
|
|
current_alias_ops->simple_assign (current_alias_ops, lhsAV,
|
|
rhsAV);
|
|
}
|
|
/* x = foo.y */
|
|
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);
|
|
}
|
|
/* x = (cast) [maybe-addr-expr] y */
|
|
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);
|
|
}
|
|
}
|
|
/* x = *y or x = foo->y */
|
|
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);
|
|
}
|
|
/* x = &y = x = &foo.y */
|
|
else if (TREE_CODE (op1) == ADDR_EXPR)
|
|
{
|
|
if (rhsAV != NULL)
|
|
current_alias_ops->addr_assign (current_alias_ops, lhsAV,
|
|
rhsAV);
|
|
}
|
|
/* x = func(...) */
|
|
else if (TREE_CODE (op1) == CALL_EXPR)
|
|
{
|
|
/* Heap assignment. These are __attribute__ malloc or
|
|
something, i'll deal with it later. */
|
|
if (0)
|
|
{}
|
|
else
|
|
{
|
|
|
|
/* NORETURN functions have no effect on aliasing. */
|
|
if (call_may_return (op1))
|
|
{
|
|
varray_type args;
|
|
tree arg;
|
|
tree callop0, callop1;
|
|
int argnum;
|
|
|
|
/* Collect the arguments */
|
|
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);
|
|
}
|
|
}
|
|
/* Simulate the call */
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* x = op (...) */
|
|
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': /* an expression */
|
|
case 's': /* an expression with side effects */
|
|
case '<': /* a comparison expression */
|
|
case '1': /* a unary arithmetic expression */
|
|
case 'r': /* a reference */
|
|
case '2': /* a binary arithmetic expression */
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
/* *x = <something> */
|
|
else
|
|
{
|
|
/* x.f = y or x->f = y */
|
|
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);
|
|
}
|
|
/* x.f = &y or x->f = &y */
|
|
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);
|
|
}
|
|
/* *x.f = y or *x->f = y */
|
|
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);
|
|
}
|
|
/* *x = &y */
|
|
else if ((TREE_CODE (op0) == INDIRECT_REF
|
|
|| TREE_CODE (op0) == ARRAY_REF)
|
|
&& TREE_CODE (op1) == ADDR_EXPR)
|
|
{
|
|
/* This becomes temp = &y and *x = temp . */
|
|
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);
|
|
}
|
|
|
|
/* *x = *y */
|
|
else if ((TREE_CODE (op0) == INDIRECT_REF
|
|
|| TREE_CODE (op0) == ARRAY_REF)
|
|
&& (TREE_CODE (op1) == INDIRECT_REF
|
|
|| TREE_CODE (op1) == ARRAY_REF))
|
|
{
|
|
/* This becomes temp = *y and *x = temp . */
|
|
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);
|
|
}
|
|
|
|
/* *x = (cast) y */
|
|
else if ((TREE_CODE (op0) == INDIRECT_REF
|
|
|| TREE_CODE (op0) == ARRAY_REF)
|
|
&& is_gimple_cast (op1))
|
|
{
|
|
if (rhsAV != NULL)
|
|
{
|
|
/* This becomes temp = (cast) y and *x = temp. */
|
|
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);
|
|
}
|
|
}
|
|
/* *x = <something else> */
|
|
else
|
|
{
|
|
if (rhsAV != NULL)
|
|
current_alias_ops->assign_ptr (current_alias_ops, lhsAV,
|
|
rhsAV);
|
|
}
|
|
}
|
|
}
|
|
/* Calls without return values. */
|
|
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)
|
|
{
|
|
|
|
/* NORETURN and CONST functions with no return value
|
|
have no effect on aliasing (as may be seen above,
|
|
const functions that return a value might have an
|
|
effect on aliasing, since the return value can point
|
|
to one of the arguments. */
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Create the alias_var for a function definition DECL, it's
|
|
arguments, and it's return value. If FORCE is true, we force
|
|
creation of the alias_var, regardless of whether one exists already.
|
|
|
|
This includes creation of alias_var's for
|
|
- The function itself.
|
|
- The arguments.
|
|
- The return value. */
|
|
|
|
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);
|
|
/* Incoming pointers can point to pta_global_var, unless
|
|
either we are interprocedural, or we can do ip on all
|
|
statics + this function has been defined + it's not an
|
|
external function. */
|
|
if (POINTER_TYPE_P (TREE_TYPE (arg))
|
|
&& !current_alias_ops->ip
|
|
/* FIXME: Need to let analyzer decide in partial case. */
|
|
&& (!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;
|
|
/* FIXME: Handle varargs */
|
|
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);
|
|
|
|
/* Incoming pointers can point to pta_global_var, unless
|
|
either we are interprocedural, or we can do ip on all
|
|
statics + this function has been defined + it's not an
|
|
external function. */
|
|
if (POINTER_TYPE_P (TREE_TYPE (fakedecl))
|
|
&& !current_alias_ops->ip
|
|
/* FIXME: need to let analyzer decide in partial case. */
|
|
&& (!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));
|
|
}
|
|
}
|
|
/* Functions declared like void f() are *not* equivalent to void
|
|
f(void). You can pass an argument to them. Thus, we need to
|
|
create some fake argument that would alias any actuals that get
|
|
passed to our function. */
|
|
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;
|
|
|
|
/* FIXME: Also, if this is a defining declaration then add the annotation
|
|
to all extern definitions of the function. */
|
|
return avar;
|
|
}
|
|
|
|
/* Create an alias variable for a pointer-to-member function DECL of
|
|
type TYPE, it's arguments, and it's return value.
|
|
Returns the alias_var for the PTF.
|
|
|
|
This includes creating alias_var's for
|
|
- The function itself.
|
|
- The arguments.
|
|
- The return value. */
|
|
|
|
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;
|
|
/* FIXME: Handle varargs */
|
|
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);
|
|
}
|
|
}
|
|
/* Functions declared like void f() are *not* equivalent to void
|
|
f(void). You can pass an argument to them. Thus, we need to
|
|
create some fake argument that would alias any actuals that get
|
|
passed to our function. */
|
|
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;
|
|
}
|
|
|
|
/* Create the alias_var for a *_DECL node DECL.
|
|
Returns the alias_var for DECL.
|
|
|
|
This function also handles creation of alias_var's for PTF
|
|
variables. */
|
|
|
|
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;
|
|
}
|
|
|
|
/* Create points-to sets for the current function. */
|
|
|
|
static void
|
|
create_alias_vars (void)
|
|
{
|
|
basic_block bb;
|
|
#if 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);
|
|
|
|
/* First, walk the variables and their DECL_INITIAL's */
|
|
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);
|
|
}
|
|
}
|
|
|
|
/* Now walk all statements and derive aliases. */
|
|
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", /* name */
|
|
NULL, /* gate */
|
|
create_alias_vars, /* execute */
|
|
NULL, /* sub */
|
|
NULL, /* next */
|
|
0, /* static_pass_number */
|
|
TV_TREE_PTA, /* tv_id */
|
|
PROP_cfg, /* properties_required */
|
|
PROP_pta, /* properties_provided */
|
|
0, /* properties_destroyed */
|
|
0, /* todo_flags_start */
|
|
0 /* todo_flags_finish */
|
|
};
|
|
|
|
|
|
/* Delete created points-to sets. */
|
|
|
|
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 (alias_vars); */
|
|
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", /* name */
|
|
NULL, /* gate */
|
|
delete_alias_vars, /* execute */
|
|
NULL, /* sub */
|
|
NULL, /* next */
|
|
0, /* static_pass_number */
|
|
TV_TREE_PTA, /* tv_id */
|
|
PROP_pta, /* properties_required */
|
|
0, /* properties_provided */
|
|
PROP_pta, /* properties_destroyed */
|
|
0, /* todo_flags_start */
|
|
0 /* todo_flags_finish */
|
|
};
|
|
|
|
|
|
/* Initialize points-to analysis machinery. */
|
|
|
|
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");
|
|
}
|
|
|
|
/* Return true if PTR can't point to anything (i.e. it has an empty
|
|
points-to set. */
|
|
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);
|
|
}
|
|
|
|
/* Return true if PTR and VAR have the same points-to set. */
|
|
|
|
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);
|
|
}
|
|
|
|
/* Determine whether two variables (PTR and VAR) may-alias.
|
|
Returns TRUE if PTR may-alias VAR. */
|
|
|
|
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)
|
|
{
|
|
/* First get the name of the field, then the prefix, then smash them
|
|
together. */
|
|
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;
|
|
/* 2 = UF
|
|
4 = the masked pointer
|
|
2 = the <> around it
|
|
1 = the terminator. */
|
|
namep = ggc_alloc (2 + 4 + 2 + 1);
|
|
sprintf (namep, "<UV%x>", MASK_POINTER (t));
|
|
return namep;
|
|
}
|
|
|
|
return name;
|
|
}
|
|
|
|
#include "gt-tree-alias-common.h"
|