diff options
Diffstat (limited to 'gcc/tree-alias-common.c')
-rw-r--r-- | gcc/tree-alias-common.c | 1251 |
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" |