summaryrefslogtreecommitdiff
path: root/gcc/tree-alias-common.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-alias-common.c')
-rw-r--r--gcc/tree-alias-common.c1251
1 files changed, 0 insertions, 1251 deletions
diff --git a/gcc/tree-alias-common.c b/gcc/tree-alias-common.c
deleted file mode 100644
index 21b8b497039..00000000000
--- a/gcc/tree-alias-common.c
+++ /dev/null
@@ -1,1251 +0,0 @@
-/* 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;
- gcc_assert (TREE_CODE (decl) != FIELD_DECL);
- 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 (TREE_STATIC (decl) && 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:
- case ARRAY_RANGE_REF:
- {
- /* Find the first non-array ref, and return its alias variable. */
- tree p;
-
- for (p = expr;
- TREE_CODE (p) == ARRAY_REF || TREE_CODE (p) == ARRAY_RANGE_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:
- gcc_unreachable ();
- }
-}
-
-/* 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);
- if (TREE_CODE (op1) == WITH_SIZE_EXPR)
- op1 = TREE_OPERAND (op1, 0);
- }
-
- /* 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;
-
- gcc_assert (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
- && TREE_STATIC (var)
- && 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;
-}
-
-static bool
-gate_pta (void)
-{
-#ifdef HAVE_BANSHEE
- return flag_tree_points_to != PTA_NONE;
-#else
- return false;
-#endif
-}
-
-struct tree_opt_pass pass_build_pta =
-{
- "pta", /* name */
- gate_pta, /* 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 */
- 0 /* letter */
-};
-
-
-/* Delete created points-to sets. */
-
-static void
-delete_alias_vars (void)
-{
- size_t i;
-
- for (i = 0; i < VARRAY_ACTIVE_SIZE (local_alias_vars); i++)
- {
- tree key = VARRAY_TREE (local_alias_vars, i);
- gcc_assert (DECL_P (key));
- DECL_PTA_ALIASVAR (key) = NULL;
- }
-
- 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 */
- gate_pta, /* 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 */
- 0 /* letter */
-};
-
-
-/* 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
-
- gcc_assert (DECL_P (ptr));
- ptrtv = DECL_PTA_ALIASVAR (ptr);
- if (!ptrtv)
- return true;
-
- 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;
-
- gcc_assert (DECL_P (ptr));
- ptrtv = DECL_PTA_ALIASVAR (ptr);
- if (!ptrtv)
- return false;
-
- gcc_assert (DECL_P (var));
- vartv = DECL_PTA_ALIASVAR (var);
- if (!vartv)
- return false;
-
- 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;
-
- gcc_assert (DECL_P (ptr));
- ptrtv = DECL_PTA_ALIASVAR (ptr);
- if (!ptrtv)
- return false;
-
- gcc_assert (DECL_P (var));
- vartv = DECL_PTA_ALIASVAR (var);
- if (!vartv)
- return false;
-
- 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"