X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fipa-type-escape.c;h=edfaab0a0f89668330223bf81925147e8d30b6a2;hb=fef144401409894f6457aae538e0b4c5e3a72c4c;hp=faddb7754cda47252238e2f4a66a07d63dfd3000;hpb=1d416bd7b7ab86376036f2fc7199b7e7667bd0b1;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ipa-type-escape.c b/gcc/ipa-type-escape.c index faddb7754cd..edfaab0a0f8 100644 --- a/gcc/ipa-type-escape.c +++ b/gcc/ipa-type-escape.c @@ -1,12 +1,13 @@ /* Type based alias analysis. - Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, 2007, 2008 Free Software Foundation, + Inc. Contributed by Kenneth Zadeck This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2, or (at your option) any later +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,9 +16,8 @@ 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; see the file COPYING. If not, write to the Free -Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301, USA. */ +along with GCC; see the file COPYING3. If not see +. */ /* This pass determines which types in the program contain only instances that are completely encapsulated by the compilation unit. @@ -43,11 +43,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "tree-pass.h" #include "langhooks.h" #include "pointer-set.h" +#include "splay-tree.h" #include "ggc.h" #include "ipa-utils.h" #include "ipa-type-escape.h" -#include "c-common.h" -#include "tree-gimple.h" +#include "gimple.h" #include "cgraph.h" #include "output.h" #include "flags.h" @@ -60,13 +60,6 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA this phase has been run. */ static bool initialized = false; -/* This bitmap contains the set of local vars that are the lhs of - calls to mallocs. These variables, when seen on the rhs as part of - a cast, the cast are not marked as doing bad things to the type - even though they are generally of the form - "foo = (type_of_foo)void_temp". */ -static bitmap results_of_malloc; - /* Scratch bitmap for avoiding work. */ static bitmap been_there_done_that; static bitmap bitmap_tmp; @@ -135,17 +128,26 @@ static splay_tree uid_to_subtype_map; scan_for_refs. */ static struct pointer_set_t *visited_nodes; +/* Visited stmts by walk_use_def_chains function because it's called + recursively. */ +static struct pointer_set_t *visited_stmts; + static bitmap_obstack ipa_obstack; +/* Static functions from this file that are used + before being defined. */ +static unsigned int look_for_casts (tree); +static bool is_cast_from_non_pointer (tree, gimple, void *); + /* Get the name of TYPE or return the string "". */ -static char* +static const char* get_name_of_type (tree type) { tree name = TYPE_NAME (type); if (!name) /* Unnamed type, do what you like here. */ - return (char*)""; + return ""; /* It will be a TYPE_DECL in the case of a typedef, otherwise, an identifier_node */ @@ -155,20 +157,20 @@ get_name_of_type (tree type) IDENTIFIER_NODE. (Some decls, most often labels, may have zero as the DECL_NAME). */ if (DECL_NAME (name)) - return (char*)IDENTIFIER_POINTER (DECL_NAME (name)); + return IDENTIFIER_POINTER (DECL_NAME (name)); else /* Unnamed type, do what you like here. */ - return (char*)""; + return ""; } else if (TREE_CODE (name) == IDENTIFIER_NODE) - return (char*)IDENTIFIER_POINTER (name); + return IDENTIFIER_POINTER (name); else - return (char*)""; + return ""; } struct type_brand_s { - char* name; + const char* name; int seq; }; @@ -194,8 +196,9 @@ compare_type_brand (splay_tree_key sk1, splay_tree_key sk2) /* This is a trivial algorithm for removing duplicate types. This would not work for any language that used structural equivalence as the basis of its type system. */ -/* Return either TYPE if this is first time TYPE has been seen an - compatible TYPE that has already been processed. */ +/* Return TYPE if no type compatible with TYPE has been seen so far, + otherwise return a type compatible with TYPE that has already been + processed. */ static tree discover_unique_type (tree type) @@ -216,7 +219,7 @@ discover_unique_type (tree type) /* Create an alias since this is just the same as other_type. */ tree other_type = (tree) result->value; - if (lang_hooks.types_compatible_p (type, other_type) == 1) + if (types_compatible_p (type, other_type)) { free (brand); /* Insert this new type as an alias for other_type. */ @@ -272,6 +275,7 @@ type_to_consider (tree type) case INTEGER_TYPE: case QUAL_UNION_TYPE: case REAL_TYPE: + case FIXED_POINT_TYPE: case RECORD_TYPE: case UNION_TYPE: case VECTOR_TYPE: @@ -304,7 +308,7 @@ get_canon_type (tree type, bool see_thru_ptrs, bool see_thru_arrays) while (POINTER_TYPE_P (type)) type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - result = splay_tree_lookup(type_to_canon_type, (splay_tree_key) type); + result = splay_tree_lookup (type_to_canon_type, (splay_tree_key) type); if (result == NULL) return discover_unique_type (type); @@ -622,10 +626,15 @@ count_stars (tree* type_ptr) } enum cast_type { - CT_UP, - CT_DOWN, - CT_SIDEWAYS, - CT_USELESS + CT_UP = 0x1, + CT_DOWN = 0x2, + CT_SIDEWAYS = 0x4, + CT_USELESS = 0x8, + CT_FROM_P_BAD = 0x10, + CT_FROM_NON_P = 0x20, + CT_TO_NON_INTER = 0x40, + CT_FROM_MALLOC = 0x80, + CT_NO_CAST = 0x100 }; /* Check the cast FROM_TYPE to TO_TYPE. This function requires that @@ -648,17 +657,45 @@ check_cast_type (tree to_type, tree from_type) return CT_SIDEWAYS; } +/* This function returns nonzero if VAR is result of call + to malloc function. */ + +static bool +is_malloc_result (tree var) +{ + gimple def_stmt; + + if (!var) + return false; + + if (SSA_NAME_IS_DEFAULT_DEF (var)) + return false; + + def_stmt = SSA_NAME_DEF_STMT (var); + + if (!is_gimple_call (def_stmt)) + return false; + + if (var != gimple_call_lhs (def_stmt)) + return false; + + return ((gimple_call_flags (def_stmt) & ECF_MALLOC) != 0); + +} + /* Check a cast FROM this variable, TO_TYPE. Mark the escaping types - if appropriate. */ -static void + if appropriate. Returns cast_type as detected. */ + +static enum cast_type check_cast (tree to_type, tree from) { tree from_type = get_canon_type (TREE_TYPE (from), false, false); bool to_interesting_type, from_interesting_type; + enum cast_type cast = CT_NO_CAST; to_type = get_canon_type (to_type, false, false); if (!from_type || !to_type || from_type == to_type) - return; + return cast; to_interesting_type = ipa_type_escape_star_count_of_interesting_type (to_type) >= 0; @@ -674,7 +711,8 @@ check_cast (tree to_type, tree from) both sides get marked as escaping. Downcasts are not interesting here because if type is marked as escaping, all of its subtypes escape. */ - switch (check_cast_type (to_type, from_type)) + cast = check_cast_type (to_type, from_type); + switch (cast) { case CT_UP: case CT_USELESS: @@ -685,17 +723,302 @@ check_cast (tree to_type, tree from) mark_type (to_type, FULL_ESCAPE); mark_type (from_type, FULL_ESCAPE); break; + + default: + break; } } else { - /* If this is a cast from the local that is a result from a - call to malloc, do not mark the cast as bad. */ - if (DECL_P (from) && !bitmap_bit_p (results_of_malloc, DECL_UID (from))) - mark_type (to_type, FULL_ESCAPE); + /* This code excludes two cases from marking as escaped: + + 1. if this is a cast of index of array of structures/unions + that happens before accessing array element, we should not + mark it as escaped. + 2. if this is a cast from the local that is a result from a + call to malloc, do not mark the cast as bad. + + */ + + if (POINTER_TYPE_P (to_type) && !POINTER_TYPE_P (from_type)) + cast = CT_FROM_NON_P; + else if (TREE_CODE (from) == SSA_NAME + && is_malloc_result (from)) + cast = CT_FROM_MALLOC; + else + { + cast = CT_FROM_P_BAD; + mark_type (to_type, FULL_ESCAPE); + } } else if (from_interesting_type) - mark_type (from_type, FULL_ESCAPE); + { + mark_type (from_type, FULL_ESCAPE); + cast = CT_TO_NON_INTER; + } + + return cast; +} + + +/* Scan assignment statement S to see if there are any casts within it. */ + +static unsigned int +look_for_casts_stmt (gimple s) +{ + unsigned int cast = 0; + + gcc_assert (is_gimple_assign (s)); + + if (gimple_assign_cast_p (s)) + { + tree castfromvar = gimple_assign_rhs1 (s); + cast |= check_cast (TREE_TYPE (gimple_assign_lhs (s)), castfromvar); + } + else + { + size_t i; + for (i = 0; i < gimple_num_ops (s); i++) + cast |= look_for_casts (gimple_op (s, i)); + } + + if (!cast) + cast = CT_NO_CAST; + + return cast; +} + + +typedef struct cast +{ + int type; + gimple stmt; +} cast_t; + +/* This function is a callback for walk_use_def_chains function called + from is_array_access_through_pointer_and_index. */ + +static bool +is_cast_from_non_pointer (tree var, gimple def_stmt, void *data) +{ + if (!def_stmt || !var) + return false; + + if (gimple_code (def_stmt) == GIMPLE_PHI) + return false; + + if (SSA_NAME_IS_DEFAULT_DEF (var)) + return false; + + if (is_gimple_assign (def_stmt)) + { + use_operand_p use_p; + ssa_op_iter iter; + unsigned int cast = look_for_casts_stmt (def_stmt); + + /* Check that only one cast happened, and it's of non-pointer + type. */ + if ((cast & CT_FROM_NON_P) == (CT_FROM_NON_P) + && (cast & ~(CT_FROM_NON_P)) == 0) + { + ((cast_t *)data)->stmt = def_stmt; + ((cast_t *)data)->type++; + + FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES) + { + walk_use_def_chains (USE_FROM_PTR (use_p), + is_cast_from_non_pointer, data, false); + if (((cast_t*)data)->type == -1) + break; + } + } + /* Check that there is no cast, or cast is not harmful. */ + else if ((cast & CT_NO_CAST) == (CT_NO_CAST) + || (cast & CT_DOWN) == (CT_DOWN) + || (cast & CT_UP) == (CT_UP) + || (cast & CT_USELESS) == (CT_USELESS) + || (cast & CT_FROM_MALLOC) == (CT_FROM_MALLOC)) + { + FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES) + { + walk_use_def_chains (USE_FROM_PTR (use_p), + is_cast_from_non_pointer, data, false); + if (((cast_t*)data)->type == -1) + break; + } + } + /* The cast is harmful. */ + else + ((cast_t *)data)->type = -1; + } + + if (((cast_t*)data)->type == -1) + return true; + + return false; +} + +/* When array element a_p[i] is accessed through the pointer a_p + and index i, it's translated into the following sequence + in gimple: + + i.1_5 = (unsigned int) i_1; + D.1605_6 = i.1_5 * 16; + D.1606_7 = (struct str_t *) D.1605_6; + a_p.2_8 = a_p; + D.1608_9 = D.1606_7 + a_p.2_8; + + OP0 and OP1 are of the same pointer types and stand for + D.1606_7 and a_p.2_8 or vise versa. + + This function checks that: + + 1. one of OP0 and OP1 (D.1606_7) has passed only one cast from + non-pointer type (D.1606_7 = (struct str_t *) D.1605_6;). + + 2. one of OP0 and OP1 which has passed the cast from + non-pointer type (D.1606_7), is actually generated by multiplication of + index by size of type to which both OP0 and OP1 point to + (in this case D.1605_6 = i.1_5 * 16; ). + + 3. an address of def of the var to which was made cast (D.1605_6) + was not taken.(How can it happen?) + + The following items are checked implicitly by the end of algorithm: + + 4. one of OP0 and OP1 (a_p.2_8) have never been cast + (because if it was cast to pointer type, its type, that is also + the type of OP0 and OP1, will be marked as escaped during + analysis of casting stmt (when check_cast() is called + from scan_for_refs for this stmt)). + + 5. defs of OP0 and OP1 are not passed into externally visible function + (because if they are passed then their type, that is also the type of OP0 + and OP1, will be marked and escaped during check_call function called from + scan_for_refs with call stmt). + + In total, 1-5 guaranty that it's an access to array by pointer and index. + +*/ + +bool +is_array_access_through_pointer_and_index (enum tree_code code, tree op0, + tree op1, tree *base, tree *offset, + gimple *offset_cast_stmt) +{ + tree before_cast; + gimple before_cast_def_stmt; + cast_t op0_cast, op1_cast; + + *base = NULL; + *offset = NULL; + *offset_cast_stmt = NULL; + + /* Check 1. */ + if (code == POINTER_PLUS_EXPR) + { + tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0)); + tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1)); + + /* One of op0 and op1 is of pointer type and the other is numerical. */ + if (POINTER_TYPE_P (op0type) && NUMERICAL_TYPE_CHECK (op1type)) + { + *base = op0; + *offset = op1; + } + else if (POINTER_TYPE_P (op1type) && NUMERICAL_TYPE_CHECK (op0type)) + { + *base = op1; + *offset = op0; + } + else + return false; + } + else + { + /* Init data for walk_use_def_chains function. */ + op0_cast.type = op1_cast.type = 0; + op0_cast.stmt = op1_cast.stmt = NULL; + + visited_stmts = pointer_set_create (); + walk_use_def_chains (op0, is_cast_from_non_pointer,(void *)(&op0_cast), + false); + pointer_set_destroy (visited_stmts); + + visited_stmts = pointer_set_create (); + walk_use_def_chains (op1, is_cast_from_non_pointer,(void *)(&op1_cast), + false); + pointer_set_destroy (visited_stmts); + + if (op0_cast.type == 1 && op1_cast.type == 0) + { + *base = op1; + *offset = op0; + *offset_cast_stmt = op0_cast.stmt; + } + else if (op0_cast.type == 0 && op1_cast.type == 1) + { + *base = op0; + *offset = op1; + *offset_cast_stmt = op1_cast.stmt; + } + else + return false; + } + + /* Check 2. + offset_cast_stmt is of the form: + D.1606_7 = (struct str_t *) D.1605_6; */ + + if (*offset_cast_stmt) + { + before_cast = SINGLE_SSA_TREE_OPERAND (*offset_cast_stmt, SSA_OP_USE); + if (!before_cast) + return false; + + if (SSA_NAME_IS_DEFAULT_DEF (before_cast)) + return false; + + before_cast_def_stmt = SSA_NAME_DEF_STMT (before_cast); + if (!before_cast_def_stmt) + return false; + } + else + before_cast_def_stmt = SSA_NAME_DEF_STMT (*offset); + + /* before_cast_def_stmt should be of the form: + D.1605_6 = i.1_5 * 16; */ + + if (is_gimple_assign (before_cast_def_stmt)) + { + /* We expect temporary here. */ + if (!is_gimple_reg (gimple_assign_lhs (before_cast_def_stmt))) + return false; + + if (gimple_assign_rhs_code (before_cast_def_stmt) == MULT_EXPR) + { + tree arg0 = gimple_assign_rhs1 (before_cast_def_stmt); + tree arg1 = gimple_assign_rhs2 (before_cast_def_stmt); + tree unit_size = + TYPE_SIZE_UNIT (TREE_TYPE (TYPE_MAIN_VARIANT (TREE_TYPE (op0)))); + + if (!(CONSTANT_CLASS_P (arg0) + && simple_cst_equal (arg0, unit_size)) + && !(CONSTANT_CLASS_P (arg1) + && simple_cst_equal (arg1, unit_size))) + return false; + } + else + return false; + } + else + return false; + + /* Check 3. + check that address of D.1605_6 was not taken. + FIXME: if D.1605_6 is gimple reg than it cannot be addressable. */ + + return true; } /* Register the parameter and return types of function FN. The type @@ -805,12 +1128,9 @@ check_operand (tree t) static void check_tree (tree t) { - if ((TREE_CODE (t) == EXC_PTR_EXPR) || (TREE_CODE (t) == FILTER_EXPR)) - return; - - while (TREE_CODE (t) == REALPART_EXPR - || TREE_CODE (t) == IMAGPART_EXPR - || handled_component_p (t)) + /* We want to catch here also REALPART_EXPR and IMAGEPART_EXPR, + but they already included in handled_component_p. */ + while (handled_component_p (t)) { if (TREE_CODE (t) == ARRAY_REF) check_operand (TREE_OPERAND (t, 1)); @@ -822,7 +1142,11 @@ check_tree (tree t) check_tree (TREE_OPERAND (t, 0)); if (SSA_VAR_P (t) || (TREE_CODE (t) == FUNCTION_DECL)) - check_operand (t); + { + check_operand (t); + if (DECL_P (t) && DECL_INITIAL (t)) + check_tree (DECL_INITIAL (t)); + } } /* Create an address_of edge FROM_TYPE.TO_TYPE. */ @@ -873,7 +1197,7 @@ mark_interesting_addressof (tree to_type, tree from_type) to_uid, (splay_tree_value)type_map); } - bitmap_set_bit (type_map, TYPE_UID (to_type)); + bitmap_set_bit (type_map, TYPE_UID (from_type)); } /* Scan tree T to see if there are any addresses taken in within T. */ @@ -909,37 +1233,37 @@ look_for_address_of (tree t) } -/* Scan tree T to see if there are any casts within it. - LHS Is the LHS of the expression involving the cast. */ +/* Scan tree T to see if there are any casts within it. */ -static void -look_for_casts (tree lhs __attribute__((unused)), tree t) +static unsigned int +look_for_casts (tree t) { + unsigned int cast = 0; + if (is_gimple_cast (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR) { tree castfromvar = TREE_OPERAND (t, 0); - check_cast (TREE_TYPE (t), castfromvar); + cast = cast | check_cast (TREE_TYPE (t), castfromvar); } - else if (TREE_CODE (t) == COMPONENT_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == BIT_FIELD_REF) - { - tree base = get_base_address (t); - while (t != base) - { - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == VIEW_CONVERT_EXPR) - { - /* This may be some part of a component ref. - IE it may be a.b.VIEW_CONVERT_EXPR(c).d, AFAIK. - castfromref will give you a.b.c, not a. */ - tree castfromref = TREE_OPERAND (t, 0); - check_cast (TREE_TYPE (t), castfromref); - } - else if (TREE_CODE (t) == COMPONENT_REF) - get_canon_type (TREE_TYPE (TREE_OPERAND (t, 1)), false, false); - } - } + else + while (handled_component_p (t)) + { + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == VIEW_CONVERT_EXPR) + { + /* This may be some part of a component ref. + IE it may be a.b.VIEW_CONVERT_EXPR(c).d, AFAIK. + castfromref will give you a.b.c, not a. */ + tree castfromref = TREE_OPERAND (t, 0); + cast = cast | check_cast (TREE_TYPE (t), castfromref); + } + else if (TREE_CODE (t) == COMPONENT_REF) + get_canon_type (TREE_TYPE (TREE_OPERAND (t, 1)), false, false); + } + + if (!cast) + cast = CT_NO_CAST; + return cast; } /* Check to see if T is a read or address of operation on a static var @@ -949,7 +1273,7 @@ static void check_rhs_var (tree t) { look_for_address_of (t); - check_tree(t); + check_tree (t); } /* Check to see if T is an assignment to a static var we are @@ -958,7 +1282,7 @@ check_rhs_var (tree t) static void check_lhs_var (tree t) { - check_tree(t); + check_tree (t); } /* This is a scaled down version of get_asm_expr_operands from @@ -969,35 +1293,15 @@ check_lhs_var (tree t) analyzed and STMT is the actual asm statement. */ static void -get_asm_expr_operands (tree stmt) +check_asm (gimple stmt) { - int noutputs = list_length (ASM_OUTPUTS (stmt)); - const char **oconstraints - = (const char **) alloca ((noutputs) * sizeof (const char *)); - int i; - tree link; - const char *constraint; - bool allows_mem, allows_reg, is_inout; - - for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link)) - { - oconstraints[i] = constraint - = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - parse_output_constraint (&constraint, i, 0, 0, - &allows_mem, &allows_reg, &is_inout); - - check_lhs_var (TREE_VALUE (link)); - } + size_t i; - for (link = ASM_INPUTS (stmt); link; link = TREE_CHAIN (link)) - { - constraint - = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link))); - parse_input_constraint (&constraint, 0, 0, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); - - check_rhs_var (TREE_VALUE (link)); - } + for (i = 0; i < gimple_asm_noutputs (stmt); i++) + check_lhs_var (gimple_asm_output_op (stmt, i)); + + for (i = 0; i < gimple_asm_ninputs (stmt); i++) + check_rhs_var (gimple_asm_input_op (stmt, i)); /* There is no code here to check for asm memory clobbers. The casual maintainer might think that such code would be necessary, @@ -1007,29 +1311,22 @@ get_asm_expr_operands (tree stmt) assumed to already escape. So, we are protected here. */ } -/* Check the parameters of a function call to CALL_EXPR to mark the + +/* Check the parameters of function call to CALL to mark the types that pass across the function boundary. Also check to see if this is either an indirect call, a call outside the compilation unit. */ -static bool -check_call (tree call_expr) +static void +check_call (gimple call) { - int flags = call_expr_flags(call_expr); - tree operand_list = TREE_OPERAND (call_expr, 1); - tree operand; - tree callee_t = get_callee_fndecl (call_expr); - tree argument; + tree callee_t = gimple_call_fndecl (call); struct cgraph_node* callee; enum availability avail = AVAIL_NOT_AVAILABLE; + size_t i; - for (operand = operand_list; - operand != NULL_TREE; - operand = TREE_CHAIN (operand)) - { - tree argument = TREE_VALUE (operand); - check_rhs_var (argument); - } + for (i = 0; i < gimple_call_num_args (call); i++) + check_rhs_var (gimple_call_arg (call, i)); if (callee_t) { @@ -1042,17 +1339,15 @@ check_call (tree call_expr) parameters. */ if (TYPE_ARG_TYPES (TREE_TYPE (callee_t))) { - operand = operand_list; - for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t)); + for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t)), i = 0; arg_type && TREE_VALUE (arg_type) != void_type_node; - arg_type = TREE_CHAIN (arg_type)) + arg_type = TREE_CHAIN (arg_type), i++) { + tree operand = gimple_call_arg (call, i); if (operand) { - argument = TREE_VALUE (operand); last_arg_type = TREE_VALUE(arg_type); - check_cast (last_arg_type, argument); - operand = TREE_CHAIN (operand); + check_cast (last_arg_type, operand); } else /* The code reaches here for some unfortunate @@ -1066,17 +1361,15 @@ check_call (tree call_expr) /* FIXME - According to Geoff Keating, we should never have to do this; the front ends should always process the arg list from the TYPE_ARG_LIST. */ - operand = operand_list; - for (arg_type = DECL_ARGUMENTS (callee_t); + for (arg_type = DECL_ARGUMENTS (callee_t), i = 0; arg_type; - arg_type = TREE_CHAIN (arg_type)) + arg_type = TREE_CHAIN (arg_type), i++) { + tree operand = gimple_call_arg (call, i); if (operand) { - argument = TREE_VALUE (operand); - last_arg_type = TREE_TYPE(arg_type); - check_cast (last_arg_type, argument); - operand = TREE_CHAIN (operand); + last_arg_type = TREE_TYPE (arg_type); + check_cast (last_arg_type, operand); } else /* The code reaches here for some unfortunate @@ -1089,13 +1382,11 @@ check_call (tree call_expr) /* In the case where we have a var_args function, we need to check the remaining parameters against the last argument. */ arg_type = last_arg_type; - for (; - operand != NULL_TREE; - operand = TREE_CHAIN (operand)) + for ( ; i < gimple_call_num_args (call); i++) { - argument = TREE_VALUE (operand); + tree operand = gimple_call_arg (call, i); if (arg_type) - check_cast (arg_type, argument); + check_cast (arg_type, operand); else { /* The code reaches here for some unfortunate @@ -1103,7 +1394,7 @@ check_call (tree call_expr) argument types. Most of these functions have been marked as having their parameters not escape, but for the rest, the type is doomed. */ - tree type = get_canon_type (TREE_TYPE (argument), false, false); + tree type = get_canon_type (TREE_TYPE (operand), false, false); mark_interesting_type (type, FULL_ESCAPE); } } @@ -1114,19 +1405,16 @@ check_call (tree call_expr) are any bits available for the callee (such as by declaration or because it is builtin) and process solely on the basis of those bits. */ - if (avail == AVAIL_NOT_AVAILABLE || avail == AVAIL_OVERWRITABLE) { /* If this is a direct call to an external function, mark all of the parameter and return types. */ - for (operand = operand_list; - operand != NULL_TREE; - operand = TREE_CHAIN (operand)) + for (i = 0; i < gimple_call_num_args (call); i++) { - tree type = - get_canon_type (TREE_TYPE (TREE_VALUE (operand)), false, false); + tree operand = gimple_call_arg (call, i); + tree type = get_canon_type (TREE_TYPE (operand), false, false); mark_interesting_type (type, EXPOSED_PARAMETER); - } + } if (callee_t) { @@ -1135,7 +1423,6 @@ check_call (tree call_expr) mark_interesting_type (type, EXPOSED_PARAMETER); } } - return (flags & ECF_MALLOC); } /* CODE is the operation on OP0 and OP1. OP0 is the operand that we @@ -1144,163 +1431,170 @@ static bool okay_pointer_operation (enum tree_code code, tree op0, tree op1) { tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0)); - tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1)); - if (POINTER_TYPE_P (op1type)) - return false; + switch (code) { case MULT_EXPR: - case PLUS_EXPR: + /* Multiplication does not change alignment. */ + return true; + break; case MINUS_EXPR: - /* TODO: Handle multiples of op0 size as well */ - if (operand_equal_p (size_in_bytes (op0type), op1, 0)) - return true; - /* fallthrough */ + case PLUS_EXPR: + case POINTER_PLUS_EXPR: + { + tree base, offset; + gimple offset_cast_stmt; + + if (POINTER_TYPE_P (op0type) + && TREE_CODE (op0) == SSA_NAME + && TREE_CODE (op1) == SSA_NAME + && is_array_access_through_pointer_and_index (code, op0, op1, + &base, + &offset, + &offset_cast_stmt)) + return true; + else + { + tree size_of_op0_points_to = TYPE_SIZE_UNIT (TREE_TYPE (op0type)); + + if (CONSTANT_CLASS_P (op1) + && size_of_op0_points_to + && multiple_of_p (TREE_TYPE (size_of_op0_points_to), + op1, size_of_op0_points_to)) + return true; + if (CONSTANT_CLASS_P (op0) + && size_of_op0_points_to + && multiple_of_p (TREE_TYPE (size_of_op0_points_to), + op0, size_of_op0_points_to)) + return true; + } + } + break; default: return false; } return false; } -/* TP is the part of the tree currently under the microscope. - WALK_SUBTREES is part of the walk_tree api but is unused here. - DATA is cgraph_node of the function being walked. */ -/* FIXME: When this is converted to run over SSA form, this code - should be converted to use the operand scanner. */ -static tree -scan_for_refs (tree *tp, int *walk_subtrees, void *data) +/* Helper for scan_for_refs. Check the operands of an assignment to + mark types that may escape. */ + +static void +check_assign (gimple t) { - struct cgraph_node *fn = data; - tree t = *tp; + /* First look on the lhs and see what variable is stored to */ + check_lhs_var (gimple_assign_lhs (t)); + + /* For the purposes of figuring out what the cast affects */ - switch (TREE_CODE (t)) + /* Next check the operands on the rhs to see if they are ok. */ + switch (TREE_CODE_CLASS (gimple_assign_rhs_code (t))) { - case VAR_DECL: - if (DECL_INITIAL (t)) - walk_tree (&DECL_INITIAL (t), scan_for_refs, fn, visited_nodes); - *walk_subtrees = 0; + case tcc_binary: + { + tree op0 = gimple_assign_rhs1 (t); + tree type0 = get_canon_type (TREE_TYPE (op0), false, false); + tree op1 = gimple_assign_rhs2 (t); + tree type1 = get_canon_type (TREE_TYPE (op1), false, false); + + /* If this is pointer arithmetic of any bad sort, then + we need to mark the types as bad. For binary + operations, no binary operator we currently support + is always "safe" in regard to what it would do to + pointers for purposes of determining which types + escape, except operations of the size of the type. + It is possible that min and max under the right set + of circumstances and if the moon is in the correct + place could be safe, but it is hard to see how this + is worth the effort. */ + if (type0 && POINTER_TYPE_P (type0) + && !okay_pointer_operation (gimple_assign_rhs_code (t), op0, op1)) + mark_interesting_type (type0, FULL_ESCAPE); + + if (type1 && POINTER_TYPE_P (type1) + && !okay_pointer_operation (gimple_assign_rhs_code (t), op1, op0)) + mark_interesting_type (type1, FULL_ESCAPE); + + look_for_casts (op0); + look_for_casts (op1); + check_rhs_var (op0); + check_rhs_var (op1); + } break; - case GIMPLE_MODIFY_STMT: + case tcc_unary: { - /* First look on the lhs and see what variable is stored to */ - tree lhs = GIMPLE_STMT_OPERAND (t, 0); - tree rhs = GIMPLE_STMT_OPERAND (t, 1); + tree op0 = gimple_assign_rhs1 (t); + tree type0 = get_canon_type (TREE_TYPE (op0), false, false); + + /* For unary operations, if the operation is NEGATE or ABS on + a pointer, this is also considered pointer arithmetic and + thus, bad for business. */ + if (type0 + && POINTER_TYPE_P (type0) + && (TREE_CODE (op0) == NEGATE_EXPR + || TREE_CODE (op0) == ABS_EXPR)) + mark_interesting_type (type0, FULL_ESCAPE); + + check_rhs_var (op0); + look_for_casts (op0); + } + break; - check_lhs_var (lhs); - check_cast (TREE_TYPE (lhs), rhs); + case tcc_reference: + look_for_casts (gimple_assign_rhs1 (t)); + check_rhs_var (gimple_assign_rhs1 (t)); + break; - /* For the purposes of figuring out what the cast affects */ + case tcc_declaration: + check_rhs_var (gimple_assign_rhs1 (t)); + break; - /* Next check the operands on the rhs to see if they are ok. */ - switch (TREE_CODE_CLASS (TREE_CODE (rhs))) - { - case tcc_binary: - { - tree op0 = TREE_OPERAND (rhs, 0); - tree type0 = get_canon_type (TREE_TYPE (op0), false, false); - tree op1 = TREE_OPERAND (rhs, 1); - tree type1 = get_canon_type (TREE_TYPE (op1), false, false); - - /* If this is pointer arithmetic of any bad sort, then - we need to mark the types as bad. For binary - operations, no binary operator we currently support - is always "safe" in regard to what it would do to - pointers for purposes of determining which types - escape, except operations of the size of the type. - It is possible that min and max under the right set - of circumstances and if the moon is in the correct - place could be safe, but it is hard to see how this - is worth the effort. */ - - if (type0 && POINTER_TYPE_P (type0) - && !okay_pointer_operation (TREE_CODE (rhs), op0, op1)) - mark_interesting_type (type0, FULL_ESCAPE); - if (type1 && POINTER_TYPE_P (type1) - && !okay_pointer_operation (TREE_CODE (rhs), op1, op0)) - mark_interesting_type (type1, FULL_ESCAPE); - - look_for_casts (lhs, op0); - look_for_casts (lhs, op1); - check_rhs_var (op0); - check_rhs_var (op1); - } - break; - case tcc_unary: - { - tree op0 = TREE_OPERAND (rhs, 0); - tree type0 = get_canon_type (TREE_TYPE (op0), false, false); - /* For unary operations, if the operation is NEGATE or - ABS on a pointer, this is also considered pointer - arithmetic and thus, bad for business. */ - if (type0 && (TREE_CODE (op0) == NEGATE_EXPR - || TREE_CODE (op0) == ABS_EXPR) - && POINTER_TYPE_P (type0)) - { - mark_interesting_type (type0, FULL_ESCAPE); - } - check_rhs_var (op0); - look_for_casts (lhs, op0); - look_for_casts (lhs, rhs); - } + case tcc_expression: + if (gimple_assign_rhs_code (t) == ADDR_EXPR) + { + tree rhs = gimple_assign_rhs1 (t); + look_for_casts (TREE_OPERAND (rhs, 0)); + check_rhs_var (rhs); + } + break; - break; - case tcc_reference: - look_for_casts (lhs, rhs); - check_rhs_var (rhs); - break; - case tcc_declaration: - check_rhs_var (rhs); - break; - case tcc_expression: - switch (TREE_CODE (rhs)) - { - case ADDR_EXPR: - look_for_casts (lhs, TREE_OPERAND (rhs, 0)); - check_rhs_var (rhs); - break; - case CALL_EXPR: - /* If this is a call to malloc, squirrel away the - result so we do mark the resulting cast as being - bad. */ - if (check_call (rhs)) - bitmap_set_bit (results_of_malloc, DECL_UID (lhs)); - break; - default: - break; - } - break; - default: - break; - } - *walk_subtrees = 0; - } + default: break; + } +} + - case ADDR_EXPR: - /* This case is here to find addresses on rhs of constructors in - decl_initial of static variables. */ - check_rhs_var (t); - *walk_subtrees = 0; +/* Scan statement T for references to types and mark anything + interesting. */ + +static void +scan_for_refs (gimple t) +{ + switch (gimple_code (t)) + { + case GIMPLE_ASSIGN: + check_assign (t); break; - case CALL_EXPR: + case GIMPLE_CALL: + /* If this is a call to malloc, squirrel away the result so we + do mark the resulting cast as being bad. */ check_call (t); - *walk_subtrees = 0; break; - case ASM_EXPR: - get_asm_expr_operands (t); - *walk_subtrees = 0; + case GIMPLE_ASM: + check_asm (t); break; default: break; } - return NULL; + + return; } @@ -1313,7 +1607,6 @@ ipa_init (void) global_types_exposed_parameter = BITMAP_ALLOC (&ipa_obstack); global_types_full_escape = BITMAP_ALLOC (&ipa_obstack); global_types_seen = BITMAP_ALLOC (&ipa_obstack); - results_of_malloc = BITMAP_ALLOC (&ipa_obstack); uid_to_canon_type = splay_tree_new (splay_tree_compare_ints, 0, 0); all_canon_types = splay_tree_new (compare_type_brand, 0, 0); @@ -1332,7 +1625,7 @@ ipa_init (void) /* Check out the rhs of a static or global initialization VNODE to see if any of them contain addressof operations. Note that some of - these variables may not even be referenced in the code in this + these variables may not even be referenced in the code in this compilation unit but their right hand sides may contain references to variables defined within this unit. */ @@ -1351,7 +1644,7 @@ analyze_variable (struct varpool_node *vnode) gcc_assert (TREE_CODE (global) == VAR_DECL); if (DECL_INITIAL (global)) - walk_tree (&DECL_INITIAL (global), scan_for_refs, NULL, visited_nodes); + check_tree (DECL_INITIAL (global)); } /* This is the main routine for finding the reference patterns for @@ -1372,10 +1665,9 @@ analyze_function (struct cgraph_node *fn) FOR_EACH_BB_FN (this_block, this_cfun) { - block_stmt_iterator bsi; - for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi)) - walk_tree (bsi_stmt_ptr (bsi), scan_for_refs, - fn, visited_nodes); + gimple_stmt_iterator gsi; + for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) + scan_for_refs (gsi_stmt (gsi)); } } @@ -1383,7 +1675,7 @@ analyze_function (struct cgraph_node *fn) if (DECL_STRUCT_FUNCTION (decl)) { tree step; - for (step = DECL_STRUCT_FUNCTION (decl)->unexpanded_var_list; + for (step = DECL_STRUCT_FUNCTION (decl)->local_decls; step; step = TREE_CHAIN (step)) { @@ -1391,8 +1683,7 @@ analyze_function (struct cgraph_node *fn) if (TREE_CODE (var) == VAR_DECL && DECL_INITIAL (var) && !TREE_STATIC (var)) - walk_tree (&DECL_INITIAL (var), scan_for_refs, - fn, visited_nodes); + check_tree (DECL_INITIAL (var)); get_canon_type (TREE_TYPE (var), false, false); } } @@ -1412,7 +1703,7 @@ type_for_uid (int uid) else return NULL; } -/* Return the a bitmap with the subtypes of the type for UID. If it +/* Return a bitmap with the subtypes of the type for UID. If it does not exist, return either NULL or a new bitmap depending on the value of CREATE. */ @@ -1682,10 +1973,10 @@ type_escape_execute (void) ipa_init (); /* Process all of the variables first. */ - for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) + FOR_EACH_STATIC_VARIABLE (vnode) analyze_variable (vnode); - /* Process all of the functions. next + /* Process all of the functions next. We do not want to process any of the clones so we check that this is a master clone. However, we do need to process any @@ -1693,9 +1984,7 @@ type_escape_execute (void) they may cause a type variable to escape. */ for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed - && (cgraph_is_master_clone (node) - || (cgraph_function_body_availability (node) == AVAIL_OVERWRITABLE))) + if (node->analyzed) analyze_function (node); @@ -1816,20 +2105,21 @@ type_escape_execute (void) BITMAP_FREE (global_types_exposed_parameter); BITMAP_FREE (been_there_done_that); BITMAP_FREE (bitmap_tmp); - BITMAP_FREE (results_of_malloc); return 0; } static bool gate_type_escape_vars (void) { - return (flag_unit_at_a_time != 0 && flag_ipa_type_escape + return (flag_ipa_type_escape /* Don't bother doing anything if the program has errors. */ && !(errorcount || sorrycount)); } -struct tree_opt_pass pass_ipa_type_escape = +struct simple_ipa_opt_pass pass_ipa_type_escape = { + { + SIMPLE_IPA_PASS, "type-escape-var", /* name */ gate_type_escape_vars, /* gate */ type_escape_execute, /* execute */ @@ -1841,7 +2131,6 @@ struct tree_opt_pass pass_ipa_type_escape = 0, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - 0, /* todo_flags_finish */ - 0 /* letter */ + 0 /* todo_flags_finish */ + } }; -