X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fipa-type-escape.c;h=7349f6b8478bfbbfb0575781aa1c24a25cbf7f9a;hb=8d40ea4504ee85e1a6b73103edb1776141d5d22e;hp=a2d459ab6902f8a1a2c0fa36f869cb23fb7f6d65;hpb=cda6870fc00cbd490d382b7acb34713138411281;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/ipa-type-escape.c b/gcc/ipa-type-escape.c index a2d459ab690..7349f6b8478 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. @@ -47,7 +47,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #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" @@ -136,18 +136,18 @@ static bitmap_obstack ipa_obstack; /* Static functions from this file that are used before being defined. */ -static unsigned int look_for_casts (tree lhs ATTRIBUTE_UNUSED, tree); -static bool is_cast_from_non_pointer (tree, tree, void *); +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 */ @@ -157,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; }; @@ -219,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. */ @@ -275,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: @@ -307,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); @@ -662,9 +663,7 @@ check_cast_type (tree to_type, tree from_type) static bool is_malloc_result (tree var) { - tree def_stmt; - tree rhs; - int flags; + gimple def_stmt; if (!var) return false; @@ -674,20 +673,13 @@ is_malloc_result (tree var) def_stmt = SSA_NAME_DEF_STMT (var); - if (TREE_CODE (def_stmt) != GIMPLE_MODIFY_STMT) + if (!is_gimple_call (def_stmt)) return false; - if (var != GIMPLE_STMT_OPERAND (def_stmt, 0)) + if (var != gimple_call_lhs (def_stmt)) return false; - rhs = get_call_expr_in (def_stmt); - - if (!rhs) - return false; - - flags = call_expr_flags (rhs); - - return ((flags & ECF_MALLOC) != 0); + return ((gimple_call_flags (def_stmt) & ECF_MALLOC) != 0); } @@ -768,115 +760,98 @@ check_cast (tree to_type, tree from) return cast; } -typedef struct cast -{ - int type; - tree stmt; -}cast_t; - -/* This function is a callback for walk_tree called from - is_cast_from_non_pointer. The data->type is set to be: - - 0 - if there is no cast - number - the number of casts from non-pointer type - -1 - if there is a cast that makes the type to escape - If data->type = number, then data->stmt will contain the - last casting stmt met in traversing. */ +/* Scan assignment statement S to see if there are any casts within it. */ -static tree -is_cast_from_non_pointer_1 (tree *tp, int *walk_subtrees, void *data) +static unsigned int +look_for_casts_stmt (gimple s) { - tree def_stmt = *tp; + unsigned int cast = 0; + gcc_assert (is_gimple_assign (s)); - if (pointer_set_insert (visited_stmts, def_stmt)) + if (gimple_assign_cast_p (s)) { - *walk_subtrees = 0; - return NULL; + tree castfromvar = gimple_assign_rhs1 (s); + cast |= check_cast (TREE_TYPE (gimple_assign_lhs (s)), castfromvar); } - - switch (TREE_CODE (def_stmt)) + else { - case GIMPLE_MODIFY_STMT: - { - use_operand_p use_p; - ssa_op_iter iter; - tree lhs = GIMPLE_STMT_OPERAND (def_stmt, 0); - tree rhs = GIMPLE_STMT_OPERAND (def_stmt, 1); - - unsigned int cast = look_for_casts (lhs, rhs); - /* 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) - return def_stmt; - } - } - - /* 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) - return def_stmt; - } - } + size_t i; + for (i = 0; i < gimple_num_ops (s); i++) + cast |= look_for_casts (gimple_op (s, i)); + } - /* The cast is harmful. */ - else - { - ((cast_t *)data)->type = -1; - return def_stmt; - } + if (!cast) + cast = CT_NO_CAST; - *walk_subtrees = 0; - } - break; + return cast; +} - default: - { - *walk_subtrees = 0; - break; - } - } - return NULL; -} +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, tree def_stmt, void *data) +is_cast_from_non_pointer (tree var, gimple def_stmt, void *data) { - if (!def_stmt || !var) return false; - if (TREE_CODE (def_stmt) == PHI_NODE) + if (gimple_code (def_stmt) == GIMPLE_PHI) return false; if (SSA_NAME_IS_DEFAULT_DEF (var)) return false; - walk_tree (&def_stmt, is_cast_from_non_pointer_1, data, NULL); + 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; @@ -926,80 +901,111 @@ is_cast_from_non_pointer (tree var, tree def_stmt, void *data) */ -static bool -is_array_access_through_pointer_and_index (tree op0, tree op1) +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 base, offset, offset_cast_stmt; - tree before_cast, before_cast_def_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)); - /* Init data for walk_use_def_chains function. */ - op0_cast.type = op1_cast.type = 0; - op0_cast.stmt = op1_cast.stmt = NULL; + /* 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 (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); + 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; + 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; } - else - return false; - + /* Check 2. offset_cast_stmt is of the form: D.1606_7 = (struct str_t *) D.1605_6; */ - before_cast = SINGLE_SSA_TREE_OPERAND (offset_cast_stmt, SSA_OP_USE); - if (!before_cast) - return false; + 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; + 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; + 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 (TREE_CODE (before_cast_def_stmt) == GIMPLE_MODIFY_STMT) + if (is_gimple_assign (before_cast_def_stmt)) { - tree lhs = GIMPLE_STMT_OPERAND (before_cast_def_stmt,0); - tree rhs = GIMPLE_STMT_OPERAND (before_cast_def_stmt,1); - /* We expect temporary here. */ - if (!is_gimple_reg (lhs)) + if (!is_gimple_reg (gimple_assign_lhs (before_cast_def_stmt))) return false; - if (TREE_CODE (rhs) == MULT_EXPR) + if (gimple_assign_rhs_code (before_cast_def_stmt) == MULT_EXPR) { - tree arg0 = TREE_OPERAND (rhs, 0); - tree arg1 = TREE_OPERAND (rhs, 1); + 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)) + && simple_cst_equal (arg0, unit_size)) && !(CONSTANT_CLASS_P (arg1) - && simple_cst_equal (arg1,unit_size))) + && simple_cst_equal (arg1, unit_size))) return false; } else @@ -1139,7 +1145,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. */ @@ -1226,15 +1236,13 @@ 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 unsigned int -look_for_casts (tree lhs ATTRIBUTE_UNUSED, tree t) +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); @@ -1268,7 +1276,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 @@ -1277,7 +1285,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 @@ -1288,35 +1296,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, @@ -1326,22 +1314,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 void -check_call (tree call_expr) +check_call (gimple call) { - tree operand; - tree callee_t = get_callee_fndecl (call_expr); + tree callee_t = gimple_call_fndecl (call); struct cgraph_node* callee; enum availability avail = AVAIL_NOT_AVAILABLE; - call_expr_arg_iterator iter; + size_t i; - FOR_EACH_CALL_EXPR_ARG (operand, iter, call_expr) - check_rhs_var (operand); + for (i = 0; i < gimple_call_num_args (call); i++) + check_rhs_var (gimple_call_arg (call, i)); if (callee_t) { @@ -1354,12 +1342,11 @@ check_call (tree call_expr) parameters. */ if (TYPE_ARG_TYPES (TREE_TYPE (callee_t))) { - for (arg_type = TYPE_ARG_TYPES (TREE_TYPE (callee_t)), - operand = first_call_expr_arg (call_expr, &iter); + 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), - operand = next_call_expr_arg (&iter)) + arg_type = TREE_CHAIN (arg_type), i++) { + tree operand = gimple_call_arg (call, i); if (operand) { last_arg_type = TREE_VALUE(arg_type); @@ -1377,15 +1364,14 @@ 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. */ - for (arg_type = DECL_ARGUMENTS (callee_t), - operand = first_call_expr_arg (call_expr, &iter); + for (arg_type = DECL_ARGUMENTS (callee_t), i = 0; arg_type; - arg_type = TREE_CHAIN (arg_type), - operand = next_call_expr_arg (&iter)) + arg_type = TREE_CHAIN (arg_type), i++) { + tree operand = gimple_call_arg (call, i); if (operand) { - last_arg_type = TREE_TYPE(arg_type); + last_arg_type = TREE_TYPE (arg_type); check_cast (last_arg_type, operand); } else @@ -1399,10 +1385,9 @@ 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 = next_call_expr_arg (&iter)) + for ( ; i < gimple_call_num_args (call); i++) { + tree operand = gimple_call_arg (call, i); if (arg_type) check_cast (arg_type, operand); else @@ -1423,16 +1408,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_EACH_CALL_EXPR_ARG (operand, iter, call_expr) + for (i = 0; i < gimple_call_num_args (call); i++) { + 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) { @@ -1449,7 +1434,6 @@ 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)); switch (code) { @@ -1459,11 +1443,18 @@ okay_pointer_operation (enum tree_code code, tree op0, tree op1) break; case MINUS_EXPR: case PLUS_EXPR: + case POINTER_PLUS_EXPR: { - if (POINTER_TYPE_P (op1type) + 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 (op0, op1)) + && is_array_access_through_pointer_and_index (code, op0, op1, + &base, + &offset, + &offset_cast_stmt)) return true; else { @@ -1489,150 +1480,124 @@ okay_pointer_operation (enum tree_code code, tree op0, tree op1) 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 = (struct cgraph_node *) data; - tree t = *tp; + /* First look on the lhs and see what variable is stored to */ + check_lhs_var (gimple_assign_lhs (t)); - switch (TREE_CODE (t)) + /* For the purposes of figuring out what the cast affects */ + + /* 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; - default: - break; - } - break; - case tcc_vl_exp: - switch (TREE_CODE (rhs)) - { - case CALL_EXPR: - /* If this is a call to malloc, squirrel away the - result so we do mark the resulting cast as being - bad. */ - check_call (rhs); - 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; } @@ -1682,7 +1647,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 @@ -1703,10 +1668,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)); } } @@ -1714,7 +1678,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)) { @@ -1722,8 +1686,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); } } @@ -1743,7 +1706,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. */ @@ -2016,7 +1979,7 @@ type_escape_execute (void) 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 @@ -2024,9 +1987,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); @@ -2153,13 +2114,15 @@ type_escape_execute (void) 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 */ @@ -2171,7 +2134,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 */ + } }; -