From b8beb4d13e5c51a50507cb2be345773fa162fce7 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Wed, 23 Mar 2011 14:49:20 +0000 Subject: Makefile.in (IPA_TYPE_ESCAPE_H): Remove. 2011-03-23 Richard Guenther * Makefile.in (IPA_TYPE_ESCAPE_H): Remove. (OBJS-archive): Remove ipa-struct-reorg.o and ipa-type-escape.o. (tree-ssa-alias.o): Do not depend on IPA_TYPE_ESCAPE_H. (alias.o): Likewise. (ipa-type-escape.o): Remove. (ipa-struct-reorg.o): Likewise. (GTFILES): Remove ipa-struct-reorg.c. * alias.c: Do not include ipa-type-escape.h. * tree-ssa-alias.c: Likewise. * common.opt (fipa-struct-reorg): Preserve for backward compatibility. * opts.c (finish_options): Do not reset flag_ipa_struct_reorg. * passes.c (init_optimization_passes): Remove ipa-struct-reorg and ipa-type-escape passes. * tree-pass.h (pass_ipa_type_escape): Remove. (pass_ipa_struct_reorg): Likewise. * ipa-struct-reorg.h: Remove. * ipa-struct-reorg.c: Likewise. * ipa-type-escape.h: Likewise. * ipa-type-escape.c: Likewise. * doc/invoke.texi (-fipa-struct-reorg): Remove. (--param struct-reorg-cold-struct-ratio): Likewise. * params.def (PARAM_STRUCT_REORG_COLD_STRUCT_RATIO): Likewise. * params.h (STRUCT_REORG_COLD_STRUCT_RATIO): Likewise. * timevar.def (TV_IPA_TYPE_ESCAPE): Likewise. * gcc.dg/struct: Remove directory and contents. From-SVN: r171352 --- gcc/ChangeLog | 27 + gcc/Makefile.in | 22 +- gcc/alias.c | 1 - gcc/common.opt | 5 +- gcc/doc/invoke.texi | 24 +- gcc/ipa-struct-reorg.c | 4064 -------------------- gcc/ipa-struct-reorg.h | 112 - gcc/ipa-type-escape.c | 2126 ---------- gcc/ipa-type-escape.h | 34 - gcc/opts.c | 1 - gcc/params.def | 10 - gcc/params.h | 2 - gcc/passes.c | 2 - gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 75 - gcc/testsuite/gcc.dg/struct/w_prof_global_array.c | 30 - gcc/testsuite/gcc.dg/struct/w_prof_global_var.c | 43 - gcc/testsuite/gcc.dg/struct/w_prof_local_array.c | 38 - gcc/testsuite/gcc.dg/struct/w_prof_local_var.c | 41 - .../gcc.dg/struct/w_prof_single_str_global.c | 33 - gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c | 66 - gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c | 43 - gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c | 27 - .../gcc.dg/struct/wo_prof_array_through_pointer.c | 39 - .../gcc.dg/struct/wo_prof_double_malloc.c | 30 - gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c | 45 - .../gcc.dg/struct/wo_prof_escape_arg_to_local.c | 44 - .../gcc.dg/struct/wo_prof_escape_return.c | 31 - .../gcc.dg/struct/wo_prof_escape_str_init.c | 33 - .../gcc.dg/struct/wo_prof_escape_substr_array.c | 34 - .../gcc.dg/struct/wo_prof_escape_substr_pointer.c | 49 - .../gcc.dg/struct/wo_prof_escape_substr_value.c | 46 - gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c | 33 - gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c | 46 - gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c | 41 - gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c | 44 - .../gcc.dg/struct/wo_prof_malloc_size_var.c | 48 - .../gcc.dg/struct/wo_prof_mult_field_peeling.c | 43 - .../gcc.dg/struct/wo_prof_single_str_global.c | 35 - .../gcc.dg/struct/wo_prof_single_str_local.c | 35 - .../gcc.dg/struct/wo_prof_single_str_pointer.c | 40 - gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c | 68 - gcc/timevar.def | 1 - gcc/tree-pass.h | 2 - gcc/tree-ssa-alias.c | 1 - 45 files changed, 37 insertions(+), 7581 deletions(-) delete mode 100644 gcc/ipa-struct-reorg.c delete mode 100644 gcc/ipa-struct-reorg.h delete mode 100644 gcc/ipa-type-escape.c delete mode 100644 gcc/ipa-type-escape.h delete mode 100644 gcc/testsuite/gcc.dg/struct/struct-reorg.exp delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_global_array.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_global_var.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_local_array.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_local_var.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_prof_two_strs.c delete mode 100644 gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_local.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_single_str_pointer.c delete mode 100644 gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index de14356..1748d61 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2011-03-23 Richard Guenther + + * Makefile.in (IPA_TYPE_ESCAPE_H): Remove. + (OBJS-archive): Remove ipa-struct-reorg.o and ipa-type-escape.o. + (tree-ssa-alias.o): Do not depend on IPA_TYPE_ESCAPE_H. + (alias.o): Likewise. + (ipa-type-escape.o): Remove. + (ipa-struct-reorg.o): Likewise. + (GTFILES): Remove ipa-struct-reorg.c. + * alias.c: Do not include ipa-type-escape.h. + * tree-ssa-alias.c: Likewise. + * common.opt (fipa-struct-reorg): Preserve for backward compatibility. + * opts.c (finish_options): Do not reset flag_ipa_struct_reorg. + * passes.c (init_optimization_passes): Remove ipa-struct-reorg + and ipa-type-escape passes. + * tree-pass.h (pass_ipa_type_escape): Remove. + (pass_ipa_struct_reorg): Likewise. + * ipa-struct-reorg.h: Remove. + * ipa-struct-reorg.c: Likewise. + * ipa-type-escape.h: Likewise. + * ipa-type-escape.c: Likewise. + * doc/invoke.texi (-fipa-struct-reorg): Remove. + (--param struct-reorg-cold-struct-ratio): Likewise. + * params.def (PARAM_STRUCT_REORG_COLD_STRUCT_RATIO): Likewise. + * params.h (STRUCT_REORG_COLD_STRUCT_RATIO): Likewise. + * timevar.def (TV_IPA_TYPE_ESCAPE): Likewise. + 2011-03-23 Andreas Krebbel * config/s390/2084.md: Enable all insn reservations also for z9_ec diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 173c3ee..fc09482 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -921,7 +921,6 @@ CFGLOOP_H = cfgloop.h $(BASIC_BLOCK_H) $(RTL_H) vecprim.h double-int.h \ $(BITMAP_H) sbitmap.h IPA_UTILS_H = ipa-utils.h $(TREE_H) $(CGRAPH_H) IPA_REFERENCE_H = ipa-reference.h $(BITMAP_H) $(TREE_H) -IPA_TYPE_ESCAPE_H = ipa-type-escape.h $(TREE_H) CGRAPH_H = cgraph.h $(VEC_H) $(TREE_H) $(BASIC_BLOCK_H) $(FUNCTION_H) \ cif-code.def ipa-ref.h ipa-ref-inline.h $(LINKER_PLUGIN_API_H) DF_H = df.h $(BITMAP_H) $(REGSET_H) sbitmap.h $(BASIC_BLOCK_H) \ @@ -1467,8 +1466,6 @@ OBJS-archive = \ ipa-pure-const.o \ ipa-reference.o \ ipa-ref.o \ - ipa-struct-reorg.o \ - ipa-type-escape.o \ ipa-utils.o \ ipa.o \ matrix-reorg.o \ @@ -2612,7 +2609,7 @@ tree-ssa-alias.o : tree-ssa-alias.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(FUNCTION_H) $(TIMEVAR_H) convert.h $(TM_H) coretypes.h langhooks.h \ $(TREE_DUMP_H) $(TREE_PASS_H) $(PARAMS_H) $(BASIC_BLOCK_H) $(DIAGNOSTIC_H) \ $(GIMPLE_H) $(VEC_H) $(TARGET_H) \ - $(IPA_TYPE_ESCAPE_H) vecprim.h pointer-set.h alloc-pool.h \ + vecprim.h pointer-set.h alloc-pool.h \ tree-pretty-print.h tree-ssa-reassoc.o : tree-ssa-reassoc.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ @@ -3034,19 +3031,6 @@ ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \ $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \ $(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H) \ gimple-pretty-print.h -ipa-type-escape.o : ipa-type-escape.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ - pointer-set.h $(GGC_H) $(IPA_TYPE_ESCAPE_H) $(IPA_UTILS_H) $(SPLAY_TREE_H) \ - $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) \ - $(TIMEVAR_H) $(DIAGNOSTIC_H) $(FUNCTION_H) tree-pretty-print.h -ipa-struct-reorg.o: ipa-struct-reorg.c ipa-struct-reorg.h $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(GGC_H) $(TREE_H) $(RTL_H) $(GIMPLE_H) tree-inline.h \ - $(TREE_FLOW_H) langhooks.h pointer-set.h $(HASHTAB_H) $(DIAGNOSTIC_CORE_H) \ - $(FLAGS_H) debug.h $(TARGET_H) $(CGRAPH_H) $(DIAGNOSTIC_H) $(TIMEVAR_H) \ - $(PARAMS_H) $(FIBHEAP_H) intl.h $(FUNCTION_H) $(BASIC_BLOCK_H) tree-iterator.h \ - $(TREE_PASS_H) $(OPTS_H) $(IPA_TYPE_ESCAPE_H) $(TREE_DUMP_H) \ - $(GIMPLE_H) tree-pretty-print.h gimple-pretty-print.h - coverage.o : coverage.c $(GCOV_IO_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) \ $(FUNCTION_H) $(BASIC_BLOCK_H) toplev.h $(DIAGNOSTIC_CORE_H) $(GGC_H) langhooks.h $(COVERAGE_H) \ @@ -3303,7 +3287,7 @@ alias.o : alias.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) $(REGS_H) $(DIAGNOSTIC_CORE_H) output.h \ $(ALIAS_H) $(EMIT_RTL_H) $(GGC_H) $(FUNCTION_H) cselib.h $(TREE_H) $(TM_P_H) \ langhooks.h $(TARGET_H) gt-alias.h $(TIMEVAR_H) $(CGRAPH_H) \ - $(SPLAY_TREE_H) $(IPA_TYPE_ESCAPE_H) $(DF_H) $(TREE_PASS_H) \ + $(SPLAY_TREE_H) $(DF_H) $(TREE_PASS_H) \ tree-ssa-alias.h pointer-set.h $(TREE_FLOW_H) stack-ptr-mod.o : stack-ptr-mod.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(TREE_H) $(RTL_H) $(REGS_H) $(EXPR_H) $(TREE_PASS_H) \ @@ -3715,7 +3699,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/reload.h $(srcdir)/caller-save.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-inline.c $(srcdir)/matrix-reorg.c \ - $(srcdir)/dbxout.c $(srcdir)/ipa-struct-reorg.c $(srcdir)/dwarf2out.c $(srcdir)/dwarf2asm.c \ + $(srcdir)/dbxout.c $(srcdir)/dwarf2out.c $(srcdir)/dwarf2asm.c \ $(srcdir)/tree-vect-generic.c \ $(srcdir)/dojump.c \ $(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \ diff --git a/gcc/alias.c b/gcc/alias.c index c5ff664..c2a2c9d 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -43,7 +43,6 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "cgraph.h" #include "tree-pass.h" -#include "ipa-type-escape.h" #include "df.h" #include "tree-ssa-alias.h" #include "pointer-set.h" diff --git a/gcc/common.opt b/gcc/common.opt index 8cc35d1..88ae101 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1249,9 +1249,8 @@ Perform matrix layout flattening and transposing based on profiling information. fipa-struct-reorg -Common Report Var(flag_ipa_struct_reorg) -Perform structure layout optimizations based -on profiling information. +Common Ignore +Does nothing. Preserved for backward compatibility. fira-algorithm= Common Joined RejectNegative Enum(ira_algorithm) Var(flag_ira_algorithm) Init(IRA_ALGORITHM_CB) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 6390b81..6bb4403 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -351,7 +351,7 @@ Objective-C and Objective-C++ Dialects}. -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol -finline-small-functions -fipa-cp -fipa-cp-clone -fipa-matrix-reorg @gol -fipa-pta -fipa-profile -fipa-pure-const -fipa-reference @gol --fipa-struct-reorg -fira-algorithm=@var{algorithm} @gol +-fira-algorithm=@var{algorithm} @gol -fira-region=@var{region} @gol -fira-loop-pressure -fno-ira-share-save-slots @gol -fno-ira-share-spill-slots -fira-verbose=@var{n} @gol @@ -6766,19 +6766,6 @@ Discover which static variables do not escape cannot escape the compilation unit. Enabled by default at @option{-O} and higher. -@item -fipa-struct-reorg -@opindex fipa-struct-reorg -Perform structure reorganization optimization, that change C-like structures -layout in order to better utilize spatial locality. This transformation is -affective for programs containing arrays of structures. Available in two -compilation modes: profile-based (enabled with @option{-fprofile-generate}) -or static (which uses built-in heuristics). It works only in whole program -mode, so it requires @option{-fwhole-program} to be -enabled. Structures considered @samp{cold} by this transformation are not -affected (see @option{--param struct-reorg-cold-struct-ratio=@var{value}}). - -With this flag, the program debug info reflects a new structure layout. - @item -fipa-pta @opindex fipa-pta Perform interprocedural pointer analysis and interprocedural modification @@ -8216,15 +8203,6 @@ In each case, the @var{value} is an integer. The allowable choices for @var{name} are given in the following table: @table @gcctabopt -@item struct-reorg-cold-struct-ratio -The threshold ratio (as a percentage) between a structure frequency -and the frequency of the hottest structure in the program. This parameter -is used by struct-reorg optimization enabled by @option{-fipa-struct-reorg}. -We say that if the ratio of a structure frequency, calculated by profiling, -to the hottest structure frequency in the program is less than this -parameter, then structure reorganization is not applied to this structure. -The default is 10. - @item predictable-branch-outcome When branch is predicted to be taken with probability lower than this threshold (in percent), then it is considered well predictable. The default is 10. diff --git a/gcc/ipa-struct-reorg.c b/gcc/ipa-struct-reorg.c deleted file mode 100644 index 7ab321e..0000000 --- a/gcc/ipa-struct-reorg.c +++ /dev/null @@ -1,4064 +0,0 @@ -/* Struct-reorg optimization. - Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc. - Contributed by Olga Golovanevsky - (Initial version of this code was developed - by Caroline Tice and Mostafa Hagog.) - -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 3, 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; see the file COPYING3. If not see -. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "ggc.h" -#include "tree.h" -#include "rtl.h" -#include "gimple.h" -#include "tree-inline.h" -#include "tree-flow.h" -#include "tree-flow-inline.h" -#include "langhooks.h" -#include "pointer-set.h" -#include "hashtab.h" -#include "flags.h" -#include "debug.h" -#include "target.h" -#include "cgraph.h" -#include "diagnostic.h" -#include "tree-pretty-print.h" -#include "gimple-pretty-print.h" -#include "timevar.h" -#include "params.h" -#include "fibheap.h" -#include "intl.h" -#include "function.h" -#include "basic-block.h" -#include "tree-iterator.h" -#include "tree-pass.h" -#include "ipa-struct-reorg.h" -#include "opts.h" -#include "ipa-type-escape.h" -#include "tree-dump.h" -#include "gimple.h" - -/* This optimization implements structure peeling. - - For example, given a structure type: - typedef struct - { - int a; - float b; - int c; - }str_t; - - it can be peeled into two structure types as follows: - - typedef struct and typedef struct - { { - int a; float b; - int c; } str_t_1; - }str_t_0; - - or can be fully peeled: - - typedef struct - { - int a; - }str_t_0; - - typedef struct - { - float b; - }str_t_1; - - typedef struct - { - int c; - }str_t_2; - - When structure type is peeled all instances and their accesses - in the program are updated accordingly. For example, if there is - array of structures: - - str_t A[N]; - - and structure type str_t was peeled into two structures str_t_0 - and str_t_1 as it was shown above, then array A will be replaced - by two arrays as follows: - - str_t_0 A_0[N]; - str_t_1 A_1[N]; - - The field access of field a of element i of array A: A[i].a will be - replaced by an access to field a of element i of array A_0: A_0[i].a. - - This optimization also supports dynamically allocated arrays. - If array of structures was allocated by malloc function: - - str_t * p = (str_t *) malloc (sizeof (str_t) * N) - - the allocation site will be replaced to reflect new structure types: - - str_t_0 * p_0 = (str_t_0 *) malloc (sizeof (str_t_0) * N) - str_t_1 * p_1 = (str_t_1 *) malloc (sizeof (str_t_1) * N) - - The field access through the pointer p[i].a will be changed by p_0[i].a. - - The goal of structure peeling is to improve spatial locality. - For example, if one of the fields of a structure is accessed frequently - in the loop: - - for (i = 0; i < N; i++) - { - ... = A[i].a; - } - - the allocation of field a of str_t contiguously in memory will - increase the chances of fetching the field from cache. - - The analysis part of this optimization is based on the frequency of - field accesses, which are collected all over the program. - Then the fields with the frequencies that satisfy the following condition - get peeled out of the structure: - - freq(f) > C * max_field_freq_in_struct - - where max_field_freq_in_struct is the maximum field frequency - in the structure. C is a constant defining which portion of - max_field_freq_in_struct the fields should have in order to be peeled. - - If profiling information is provided, it is used to calculate the - frequency of field accesses. Otherwise, the structure is fully peeled. - - IPA type-escape analysis is used to determine when it is safe - to peel a structure. - - The optimization is activated by flag -fipa-struct-reorg. */ - -/* New variables created by this optimization. - When doing struct peeling, each variable of - the original struct type will be replaced by - the set of new variables corresponding to - the new structure types. */ -struct new_var_data { - /* VAR_DECL for original struct type. */ - tree orig_var; - /* Vector of new variables. */ - VEC(tree, heap) *new_vars; -}; - -typedef struct new_var_data *new_var; -typedef const struct new_var_data *const_new_var; - -/* This structure represents allocation site of the structure. */ -typedef struct alloc_site -{ - gimple stmt; - d_str str; -} alloc_site_t; - -DEF_VEC_O (alloc_site_t); -DEF_VEC_ALLOC_O (alloc_site_t, heap); - -/* Allocation sites that belong to the same function. */ -struct func_alloc_sites -{ - tree func; - /* Vector of allocation sites for function. */ - VEC (alloc_site_t, heap) *allocs; -}; - -typedef struct func_alloc_sites *fallocs_t; -typedef const struct func_alloc_sites *const_fallocs_t; - -/* All allocation sites in the program. */ -htab_t alloc_sites = NULL; - -/* New global variables. Generated once for whole program. */ -htab_t new_global_vars; - -/* New local variables. Generated per-function. */ -htab_t new_local_vars; - -/* Vector of structures to be transformed. */ -typedef struct data_structure structure; -DEF_VEC_O (structure); -DEF_VEC_ALLOC_O (structure, heap); -VEC (structure, heap) *structures; - -/* Forward declarations. */ -static bool is_equal_types (tree, tree); - -/* Strip structure TYPE from pointers and arrays. */ - -static inline tree -strip_type (tree type) -{ - gcc_assert (TYPE_P (type)); - - while (POINTER_TYPE_P (type) - || TREE_CODE (type) == ARRAY_TYPE) - type = TREE_TYPE (type); - - return type; -} - -/* This function returns type of VAR. */ - -static inline tree -get_type_of_var (tree var) -{ - if (!var) - return NULL; - - if (TREE_CODE (var) == PARM_DECL) - return DECL_ARG_TYPE (var); - else - return TREE_TYPE (var); -} - -/* Set of actions we do for each newly generated STMT. */ - -static inline void -finalize_stmt (gimple stmt) -{ - update_stmt (stmt); - mark_symbols_for_renaming (stmt); -} - -/* This function finalizes STMT and appends it to the list STMTS. */ - -static inline void -finalize_stmt_and_append (gimple_seq *stmts, gimple stmt) -{ - gimple_seq_add_stmt (stmts, stmt); - finalize_stmt (stmt); -} - -/* This function returns true if two fields FIELD1 and FIELD2 are - semantically equal, and false otherwise. */ - -static bool -compare_fields (tree field1, tree field2) -{ - if (DECL_NAME (field1) && DECL_NAME (field2)) - { - const char *name1 = IDENTIFIER_POINTER (DECL_NAME (field1)); - const char *name2 = IDENTIFIER_POINTER (DECL_NAME (field2)); - - gcc_assert (name1 && name2); - - if (strcmp (name1, name2)) - return false; - - } - else if (DECL_NAME (field1) || DECL_NAME (field2)) - return false; - - if (!is_equal_types (TREE_TYPE (field1), TREE_TYPE (field2))) - return false; - - return true; -} - -/* Given structure type SRT_TYPE and field FIELD, - this function is looking for a field with the same name - and type as FIELD in STR_TYPE. It returns it if found, - or NULL_TREE otherwise. */ - -static tree -find_field_in_struct_1 (tree str_type, tree field) -{ - tree str_field; - - if (!DECL_NAME (field)) - return NULL; - - for (str_field = TYPE_FIELDS (str_type); str_field; - str_field = TREE_CHAIN (str_field)) - { - - if (!DECL_NAME (str_field)) - continue; - - if (compare_fields (field, str_field)) - return str_field; - } - - return NULL_TREE; -} - -/* Given a field declaration FIELD_DECL, this function - returns corresponding field entry in structure STR. */ - -static struct field_entry * -find_field_in_struct (d_str str, tree field_decl) -{ - int i; - - tree field = find_field_in_struct_1 (str->decl, field_decl); - - for (i = 0; i < str->num_fields; i++) - if (str->fields[i].decl == field) - return &(str->fields[i]); - - return NULL; -} - -/* This function checks whether ARG is a result of multiplication - of some number by STRUCT_SIZE. If yes, the function returns true - and this number is filled into NUM. */ - -static bool -is_result_of_mult (tree arg, tree *num, tree struct_size) -{ - gimple size_def_stmt = SSA_NAME_DEF_STMT (arg); - - /* If the allocation statement was of the form - D.2229_10 = (D.2228_9); - then size_def_stmt can be D.2228_9 = num.3_8 * 8; */ - - if (size_def_stmt && is_gimple_assign (size_def_stmt)) - { - tree lhs = gimple_assign_lhs (size_def_stmt); - - /* We expect temporary here. */ - if (!is_gimple_reg (lhs)) - return false; - - if (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR) - { - tree arg0 = gimple_assign_rhs1 (size_def_stmt); - tree arg1 = gimple_assign_rhs2 (size_def_stmt); - - if (operand_equal_p (arg0, struct_size, OEP_ONLY_CONST)) - { - *num = arg1; - return true; - } - - if (operand_equal_p (arg1, struct_size, OEP_ONLY_CONST)) - { - *num = arg0; - return true; - } - } - } - - *num = NULL_TREE; - return false; -} - - -/* This function returns true if access ACC corresponds to the pattern - generated by compiler when an address of element i of an array - of structures STR_DECL (pointed by p) is calculated (p[i]). If this - pattern is recognized correctly, this function returns true - and fills missing fields in ACC. Otherwise it returns false. */ - -static bool -decompose_indirect_ref_acc (tree str_decl, struct field_access_site *acc) -{ - tree ref_var; - tree struct_size, op0, op1; - tree before_cast; - enum tree_code rhs_code; - - ref_var = TREE_OPERAND (acc->ref, 0); - - if (TREE_CODE (ref_var) != SSA_NAME) - return false; - - acc->ref_def_stmt = SSA_NAME_DEF_STMT (ref_var); - if (!(acc->ref_def_stmt) - || (gimple_code (acc->ref_def_stmt) != GIMPLE_ASSIGN)) - return false; - - rhs_code = gimple_assign_rhs_code (acc->ref_def_stmt); - - if (rhs_code != PLUS_EXPR - && rhs_code != MINUS_EXPR - && rhs_code != POINTER_PLUS_EXPR) - return false; - - op0 = gimple_assign_rhs1 (acc->ref_def_stmt); - op1 = gimple_assign_rhs2 (acc->ref_def_stmt); - - if (!is_array_access_through_pointer_and_index (rhs_code, op0, op1, - &acc->base, &acc->offset, - &acc->cast_stmt)) - return false; - - if (acc->cast_stmt) - before_cast = SINGLE_SSA_TREE_OPERAND (acc->cast_stmt, SSA_OP_USE); - else - before_cast = acc->offset; - - if (!before_cast) - return false; - - - if (SSA_NAME_IS_DEFAULT_DEF (before_cast)) - return false; - - struct_size = TYPE_SIZE_UNIT (str_decl); - - if (!is_result_of_mult (before_cast, &acc->num, struct_size)) - return false; - - /* ??? Add TREE_OPERAND (acc->ref, 1) to acc->offset. */ - if (!integer_zerop (TREE_OPERAND (acc->ref, 1))) - return false; - - return true; -} - - -/* This function checks whether the access ACC of structure type STR - is of the form suitable for transformation. If yes, it returns true. - False otherwise. */ - -static bool -decompose_access (tree str_decl, struct field_access_site *acc) -{ - gcc_assert (acc->ref); - - if (TREE_CODE (acc->ref) == MEM_REF) - return decompose_indirect_ref_acc (str_decl, acc); - else if (TREE_CODE (acc->ref) == ARRAY_REF) - return true; - else if (TREE_CODE (acc->ref) == VAR_DECL) - return true; - - return false; -} - -/* This function creates empty field_access_site node. */ - -static inline struct field_access_site * -make_field_acc_node (void) -{ - return XCNEW (struct field_access_site); -} - -/* This function returns the structure field access, defined by STMT, - if it is already in hashtable of function accesses F_ACCS. */ - -static struct field_access_site * -is_in_field_accs (gimple stmt, htab_t f_accs) -{ - return (struct field_access_site *) - htab_find_with_hash (f_accs, stmt, htab_hash_pointer (stmt)); -} - -/* This function adds an access ACC to the hashtable - F_ACCS of field accesses. */ - -static void -add_field_acc_to_acc_sites (struct field_access_site *acc, - htab_t f_accs) -{ - void **slot; - - gcc_assert (!is_in_field_accs (acc->stmt, f_accs)); - slot = htab_find_slot_with_hash (f_accs, acc->stmt, - htab_hash_pointer (acc->stmt), - INSERT); - *slot = acc; -} - -/* This function adds the VAR to vector of variables of - an access site defined by statement STMT. If access entry - with statement STMT does not exist in hashtable of - accesses ACCS, this function creates it. */ - -static void -add_access_to_acc_sites (gimple stmt, tree var, htab_t accs) -{ - struct access_site *acc; - - acc = (struct access_site *) - htab_find_with_hash (accs, stmt, htab_hash_pointer (stmt)); - - if (!acc) - { - void **slot; - - acc = XNEW (struct access_site); - acc->stmt = stmt; - if (!is_gimple_debug (stmt)) - acc->vars = VEC_alloc (tree, heap, 10); - else - acc->vars = NULL; - slot = htab_find_slot_with_hash (accs, stmt, - htab_hash_pointer (stmt), INSERT); - *slot = acc; - } - if (!is_gimple_debug (stmt)) - VEC_safe_push (tree, heap, acc->vars, var); -} - -/* This function adds NEW_DECL to function - referenced vars, and marks it for renaming. */ - -static void -finalize_var_creation (tree new_decl) -{ - add_referenced_var (new_decl); - mark_sym_for_renaming (new_decl); -} - -/* This function finalizes VAR creation if it is a global VAR_DECL. */ - -static void -finalize_global_creation (tree var) -{ - if (TREE_CODE (var) == VAR_DECL - && is_global_var (var)) - finalize_var_creation (var); -} - -/* This function inserts NEW_DECL to varpool. */ - -static inline void -insert_global_to_varpool (tree new_decl) -{ - struct varpool_node *new_node; - - new_node = varpool_node (new_decl); - notice_global_symbol (new_decl); - varpool_mark_needed_node (new_node); - varpool_finalize_decl (new_decl); -} - -/* This function finalizes the creation of new variables, - defined by *SLOT->new_vars. */ - -static int -finalize_new_vars_creation (void **slot, void *data ATTRIBUTE_UNUSED) -{ - new_var n_var = *(new_var *) slot; - unsigned i; - tree var; - - FOR_EACH_VEC_ELT (tree, n_var->new_vars, i, var) - finalize_var_creation (var); - return 1; -} - -/* This function looks for the variable of NEW_TYPE type, stored in VAR. - It returns it, if found, and NULL_TREE otherwise. */ - -static tree -find_var_in_new_vars_vec (new_var var, tree new_type) -{ - tree n_var; - unsigned i; - - FOR_EACH_VEC_ELT (tree, var->new_vars, i, n_var) - { - tree type = strip_type(get_type_of_var (n_var)); - gcc_assert (type); - - if (type == new_type) - return n_var; - } - - return NULL_TREE; -} - -/* This function returns new_var node, the orig_var of which is DECL. - It looks for new_var's in NEW_VARS_HTAB. If not found, - the function returns NULL. */ - -static new_var -is_in_new_vars_htab (tree decl, htab_t new_vars_htab) -{ - return (new_var) htab_find_with_hash (new_vars_htab, decl, - DECL_UID (decl)); -} - -/* Given original variable ORIG_VAR, this function returns - new variable corresponding to it of NEW_TYPE type. */ - -static tree -find_new_var_of_type (tree orig_var, tree new_type) -{ - new_var var; - gcc_assert (orig_var && new_type); - - if (TREE_CODE (orig_var) == SSA_NAME) - orig_var = SSA_NAME_VAR (orig_var); - - var = is_in_new_vars_htab (orig_var, new_global_vars); - if (!var) - var = is_in_new_vars_htab (orig_var, new_local_vars); - gcc_assert (var); - return find_var_in_new_vars_vec (var, new_type); -} - -/* This function generates stmt: - res = NUM * sizeof(TYPE) and returns it. - res is filled into RES. */ - -static gimple -gen_size (tree num, tree type, tree *res) -{ - tree struct_size = TYPE_SIZE_UNIT (type); - HOST_WIDE_INT struct_size_int = TREE_INT_CST_LOW (struct_size); - gimple new_stmt; - - *res = create_tmp_var (TREE_TYPE (num), NULL); - - if (*res) - add_referenced_var (*res); - - if (exact_log2 (struct_size_int) == -1) - { - tree size = build_int_cst (TREE_TYPE (num), struct_size_int); - new_stmt = gimple_build_assign (*res, fold_build2 (MULT_EXPR, - TREE_TYPE (num), - num, size)); - } - else - { - tree C = build_int_cst (TREE_TYPE (num), exact_log2 (struct_size_int)); - - new_stmt = gimple_build_assign (*res, fold_build2 (LSHIFT_EXPR, - TREE_TYPE (num), - num, C)); - } - - finalize_stmt (new_stmt); - return new_stmt; -} - -/* This function generates and returns a statement, that cast variable - BEFORE_CAST to NEW_TYPE. The cast result variable is stored - into RES_P. ORIG_CAST_STMT is the original cast statement. */ - -static gimple -gen_cast_stmt (tree before_cast, tree new_type, gimple orig_cast_stmt, - tree *res_p) -{ - tree lhs, new_lhs; - gimple new_stmt; - - lhs = gimple_assign_lhs (orig_cast_stmt); - new_lhs = find_new_var_of_type (lhs, new_type); - gcc_assert (new_lhs); - - new_stmt = gimple_build_assign_with_ops (NOP_EXPR, new_lhs, before_cast, 0); - finalize_stmt (new_stmt); - *res_p = new_lhs; - return new_stmt; -} - -/* This function builds an edge between BB and E->dest and updates - phi nodes of E->dest. It returns newly created edge. */ - -static edge -make_edge_and_fix_phis_of_dest (basic_block bb, edge e) -{ - edge new_e; - tree arg; - gimple_stmt_iterator si; - - new_e = make_edge (bb, e->dest, e->flags); - - for (si = gsi_start_phis (new_e->dest); !gsi_end_p (si); gsi_next (&si)) - { - gimple phi = gsi_stmt (si); - arg = PHI_ARG_DEF_FROM_EDGE (phi, e); - add_phi_arg (phi, arg, new_e, gimple_phi_arg_location_from_edge (phi, e)); - } - - return new_e; -} - -/* This function inserts NEW_STMT before STMT. */ - -static void -insert_before_stmt (gimple stmt, gimple new_stmt) -{ - gimple_stmt_iterator bsi; - - if (!stmt || !new_stmt) - return; - - bsi = gsi_for_stmt (stmt); - gsi_insert_before (&bsi, new_stmt, GSI_SAME_STMT); -} - -/* Insert NEW_STMTS after STMT. */ - -static void -insert_seq_after_stmt (gimple stmt, gimple_seq new_stmts) -{ - gimple_stmt_iterator bsi; - - if (!stmt || !new_stmts) - return; - - bsi = gsi_for_stmt (stmt); - gsi_insert_seq_after (&bsi, new_stmts, GSI_SAME_STMT); -} - -/* Insert NEW_STMT after STMT. */ - -static void -insert_after_stmt (gimple stmt, gimple new_stmt) -{ - gimple_stmt_iterator bsi; - - if (!stmt || !new_stmt) - return; - - bsi = gsi_for_stmt (stmt); - gsi_insert_after (&bsi, new_stmt, GSI_SAME_STMT); -} - -/* This function returns vector of allocation sites - that appear in function FN_DECL. */ - -static fallocs_t -get_fallocs (tree fn_decl) -{ - return (fallocs_t) htab_find_with_hash (alloc_sites, fn_decl, - htab_hash_pointer (fn_decl)); -} - -/* If ALLOC_STMT is D.2225_7 = (D.2224_6); - and it is a part of allocation of a structure, - then it is usually followed by a cast stmt - p_8 = (struct str_t *) D.2225_7; - which is returned by this function. */ - -static gimple -get_final_alloc_stmt (gimple alloc_stmt) -{ - gimple final_stmt; - use_operand_p use_p; - tree alloc_res; - - if (!alloc_stmt) - return NULL; - - if (!is_gimple_call (alloc_stmt)) - return NULL; - - alloc_res = gimple_get_lhs (alloc_stmt); - - if (TREE_CODE (alloc_res) != SSA_NAME) - return NULL; - - if (!single_imm_use (alloc_res, &use_p, &final_stmt)) - return NULL; - else - return final_stmt; -} - -/* This function returns true if STMT is one of allocation - sites of function FN_DECL. It returns false otherwise. */ - -static bool -is_part_of_malloc (gimple stmt, tree fn_decl) -{ - fallocs_t fallocs = get_fallocs (fn_decl); - - if (fallocs) - { - alloc_site_t *call; - unsigned i; - - FOR_EACH_VEC_ELT (alloc_site_t, fallocs->allocs, i, call) - if (call->stmt == stmt - || get_final_alloc_stmt (call->stmt) == stmt) - return true; - } - return false; -} - -/* Auxiliary structure for a lookup over field accesses. */ -struct find_stmt_data -{ - bool found; - gimple stmt; -}; - -/* This function looks for DATA->stmt among - the statements involved in the field access, - defined by SLOT. It stops when it's found. */ - -static int -find_in_field_accs (void **slot, void *data) -{ - struct field_access_site *f_acc = *(struct field_access_site **) slot; - gimple stmt = ((struct find_stmt_data *)data)->stmt; - - if (f_acc->stmt == stmt - || f_acc->ref_def_stmt == stmt - || f_acc->cast_stmt == stmt) - { - ((struct find_stmt_data *)data)->found = true; - return 0; - } - else - return 1; -} - -/* This function checks whether STMT is part of field - accesses of structure STR. It returns true, if found, - and false otherwise. */ - -static bool -is_part_of_field_access (gimple stmt, d_str str) -{ - int i; - - for (i = 0; i < str->num_fields; i++) - { - struct find_stmt_data data; - data.found = false; - data.stmt = stmt; - - if (str->fields[i].acc_sites) - htab_traverse (str->fields[i].acc_sites, find_in_field_accs, &data); - - if (data.found) - return true; - } - - return false; -} - -/* Auxiliary data for exclude_from_accs function. */ - -struct exclude_data -{ - tree fn_decl; - d_str str; -}; - -/* This function returns component_ref with the BASE and - field named FIELD_ID from structure TYPE. */ - -static inline tree -build_comp_ref (tree base, tree field_id, tree type) -{ - tree field; - bool found = false; - - - /* Find field of structure type with the same name as field_id. */ - for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) - { - if (DECL_NAME (field) == field_id) - { - found = true; - break; - } - } - - gcc_assert (found); - - return build3 (COMPONENT_REF, TREE_TYPE (field), base, field, NULL_TREE); -} - - -/* This struct represent data used for walk_tree - called from function find_pos_in_stmt. - - ref is a tree to be found, - - and pos is a pointer that points to ref in stmt. */ -struct ref_pos -{ - tree *pos; - tree ref; - tree container; -}; - - -/* This is a callback function for walk_tree, called from - collect_accesses_in_bb function. DATA is a pointer to ref_pos structure. - When *TP is equal to DATA->ref, the walk_tree stops, - and found position, equal to TP, is assigned to DATA->pos. */ - -static tree -find_pos_in_stmt_1 (tree *tp, int *walk_subtrees, void * data) -{ - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - struct ref_pos *r_pos = (struct ref_pos *) wi->info; - tree ref = r_pos->ref; - tree t = *tp; - - if (t == ref || (TREE_CODE (t) == SSA_NAME && SSA_NAME_VAR (t) == ref)) - { - r_pos->pos = tp; - return t; - } - - r_pos->container = t; - *walk_subtrees = 1; - return NULL_TREE; -} - - -/* This function looks for the pointer of REF in STMT, - It returns it, if found, and NULL otherwise. */ - -static tree * -find_pos_in_stmt (gimple stmt, tree ref, struct ref_pos * r_pos) -{ - struct walk_stmt_info wi; - - r_pos->ref = ref; - r_pos->pos = NULL; - r_pos->container = NULL_TREE; - memset (&wi, 0, sizeof (wi)); - wi.info = r_pos; - walk_gimple_op (stmt, find_pos_in_stmt_1, &wi); - - return r_pos->pos; -} - -/* This structure is used to represent array - or pointer-to wrappers of structure type. - For example, if type1 is structure type, - then for type1 ** we generate two type_wrapper - structures with wrap = 0 each one. - It's used to unwind the original type up to - structure type, replace it with the new structure type - and wrap it back in the opposite order. */ - -typedef struct type_wrapper -{ - /* 0 stand for pointer wrapper, and 1 for array wrapper. */ - bool wrap; - - /* Relevant for arrays as domain or index. */ - tree domain; -}type_wrapper_t; - -DEF_VEC_O (type_wrapper_t); -DEF_VEC_ALLOC_O (type_wrapper_t, heap); - -/* This function replace field access ACC by the new - field access of structure type NEW_TYPE. */ - -static void -replace_field_acc (struct field_access_site *acc, tree new_type) -{ - tree ref_var = acc->ref; - tree new_ref; - tree lhs, rhs; - tree *pos; - tree new_acc; - tree field_id = DECL_NAME (acc->field_decl); - VEC (type_wrapper_t, heap) *wrapper = VEC_alloc (type_wrapper_t, heap, 10); - type_wrapper_t *wr_p = NULL; - struct ref_pos r_pos; - - while (TREE_CODE (ref_var) == MEM_REF - || TREE_CODE (ref_var) == ARRAY_REF) - { - type_wrapper_t wr; - - if (TREE_CODE (ref_var) == MEM_REF) - { - wr.wrap = 0; - wr.domain = 0; - } - else - { - wr.wrap = 1; - wr.domain = TREE_OPERAND (ref_var, 1); - } - - VEC_safe_push (type_wrapper_t, heap, wrapper, &wr); - ref_var = TREE_OPERAND (ref_var, 0); - } - - new_ref = find_new_var_of_type (ref_var, new_type); - finalize_global_creation (new_ref); - - while (VEC_length (type_wrapper_t, wrapper) != 0) - { - tree type = TREE_TYPE (TREE_TYPE (new_ref)); - - wr_p = VEC_last (type_wrapper_t, wrapper); - if (wr_p->wrap) /* Array. */ - new_ref = build4 (ARRAY_REF, type, new_ref, - wr_p->domain, NULL_TREE, NULL_TREE); - else /* Pointer. */ - new_ref = build_simple_mem_ref (new_ref); - VEC_pop (type_wrapper_t, wrapper); - } - - new_acc = build_comp_ref (new_ref, field_id, new_type); - VEC_free (type_wrapper_t, heap, wrapper); - - if (is_gimple_assign (acc->stmt)) - { - lhs = gimple_assign_lhs (acc->stmt); - rhs = gimple_assign_rhs1 (acc->stmt); - - if (lhs == acc->comp_ref) - gimple_assign_set_lhs (acc->stmt, new_acc); - else if (rhs == acc->comp_ref) - gimple_assign_set_rhs1 (acc->stmt, new_acc); - else - { - pos = find_pos_in_stmt (acc->stmt, acc->comp_ref, &r_pos); - gcc_assert (pos); - *pos = new_acc; - } - } - else - { - pos = find_pos_in_stmt (acc->stmt, acc->comp_ref, &r_pos); - gcc_assert (pos); - *pos = new_acc; - } - - finalize_stmt (acc->stmt); -} - -/* This function replace field access ACC by a new field access - of structure type NEW_TYPE. */ - -static void -replace_field_access_stmt (struct field_access_site *acc, tree new_type) -{ - - if (TREE_CODE (acc->ref) == MEM_REF - ||TREE_CODE (acc->ref) == ARRAY_REF - ||TREE_CODE (acc->ref) == VAR_DECL) - replace_field_acc (acc, new_type); - else - gcc_unreachable (); -} - -/* This function looks for d_str, represented by TYPE, in the structures - vector. If found, it returns an index of found structure. Otherwise - it returns a length of the structures vector. */ - -static unsigned -find_structure (tree type) -{ - d_str str; - unsigned i; - - type = TYPE_MAIN_VARIANT (type); - - FOR_EACH_VEC_ELT (structure, structures, i, str) - if (is_equal_types (str->decl, type)) - return i; - - return VEC_length (structure, structures); -} - -/* In this function we create new statements that have the same - form as ORIG_STMT, but of type NEW_TYPE. The statements - treated by this function are simple assignments, - like assignments: p.8_7 = p; or statements with rhs of - tree codes PLUS_EXPR and MINUS_EXPR. */ - -static gimple -create_base_plus_offset (gimple orig_stmt, tree new_type, tree offset) -{ - tree lhs; - tree new_lhs; - gimple new_stmt; - tree new_op0 = NULL_TREE, new_op1 = NULL_TREE; - - lhs = gimple_assign_lhs (orig_stmt); - - gcc_assert (TREE_CODE (lhs) == VAR_DECL - || TREE_CODE (lhs) == SSA_NAME); - - new_lhs = find_new_var_of_type (lhs, new_type); - gcc_assert (new_lhs); - finalize_var_creation (new_lhs); - - switch (gimple_assign_rhs_code (orig_stmt)) - { - case PLUS_EXPR: - case MINUS_EXPR: - case POINTER_PLUS_EXPR: - { - tree op0 = gimple_assign_rhs1 (orig_stmt); - tree op1 = gimple_assign_rhs2 (orig_stmt); - unsigned str0, str1; - unsigned length = VEC_length (structure, structures); - - - str0 = find_structure (strip_type (get_type_of_var (op0))); - str1 = find_structure (strip_type (get_type_of_var (op1))); - gcc_assert ((str0 != length) || (str1 != length)); - - if (str0 != length) - new_op0 = find_new_var_of_type (op0, new_type); - if (str1 != length) - new_op1 = find_new_var_of_type (op1, new_type); - - if (!new_op0) - new_op0 = offset; - if (!new_op1) - new_op1 = offset; - } - break; - - default: - gcc_unreachable(); - } - - new_stmt = gimple_build_assign_with_ops (gimple_assign_rhs_code (orig_stmt), - new_lhs, new_op0, new_op1); - finalize_stmt (new_stmt); - - return new_stmt; -} - -/* Given a field access F_ACC of the FIELD, this function - replaces it by the new field access. */ - -static void -create_new_field_access (struct field_access_site *f_acc, - struct field_entry field) -{ - tree new_type = field.field_mapping; - gimple new_stmt; - tree size_res; - gimple mult_stmt; - gimple cast_stmt; - tree cast_res = NULL; - - if (f_acc->num) - { - mult_stmt = gen_size (f_acc->num, new_type, &size_res); - insert_before_stmt (f_acc->ref_def_stmt, mult_stmt); - } - - if (f_acc->cast_stmt) - { - cast_stmt = gen_cast_stmt (size_res, new_type, - f_acc->cast_stmt, &cast_res); - insert_after_stmt (f_acc->cast_stmt, cast_stmt); - } - - if (f_acc->ref_def_stmt) - { - tree offset; - if (cast_res) - offset = cast_res; - else - offset = size_res; - - new_stmt = create_base_plus_offset (f_acc->ref_def_stmt, - new_type, offset); - insert_after_stmt (f_acc->ref_def_stmt, new_stmt); - } - - /* In stmt D.2163_19 = D.2162_18->b; we replace variable - D.2162_18 by an appropriate variable of new_type type. */ - replace_field_access_stmt (f_acc, new_type); -} - -/* This function creates a new condition statement - corresponding to the original COND_STMT, adds new basic block - and redirects condition edges. NEW_VAR is a new condition - variable located in the condition statement at the position POS. */ - -static void -create_new_stmts_for_cond_expr_1 (tree new_var, gimple cond_stmt, unsigned pos) -{ - gimple new_stmt; - edge true_e = NULL, false_e = NULL; - basic_block new_bb; - gimple_stmt_iterator si; - - extract_true_false_edges_from_block (gimple_bb (cond_stmt), - &true_e, &false_e); - - new_stmt = gimple_build_cond (gimple_cond_code (cond_stmt), - pos == 0 ? new_var : gimple_cond_lhs (cond_stmt), - pos == 1 ? new_var : gimple_cond_rhs (cond_stmt), - NULL_TREE, - NULL_TREE); - - finalize_stmt (new_stmt); - - /* Create new basic block after bb. */ - new_bb = create_empty_bb (gimple_bb (cond_stmt)); - - /* Add new condition stmt to the new_bb. */ - si = gsi_start_bb (new_bb); - gsi_insert_after (&si, new_stmt, GSI_NEW_STMT); - - /* Create false and true edges from new_bb. */ - make_edge_and_fix_phis_of_dest (new_bb, true_e); - make_edge_and_fix_phis_of_dest (new_bb, false_e); - - /* Redirect one of original edges to point to new_bb. */ - if (gimple_cond_code (cond_stmt) == NE_EXPR) - redirect_edge_succ (true_e, new_bb); - else - redirect_edge_succ (false_e, new_bb); -} - -/* This function creates new condition statements corresponding - to original condition STMT, one for each new type, and - recursively redirect edges to newly generated basic blocks. */ - -static void -create_new_stmts_for_cond_expr (gimple stmt) -{ - tree arg0, arg1, arg; - unsigned str0, str1; - bool s0, s1; - d_str str; - tree type; - unsigned pos; - int i; - unsigned length = VEC_length (structure, structures); - - gcc_assert (gimple_cond_code (stmt) == EQ_EXPR - || gimple_cond_code (stmt) == NE_EXPR); - - arg0 = gimple_cond_lhs (stmt); - arg1 = gimple_cond_rhs (stmt); - - str0 = find_structure (strip_type (get_type_of_var (arg0))); - str1 = find_structure (strip_type (get_type_of_var (arg1))); - - s0 = (str0 != length) ? true : false; - s1 = (str1 != length) ? true : false; - - gcc_assert (s0 || s1); - /* For now we allow only comparison with 0 or NULL. */ - gcc_assert (integer_zerop (arg0) || integer_zerop (arg1)); - - str = integer_zerop (arg0) ? - VEC_index (structure, structures, str1): - VEC_index (structure, structures, str0); - arg = integer_zerop (arg0) ? arg1 : arg0; - pos = integer_zerop (arg0) ? 1 : 0; - - FOR_EACH_VEC_ELT (tree, str->new_types, i, type) - { - tree new_arg; - - new_arg = find_new_var_of_type (arg, type); - create_new_stmts_for_cond_expr_1 (new_arg, stmt, pos); - } -} - -/* This function looks for VAR in STMT, and replace it with NEW_VAR. - If needed, it wraps NEW_VAR in pointers and indirect references - before insertion. */ - -static void -insert_new_var_in_stmt (gimple stmt, tree var, tree new_var) -{ - struct ref_pos r_pos; - tree *pos; - - pos = find_pos_in_stmt (stmt, var, &r_pos); - gcc_assert (pos); - - while (r_pos.container && (TREE_CODE(r_pos.container) == MEM_REF - || TREE_CODE(r_pos.container) == ADDR_EXPR)) - { - if (TREE_CODE(r_pos.container) == MEM_REF) - new_var = build_simple_mem_ref (new_var); - else - new_var = build_fold_addr_expr (new_var); - pos = find_pos_in_stmt (stmt, r_pos.container, &r_pos); - } - - *pos = new_var; -} - - -/* Create a new general access to replace original access ACC - for structure type NEW_TYPE. */ - -static gimple -create_general_new_stmt (struct access_site *acc, tree new_type) -{ - gimple old_stmt = acc->stmt; - tree var; - gimple new_stmt = gimple_copy (old_stmt); - unsigned i; - - /* We are really building a new stmt, clear the virtual operands. */ - if (gimple_has_mem_ops (new_stmt)) - { - gimple_set_vuse (new_stmt, NULL_TREE); - gimple_set_vdef (new_stmt, NULL_TREE); - } - - FOR_EACH_VEC_ELT (tree, acc->vars, i, var) - { - tree new_var = find_new_var_of_type (var, new_type); - tree lhs, rhs = NULL_TREE; - - gcc_assert (new_var); - finalize_var_creation (new_var); - - if (is_gimple_assign (new_stmt)) - { - lhs = gimple_assign_lhs (new_stmt); - - if (TREE_CODE (lhs) == SSA_NAME) - lhs = SSA_NAME_VAR (lhs); - if (gimple_assign_rhs_code (new_stmt) == SSA_NAME) - rhs = SSA_NAME_VAR (gimple_assign_rhs1 (new_stmt)); - - /* It can happen that rhs is a constructor. - Then we have to replace it to be of new_type. */ - if (gimple_assign_rhs_code (new_stmt) == CONSTRUCTOR) - { - /* Dealing only with empty constructors right now. */ - gcc_assert (VEC_empty (constructor_elt, - CONSTRUCTOR_ELTS (rhs))); - rhs = build_constructor (new_type, 0); - gimple_assign_set_rhs1 (new_stmt, rhs); - } - - if (lhs == var) - gimple_assign_set_lhs (new_stmt, new_var); - else if (rhs == var) - gimple_assign_set_rhs1 (new_stmt, new_var); - else - insert_new_var_in_stmt (new_stmt, var, new_var); - } - else - insert_new_var_in_stmt (new_stmt, var, new_var); - } - - finalize_stmt (new_stmt); - return new_stmt; -} - -/* For each new type in STR this function creates new general accesses - corresponding to the original access ACC. */ - -static void -create_new_stmts_for_general_acc (struct access_site *acc, d_str str) -{ - tree type; - gimple stmt = acc->stmt; - unsigned i; - - FOR_EACH_VEC_ELT (tree, str->new_types, i, type) - { - gimple new_stmt; - - new_stmt = create_general_new_stmt (acc, type); - insert_after_stmt (stmt, new_stmt); - } -} - -/* This function creates a new general access of structure STR - to replace the access ACC. */ - -static void -create_new_general_access (struct access_site *acc, d_str str) -{ - gimple stmt = acc->stmt; - switch (gimple_code (stmt)) - { - case GIMPLE_COND: - create_new_stmts_for_cond_expr (stmt); - break; - - case GIMPLE_DEBUG: - /* It is very hard to maintain usable debug info after struct peeling, - for now just reset all debug stmts referencing objects that have - been peeled. */ - gimple_debug_bind_reset_value (stmt); - update_stmt (stmt); - break; - - default: - create_new_stmts_for_general_acc (acc, str); - } -} - -/* Auxiliary data for creation of accesses. */ -struct create_acc_data -{ - basic_block bb; - d_str str; - int field_index; -}; - -/* This function creates a new general access, defined by SLOT. - DATA is a pointer to create_acc_data structure. */ - -static int -create_new_acc (void **slot, void *data) -{ - struct access_site *acc = *(struct access_site **) slot; - basic_block bb = ((struct create_acc_data *)data)->bb; - d_str str = ((struct create_acc_data *)data)->str; - - if (gimple_bb (acc->stmt) == bb) - create_new_general_access (acc, str); - return 1; -} - -/* This function creates a new field access, defined by SLOT. - DATA is a pointer to create_acc_data structure. */ - -static int -create_new_field_acc (void **slot, void *data) -{ - struct field_access_site *f_acc = *(struct field_access_site **) slot; - basic_block bb = ((struct create_acc_data *)data)->bb; - d_str str = ((struct create_acc_data *)data)->str; - int i = ((struct create_acc_data *)data)->field_index; - - if (gimple_bb (f_acc->stmt) == bb) - create_new_field_access (f_acc, str->fields[i]); - return 1; -} - -/* This function creates new accesses for the structure - type STR in basic block BB. */ - -static void -create_new_accs_for_struct (d_str str, basic_block bb) -{ - int i; - struct create_acc_data dt; - - dt.str = str; - dt.bb = bb; - dt.field_index = -1; - - for (i = 0; i < str->num_fields; i++) - { - dt.field_index = i; - - if (str->fields[i].acc_sites) - htab_traverse (str->fields[i].acc_sites, - create_new_field_acc, &dt); - } - if (str->accs) - htab_traverse (str->accs, create_new_acc, &dt); -} - -/* This function inserts new variables from new_var, - defined by SLOT, into varpool. */ - -static int -update_varpool_with_new_var (void **slot, void *data ATTRIBUTE_UNUSED) -{ - new_var n_var = *(new_var *) slot; - tree var; - unsigned i; - - FOR_EACH_VEC_ELT (tree, n_var->new_vars, i, var) - insert_global_to_varpool (var); - return 1; -} - -/* This function prints a field access site, defined by SLOT. */ - -static int -dump_field_acc (void **slot, void *data ATTRIBUTE_UNUSED) -{ - struct field_access_site *f_acc = - *(struct field_access_site **) slot; - - fprintf(dump_file, "\n"); - if (f_acc->stmt) - print_gimple_stmt (dump_file, f_acc->stmt, 0, 0); - if (f_acc->ref_def_stmt) - print_gimple_stmt (dump_file, f_acc->ref_def_stmt, 0, 0); - if (f_acc->cast_stmt) - print_gimple_stmt (dump_file, f_acc->cast_stmt, 0, 0); - return 1; -} - -/* Print field accesses from hashtable F_ACCS. */ - -static void -dump_field_acc_sites (htab_t f_accs) -{ - if (!dump_file) - return; - - if (f_accs) - htab_traverse (f_accs, dump_field_acc, NULL); -} - -/* Hash value for fallocs_t. */ - -static hashval_t -malloc_hash (const void *x) -{ - return htab_hash_pointer (((const_fallocs_t)x)->func); -} - -/* This function returns nonzero if function of func_alloc_sites' X - is equal to Y. */ - -static int -malloc_eq (const void *x, const void *y) -{ - return ((const_fallocs_t)x)->func == (const_tree)y; -} - -/* This function is a callback for traversal over a structure accesses. - It frees an access represented by SLOT. */ - -static int -free_accs (void **slot, void *data ATTRIBUTE_UNUSED) -{ - struct access_site * acc = *(struct access_site **) slot; - - VEC_free (tree, heap, acc->vars); - free (acc); - return 1; -} - -/* This is a callback function for traversal over field accesses. - It frees a field access represented by SLOT. */ - -static int -free_field_accs (void **slot, void *data ATTRIBUTE_UNUSED) -{ - struct field_access_site *f_acc = *(struct field_access_site **) slot; - - free (f_acc); - return 1; -} - -/* This function inserts TYPE into vector of UNSUITABLE_TYPES, - if it is not there yet. */ - -static void -add_unsuitable_type (VEC (tree, heap) **unsuitable_types, tree type) -{ - unsigned i; - tree t; - - if (!type) - return; - - type = TYPE_MAIN_VARIANT (type); - - FOR_EACH_VEC_ELT (tree, *unsuitable_types, i, t) - if (is_equal_types (t, type)) - break; - - if (i == VEC_length (tree, *unsuitable_types)) - VEC_safe_push (tree, heap, *unsuitable_types, type); -} - -/* Given a type TYPE, this function returns the name of the type. */ - -static const char * -get_type_name (tree type) -{ - if (! TYPE_NAME (type)) - return NULL; - - if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) - return IDENTIFIER_POINTER (TYPE_NAME (type)); - else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL - && DECL_NAME (TYPE_NAME (type))) - return IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); - else - return NULL; -} - -/* This function is a temporary hack to overcome the types problem. - When several compilation units are compiled together - with -combine, the TYPE_MAIN_VARIANT of the same type - can appear differently in different compilation units. - Therefore this function first compares type names. - If there are no names, structure bodies are recursively - compared. */ - -static bool -is_equal_types (tree type1, tree type2) -{ - const char * name1,* name2; - - if ((!type1 && type2) - ||(!type2 && type1)) - return false; - - if (!type1 && !type2) - return true; - - if (TREE_CODE (type1) != TREE_CODE (type2)) - return false; - - if (type1 == type2) - return true; - - if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)) - return true; - - name1 = get_type_name (type1); - name2 = get_type_name (type2); - - if (name1 && name2) - return strcmp (name1, name2) == 0; - - switch (TREE_CODE (type1)) - { - case POINTER_TYPE: - case REFERENCE_TYPE: - { - return is_equal_types (TREE_TYPE (type1), TREE_TYPE (type2)); - } - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - case ENUMERAL_TYPE: - { - tree field1, field2; - - /* Compare fields of structure. */ - for (field1 = TYPE_FIELDS (type1), field2 = TYPE_FIELDS (type2); - field1 && field2; - field1 = TREE_CHAIN (field1), field2 = TREE_CHAIN (field2)) - { - if (!compare_fields (field1, field2)) - return false; - } - if (field1 || field2) - return false; - else - return true; - } - break; - - case INTEGER_TYPE: - { - if (TYPE_UNSIGNED (type1) == TYPE_UNSIGNED (type2) - && TYPE_PRECISION (type1) == TYPE_PRECISION (type2)) - return true; - } - break; - - case ARRAY_TYPE: - { - tree d1, d2; - tree max1, min1, max2, min2; - - if (!is_equal_types (TREE_TYPE (type1), TREE_TYPE (type2))) - return false; - - d1 = TYPE_DOMAIN (type1); - d2 = TYPE_DOMAIN (type2); - - if (!d1 || !d2) - return false; - - max1 = TYPE_MAX_VALUE (d1); - max2 = TYPE_MAX_VALUE (d2); - min1 = TYPE_MIN_VALUE (d1); - min2 = TYPE_MIN_VALUE (d2); - - if (max1 && max2 && min1 && min2 - && TREE_CODE (max1) == TREE_CODE (max2) - && TREE_CODE (max1) == INTEGER_CST - && TREE_CODE (min1) == TREE_CODE (min2) - && TREE_CODE (min1) == INTEGER_CST - && tree_int_cst_equal (max1, max2) - && tree_int_cst_equal (min1, min2)) - return true; - } - break; - - default: - gcc_unreachable(); - } - - return false; -} - -/* This function free non-field accesses from hashtable ACCS. */ - -static void -free_accesses (htab_t accs) -{ - if (accs) - htab_traverse (accs, free_accs, NULL); - htab_delete (accs); -} - -/* This function free field accesses hashtable F_ACCS. */ - -static void -free_field_accesses (htab_t f_accs) -{ - if (f_accs) - htab_traverse (f_accs, free_field_accs, NULL); - htab_delete (f_accs); -} - -/* Update call graph with new edge generated by new MALLOC_STMT. - The edge origin is CONTEXT function. */ - -static void -update_cgraph_with_malloc_call (gimple malloc_stmt, tree context) -{ - struct cgraph_node *src, *dest; - tree malloc_fn_decl; - - if (!malloc_stmt) - return; - - malloc_fn_decl = gimple_call_fndecl (malloc_stmt); - - src = cgraph_node (context); - dest = cgraph_node (malloc_fn_decl); - cgraph_create_edge (src, dest, malloc_stmt, - gimple_bb (malloc_stmt)->count, - compute_call_stmt_bb_frequency - (context, gimple_bb (malloc_stmt)), - gimple_bb (malloc_stmt)->loop_depth); -} - -/* This function generates set of statements required - to allocate number NUM of structures of type NEW_TYPE. - The statements are stored in NEW_STMTS. The statement that contain - call to malloc is returned. MALLOC_STMT is an original call to malloc. */ - -static gimple -create_new_malloc (gimple malloc_stmt, tree new_type, gimple_seq *new_stmts, - tree num) -{ - tree new_malloc_size; - tree malloc_fn_decl; - gimple new_stmt; - tree malloc_res; - gimple call_stmt, final_stmt; - tree cast_res; - - gcc_assert (num && malloc_stmt && new_type); - *new_stmts = gimple_seq_alloc (); - - /* Generate argument to malloc as multiplication of num - and size of new_type. */ - new_stmt = gen_size (num, new_type, &new_malloc_size); - gimple_seq_add_stmt (new_stmts, new_stmt); - - /* Generate new call for malloc. */ - malloc_res = create_tmp_var (ptr_type_node, NULL); - add_referenced_var (malloc_res); - - malloc_fn_decl = gimple_call_fndecl (malloc_stmt); - call_stmt = gimple_build_call (malloc_fn_decl, 1, new_malloc_size); - gimple_call_set_lhs (call_stmt, malloc_res); - finalize_stmt_and_append (new_stmts, call_stmt); - - /* Create new cast statement. */ - final_stmt = get_final_alloc_stmt (malloc_stmt); - gcc_assert (final_stmt); - new_stmt = gen_cast_stmt (malloc_res, new_type, final_stmt, &cast_res); - gimple_seq_add_stmt (new_stmts, new_stmt); - - return call_stmt; -} - -/* This function returns a tree representing - the number of instances of structure STR_DECL allocated - by allocation STMT. If new statements are generated, - they are filled into NEW_STMTS_P. */ - -static tree -gen_num_of_structs_in_malloc (gimple stmt, tree str_decl, - gimple_seq *new_stmts_p) -{ - tree arg; - tree struct_size; - HOST_WIDE_INT struct_size_int; - - if (!stmt) - return NULL_TREE; - - /* Get malloc argument. */ - if (!is_gimple_call (stmt)) - return NULL_TREE; - - arg = gimple_call_arg (stmt, 0); - - if (TREE_CODE (arg) != SSA_NAME - && !TREE_CONSTANT (arg)) - return NULL_TREE; - - struct_size = TYPE_SIZE_UNIT (str_decl); - struct_size_int = TREE_INT_CST_LOW (struct_size); - - gcc_assert (struct_size); - - if (TREE_CODE (arg) == SSA_NAME) - { - tree num; - gimple div_stmt; - - if (is_result_of_mult (arg, &num, struct_size)) - return num; - - num = create_tmp_var (integer_type_node, NULL); - - if (num) - add_referenced_var (num); - - if (exact_log2 (struct_size_int) == -1) - div_stmt = gimple_build_assign_with_ops (TRUNC_DIV_EXPR, num, arg, - struct_size); - else - { - tree C = build_int_cst (integer_type_node, - exact_log2 (struct_size_int)); - - div_stmt = gimple_build_assign_with_ops (RSHIFT_EXPR, num, arg, C); - } - gimple_seq_add_stmt (new_stmts_p, div_stmt); - finalize_stmt (div_stmt); - return num; - } - - if (CONSTANT_CLASS_P (arg) - && multiple_of_p (TREE_TYPE (struct_size), arg, struct_size)) - return int_const_binop (TRUNC_DIV_EXPR, arg, struct_size, 0); - - return NULL_TREE; -} - -/* This function is a callback for traversal on new_var's hashtable. - SLOT is a pointer to new_var. This function prints to dump_file - an original variable and all new variables from the new_var - pointed by *SLOT. */ - -static int -dump_new_var (void **slot, void *data ATTRIBUTE_UNUSED) -{ - new_var n_var = *(new_var *) slot; - tree var_type; - tree var; - unsigned i; - - var_type = get_type_of_var (n_var->orig_var); - - fprintf (dump_file, "\nOrig var: "); - print_generic_expr (dump_file, n_var->orig_var, 0); - fprintf (dump_file, " of type "); - print_generic_expr (dump_file, var_type, 0); - fprintf (dump_file, "\n"); - - for (i = 0; - VEC_iterate (tree, n_var->new_vars, i, var); i++) - { - var_type = get_type_of_var (var); - - fprintf (dump_file, " "); - print_generic_expr (dump_file, var, 0); - fprintf (dump_file, " of type "); - print_generic_expr (dump_file, var_type, 0); - fprintf (dump_file, "\n"); - } - return 1; -} - -/* This function copies attributes form ORIG_DECL to NEW_DECL. */ - -static inline void -copy_decl_attributes (tree new_decl, tree orig_decl) -{ - - DECL_ARTIFICIAL (new_decl) = 1; - DECL_EXTERNAL (new_decl) = DECL_EXTERNAL (orig_decl); - TREE_STATIC (new_decl) = TREE_STATIC (orig_decl); - TREE_PUBLIC (new_decl) = TREE_PUBLIC (orig_decl); - TREE_USED (new_decl) = TREE_USED (orig_decl); - DECL_CONTEXT (new_decl) = DECL_CONTEXT (orig_decl); - TREE_THIS_VOLATILE (new_decl) = TREE_THIS_VOLATILE (orig_decl); - TREE_ADDRESSABLE (new_decl) = TREE_ADDRESSABLE (orig_decl); - - if (TREE_CODE (orig_decl) == VAR_DECL) - { - TREE_READONLY (new_decl) = TREE_READONLY (orig_decl); - DECL_TLS_MODEL (new_decl) = DECL_TLS_MODEL (orig_decl); - } -} - -/* This function wraps NEW_STR_TYPE in pointers or arrays wrapper - the same way as a structure type is wrapped in DECL. - It returns the generated type. */ - -static inline tree -gen_struct_type (tree decl, tree new_str_type) -{ - tree type_orig = get_type_of_var (decl); - tree new_type = new_str_type; - VEC (type_wrapper_t, heap) *wrapper = VEC_alloc (type_wrapper_t, heap, 10); - type_wrapper_t wr; - type_wrapper_t *wr_p; - - while (POINTER_TYPE_P (type_orig) - || TREE_CODE (type_orig) == ARRAY_TYPE) - { - if (POINTER_TYPE_P (type_orig)) - { - wr.wrap = 0; - wr.domain = NULL_TREE; - } - else - { - gcc_assert (TREE_CODE (type_orig) == ARRAY_TYPE); - wr.wrap = 1; - wr.domain = TYPE_DOMAIN (type_orig); - } - VEC_safe_push (type_wrapper_t, heap, wrapper, &wr); - type_orig = TREE_TYPE (type_orig); - } - - while (VEC_length (type_wrapper_t, wrapper) != 0) - { - wr_p = VEC_last (type_wrapper_t, wrapper); - - if (wr_p->wrap) /* Array. */ - new_type = build_array_type (new_type, wr_p->domain); - else /* Pointer. */ - new_type = build_pointer_type (new_type); - - VEC_pop (type_wrapper_t, wrapper); - } - - VEC_free (type_wrapper_t, heap, wrapper); - return new_type; -} - -/* This function generates and returns new variable name based on - ORIG_DECL name, combined with index I. - The form of the new name is . . */ - -static tree -gen_var_name (tree orig_decl, unsigned HOST_WIDE_INT i) -{ - const char *old_name; - char *prefix; - char *new_name; - - if (!DECL_NAME (orig_decl) - || !IDENTIFIER_POINTER (DECL_NAME (orig_decl))) - return NULL; - - /* If the original variable has a name, create an - appropriate new name for the new variable. */ - - old_name = IDENTIFIER_POINTER (DECL_NAME (orig_decl)); - prefix = XALLOCAVEC (char, strlen (old_name) + 1); - strcpy (prefix, old_name); - ASM_FORMAT_PRIVATE_NAME (new_name, prefix, i); - return get_identifier (new_name); -} - -/* This function adds NEW_NODE to hashtable of new_var's NEW_VARS_HTAB. */ - -static void -add_to_new_vars_htab (new_var new_node, htab_t new_vars_htab) -{ - void **slot; - - slot = htab_find_slot_with_hash (new_vars_htab, new_node->orig_var, - DECL_UID (new_node->orig_var), - INSERT); - *slot = new_node; -} - -/* This function creates and returns new_var_data node - with empty new_vars and orig_var equal to VAR. */ - -static new_var -create_new_var_node (tree var, d_str str) -{ - new_var node; - - node = XNEW (struct new_var_data); - node->orig_var = var; - node->new_vars = VEC_alloc (tree, heap, VEC_length (tree, str->new_types)); - return node; -} - -/* Check whether the type of VAR is potential candidate for peeling. - Returns true if yes, false otherwise. If yes, TYPE_P will contain - candidate type. If VAR is initialized, the type of VAR will be added - to UNSUITABLE_TYPES. */ - -static bool -is_candidate (tree var, tree *type_p, VEC (tree, heap) **unsuitable_types) -{ - tree type; - bool initialized = false; - - *type_p = NULL; - - if (!var) - return false; - - /* There is no support of initialized vars. */ - if (TREE_CODE (var) == VAR_DECL - && DECL_INITIAL (var) != NULL_TREE) - initialized = true; - - type = get_type_of_var (var); - - if (type) - { - type = TYPE_MAIN_VARIANT (strip_type (type)); - if (TREE_CODE (type) != RECORD_TYPE) - return false; - else - { - if (initialized && unsuitable_types && *unsuitable_types) - { - if (dump_file) - { - fprintf (dump_file, "The type "); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, " is initialized...Excluded."); - } - add_unsuitable_type (unsuitable_types, type); - } - *type_p = type; - return true; - } - } - else - return false; -} - -/* Hash value for field_access_site. */ - -static hashval_t -field_acc_hash (const void *x) -{ - return htab_hash_pointer (((const struct field_access_site *)x)->stmt); -} - -/* This function returns nonzero if stmt of field_access_site X - is equal to Y. */ - -static int -field_acc_eq (const void *x, const void *y) -{ - return ((const struct field_access_site *)x)->stmt == (const_gimple)y; -} - -/* This function prints an access site, defined by SLOT. */ - -static int -dump_acc (void **slot, void *data ATTRIBUTE_UNUSED) -{ - struct access_site *acc = *(struct access_site **) slot; - tree var; - unsigned i; - - fprintf(dump_file, "\n"); - if (acc->stmt) - print_gimple_stmt (dump_file, acc->stmt, 0, 0); - fprintf(dump_file, " : "); - - FOR_EACH_VEC_ELT (tree, acc->vars, i, var) - { - print_generic_expr (dump_file, var, 0); - fprintf(dump_file, ", "); - } - return 1; -} - -/* This function frees memory allocated for structure clusters, - starting from CLUSTER. */ - -static void -free_struct_cluster (struct field_cluster* cluster) -{ - if (cluster) - { - if (cluster->fields_in_cluster) - sbitmap_free (cluster->fields_in_cluster); - if (cluster->sibling) - free_struct_cluster (cluster->sibling); - free (cluster); - } -} - -/* Free all allocated memory under the structure node pointed by D_NODE. */ - -static void -free_data_struct (d_str d_node) -{ - int i; - - if (!d_node) - return; - - if (dump_file) - { - fprintf (dump_file, "\nRemoving data structure \""); - print_generic_expr (dump_file, d_node->decl, 0); - fprintf (dump_file, "\" from data_struct_list."); - } - - /* Free all space under d_node. */ - if (d_node->fields) - { - for (i = 0; i < d_node->num_fields; i++) - free_field_accesses (d_node->fields[i].acc_sites); - free (d_node->fields); - } - - if (d_node->accs) - free_accesses (d_node->accs); - - if (d_node->struct_clustering) - free_struct_cluster (d_node->struct_clustering); - - if (d_node->new_types) - VEC_free (tree, heap, d_node->new_types); -} - -/* This function creates new general and field accesses in BB. */ - -static void -create_new_accesses_in_bb (basic_block bb) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - create_new_accs_for_struct (str, bb); -} - -/* This function adds allocation sites for peeled structures. - M_DATA is vector of allocation sites of function CONTEXT. */ - -static void -create_new_alloc_sites (fallocs_t m_data, tree context) -{ - alloc_site_t *call; - unsigned j; - - FOR_EACH_VEC_ELT (alloc_site_t, m_data->allocs, j, call) - { - gimple stmt = call->stmt; - d_str str = call->str; - tree num; - gimple_seq new_stmts = NULL; - gimple last_stmt = get_final_alloc_stmt (stmt); - unsigned i; - tree type; - - num = gen_num_of_structs_in_malloc (stmt, str->decl, &new_stmts); - if (new_stmts) - { - gimple last_stmt_tmp = gimple_seq_last_stmt (new_stmts); - insert_seq_after_stmt (last_stmt, new_stmts); - last_stmt = last_stmt_tmp; - } - - /* Generate an allocation sites for each new structure type. */ - FOR_EACH_VEC_ELT (tree, str->new_types, i, type) - { - gimple new_malloc_stmt = NULL; - gimple last_stmt_tmp = NULL; - - new_stmts = NULL; - new_malloc_stmt = create_new_malloc (stmt, type, &new_stmts, num); - last_stmt_tmp = gimple_seq_last_stmt (new_stmts); - insert_seq_after_stmt (last_stmt, new_stmts); - update_cgraph_with_malloc_call (new_malloc_stmt, context); - last_stmt = last_stmt_tmp; - } - } -} - -/* This function prints new variables from hashtable - NEW_VARS_HTAB to dump_file. */ - -static void -dump_new_vars (htab_t new_vars_htab) -{ - if (!dump_file) - return; - - if (new_vars_htab) - htab_traverse (new_vars_htab, dump_new_var, NULL); -} - -/* Given an original variable ORIG_DECL of structure type STR, - this function generates new variables of the types defined - by STR->new_type. Generated types are saved in new_var node NODE. - ORIG_DECL should has VAR_DECL tree_code. */ - -static void -create_new_var_1 (tree orig_decl, d_str str, new_var node) -{ - unsigned i; - tree type; - - for (i = 0; - VEC_iterate (tree, str->new_types, i, type); i++) - { - tree new_decl = NULL; - tree new_name; - - new_name = gen_var_name (orig_decl, i); - type = gen_struct_type (orig_decl, type); - - if (is_global_var (orig_decl)) - new_decl = build_decl (DECL_SOURCE_LOCATION (orig_decl), - VAR_DECL, new_name, type); - else - { - const char *name = new_name ? IDENTIFIER_POINTER (new_name) : NULL; - new_decl = create_tmp_var (type, name); - } - - copy_decl_attributes (new_decl, orig_decl); - VEC_safe_push (tree, heap, node->new_vars, new_decl); - } -} - -/* This function creates new variables to - substitute the original variable VAR_DECL and adds - them to the new_var's hashtable NEW_VARS_HTAB. */ - -static void -create_new_var (tree var_decl, htab_t new_vars_htab) -{ - new_var node; - d_str str; - tree type; - unsigned i; - - if (!var_decl || is_in_new_vars_htab (var_decl, new_vars_htab)) - return; - - if (!is_candidate (var_decl, &type, NULL)) - return; - - i = find_structure (type); - if (i == VEC_length (structure, structures)) - return; - - str = VEC_index (structure, structures, i); - node = create_new_var_node (var_decl, str); - create_new_var_1 (var_decl, str, node); - add_to_new_vars_htab (node, new_vars_htab); -} - -/* Hash value for new_var. */ - -static hashval_t -new_var_hash (const void *x) -{ - return DECL_UID (((const_new_var)x)->orig_var); -} - -/* This function returns nonzero if orig_var of new_var X - and tree Y have equal UIDs. */ - -static int -new_var_eq (const void *x, const void *y) -{ - if (DECL_P ((const_tree)y)) - return DECL_UID (((const_new_var)x)->orig_var) == DECL_UID ((const_tree)y); - else - return 0; -} - -/* This function check whether a structure type represented by STR - escapes due to ipa-type-escape analysis. If yes, this type is added - to UNSUITABLE_TYPES vector. */ - -static void -check_type_escape (d_str str, VEC (tree, heap) **unsuitable_types) -{ - tree type = str->decl; - - if (!ipa_type_escape_type_contained_p (type)) - { - if (dump_file) - { - fprintf (dump_file, "\nEscaping type is "); - print_generic_expr (dump_file, type, 0); - } - add_unsuitable_type (unsuitable_types, type); - } -} - -/* Hash value for access_site. */ - -static hashval_t -acc_hash (const void *x) -{ - return htab_hash_pointer (((const struct access_site *)x)->stmt); -} - -/* Return nonzero if stmt of access_site X is equal to Y. */ - -static int -acc_eq (const void *x, const void *y) -{ - return ((const struct access_site *)x)->stmt == (const_gimple)y; -} - -/* Given a structure declaration STRUCT_DECL, and number of fields - in the structure NUM_FIELDS, this function creates and returns - corresponding field_entry's. */ - -static struct field_entry * -get_fields (tree struct_decl, int num_fields) -{ - struct field_entry *list; - tree t = TYPE_FIELDS (struct_decl); - int idx = 0; - - list = XNEWVEC (struct field_entry, num_fields); - - for (idx = 0 ; t; t = TREE_CHAIN (t), idx++) - if (TREE_CODE (t) == FIELD_DECL) - { - list[idx].index = idx; - list[idx].decl = t; - list[idx].acc_sites = - htab_create (32, field_acc_hash, field_acc_eq, NULL); - list[idx].count = 0; - list[idx].field_mapping = NULL_TREE; - } - - return list; -} - -/* Print non-field accesses from hashtable ACCS of structure. */ - -static void -dump_access_sites (htab_t accs) -{ - if (!dump_file) - return; - - if (accs) - htab_traverse (accs, dump_acc, NULL); -} - -/* This function is a callback for alloc_sites hashtable - traversal. SLOT is a pointer to fallocs_t. This function - removes all allocations of the structure defined by DATA. */ - -static int -remove_str_allocs_in_func (void **slot, void *data) -{ - fallocs_t fallocs = *(fallocs_t *) slot; - unsigned i = 0; - alloc_site_t *call; - - while (VEC_iterate (alloc_site_t, fallocs->allocs, i, call)) - { - if (call->str == (d_str) data) - VEC_ordered_remove (alloc_site_t, fallocs->allocs, i); - else - i++; - } - - return 1; -} - -/* This function remove all entries corresponding to the STR structure - from alloc_sites hashtable. */ - -static void -remove_str_allocs (d_str str) -{ - if (!str) - return; - - if (alloc_sites) - htab_traverse (alloc_sites, remove_str_allocs_in_func, str); -} - -/* This function removes the structure with index I from structures vector. */ - -static void -remove_structure (unsigned i) -{ - d_str str; - - if (i >= VEC_length (structure, structures)) - return; - - str = VEC_index (structure, structures, i); - - /* Before removing the structure str, we have to remove its - allocations from alloc_sites hashtable. */ - remove_str_allocs (str); - free_data_struct (str); - VEC_ordered_remove (structure, structures, i); -} - -/* Currently we support only EQ_EXPR or NE_EXPR conditions. - COND_STMT is a condition statement to check. */ - -static bool -is_safe_cond_expr (gimple cond_stmt) -{ - tree arg0, arg1; - unsigned str0, str1; - bool s0, s1; - unsigned length = VEC_length (structure, structures); - - if (gimple_cond_code (cond_stmt) != EQ_EXPR - && gimple_cond_code (cond_stmt) != NE_EXPR) - return false; - - arg0 = gimple_cond_lhs (cond_stmt); - arg1 = gimple_cond_rhs (cond_stmt); - - str0 = find_structure (strip_type (get_type_of_var (arg0))); - str1 = find_structure (strip_type (get_type_of_var (arg1))); - - s0 = (str0 != length) ? true : false; - s1 = (str1 != length) ? true : false; - - if (!s0 && !s1) - return false; - - /* For now we allow only comparison with 0 or NULL. */ - if (!integer_zerop (arg0) && !integer_zerop (arg1)) - return false; - - return true; -} - -/* This function excludes statements, that are - part of allocation sites or field accesses, from the - hashtable of general accesses. SLOT represents general - access that will be checked. DATA is a pointer to - exclude_data structure. */ - -static int -exclude_from_accs (void **slot, void *data) -{ - struct access_site *acc = *(struct access_site **) slot; - tree fn_decl = ((struct exclude_data *)data)->fn_decl; - d_str str = ((struct exclude_data *)data)->str; - - if (is_part_of_malloc (acc->stmt, fn_decl) - || is_part_of_field_access (acc->stmt, str)) - { - VEC_free (tree, heap, acc->vars); - free (acc); - htab_clear_slot (str->accs, slot); - } - return 1; -} - -/* Callback function for walk_tree called from collect_accesses_in_bb - function. DATA is the statement which is analyzed. */ - -static tree -get_stmt_accesses (tree *tp, int *walk_subtrees, void *data) -{ - struct walk_stmt_info *wi = (struct walk_stmt_info *) data; - gimple stmt = (gimple) wi->info; - tree t = *tp; - - if (!t) - return NULL; - - switch (TREE_CODE (t)) - { - case BIT_FIELD_REF: - { - tree var = TREE_OPERAND(t, 0); - tree type = TYPE_MAIN_VARIANT (strip_type (get_type_of_var (var))); - unsigned i = find_structure (type); - - if (i != VEC_length (structure, structures)) - { - if (is_gimple_debug (stmt)) - { - d_str str; - - str = VEC_index (structure, structures, i); - add_access_to_acc_sites (stmt, NULL, str->accs); - *walk_subtrees = 0; - break; - } - if (dump_file) - { - fprintf (dump_file, "\nThe type "); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, " has bitfield."); - } - remove_structure (i); - } - } - break; - - case COMPONENT_REF: - { - tree ref = TREE_OPERAND (t, 0); - tree field_decl = TREE_OPERAND (t, 1); - - - if ((TREE_CODE (ref) == MEM_REF - || TREE_CODE (ref) == ARRAY_REF - || TREE_CODE (ref) == VAR_DECL) - && TREE_CODE (field_decl) == FIELD_DECL) - { - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ref)); - unsigned i = find_structure (type); - - if (i != VEC_length (structure, structures)) - { - d_str str = VEC_index (structure, structures, i); - struct field_entry * field = - find_field_in_struct (str, field_decl); - - if (is_gimple_debug (stmt)) - { - add_access_to_acc_sites (stmt, NULL, str->accs); - *walk_subtrees = 0; - break; - } - - if (field) - { - struct field_access_site *acc = make_field_acc_node (); - - gcc_assert (acc); - - acc->stmt = stmt; - acc->comp_ref = t; - acc->ref = ref; - acc->field_decl = field_decl; - - /* Check whether the access is of the form - we can deal with. */ - if (!decompose_access (str->decl, acc)) - { - if (dump_file) - { - fprintf (dump_file, "\nThe type "); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, - " has complicate access in statement "); - print_gimple_stmt (dump_file, stmt, 0, 0); - } - - remove_structure (i); - free (acc); - } - else - { - /* Increase count of field. */ - basic_block bb = gimple_bb (stmt); - field->count += bb->count; - - /* Add stmt to the acc_sites of field. */ - add_field_acc_to_acc_sites (acc, field->acc_sites); - } - *walk_subtrees = 0; - } - } - } - } - break; - - case COND_EXPR: - { - tree cond = COND_EXPR_COND (t); - int i; - for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (cond)); i++) - { - tree t = TREE_OPERAND (cond, i); - - *walk_subtrees = 1; - walk_tree (&t, get_stmt_accesses, data, NULL); - } - *walk_subtrees = 0; - } - break; - - case VAR_DECL: - case SSA_NAME: - { - unsigned i; - - if (TREE_CODE (t) == SSA_NAME) - t = SSA_NAME_VAR (t); - - i = find_structure (strip_type (get_type_of_var (t))); - if (i != VEC_length (structure, structures)) - { - d_str str; - - str = VEC_index (structure, structures, i); - add_access_to_acc_sites (stmt, t, str->accs); - } - *walk_subtrees = 0; - } - break; - - default: - return NULL; - } - - return NULL; -} - -/* Free structures hashtable. */ - -static void -free_structures (void) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - free_data_struct (str); - - VEC_free (structure, heap, structures); - structures = NULL; -} - -/* This function is a callback for traversal over new_var's hashtable. - SLOT is a pointer to new_var. This function frees memory allocated - for new_var and pointed by *SLOT. */ - -static int -free_new_var (void **slot, void *data ATTRIBUTE_UNUSED) -{ - new_var n_var = *(new_var *) slot; - - /* Free vector of new_vars. */ - VEC_free (tree, heap, n_var->new_vars); - free (n_var); - return 1; -} - -/* Free new_vars hashtable NEW_VARS_HTAB. */ - -static void -free_new_vars_htab (htab_t new_vars_htab) -{ - if (new_vars_htab) - htab_traverse (new_vars_htab, free_new_var, NULL); - htab_delete (new_vars_htab); - new_vars_htab = NULL; -} - -/* This function creates new general and field accesses that appear in cfun. */ - -static void -create_new_accesses_for_func (void) -{ - basic_block bb; - - FOR_EACH_BB_FN (bb, cfun) - create_new_accesses_in_bb (bb); -} - -/* Create new allocation sites for the function represented by NODE. */ - -static void -create_new_alloc_sites_for_func (struct cgraph_node *node) -{ - fallocs_t fallocs = get_fallocs (node->decl); - - if (fallocs) - create_new_alloc_sites (fallocs, node->decl); -} - -/* For each local variable of structure type from the vector of structures - this function generates new variable(s) to replace it. */ - -static void -create_new_local_vars (void) -{ - tree var; - referenced_var_iterator rvi; - - new_local_vars = htab_create (num_referenced_vars, - new_var_hash, new_var_eq, NULL); - - FOR_EACH_REFERENCED_VAR (cfun, var, rvi) - { - if (!is_global_var (var)) - create_new_var (var, new_local_vars); - } - - if (new_local_vars) - htab_traverse (new_local_vars, finalize_new_vars_creation, NULL); - dump_new_vars (new_local_vars); -} - -/* This function prints the SHIFT number of spaces to the DUMP_FILE. */ - -static inline void -print_shift (unsigned HOST_WIDE_INT shift) -{ - unsigned HOST_WIDE_INT sh = shift; - - while (sh--) - fprintf (dump_file, " "); -} - -/* This function updates field_mapping of FIELDS in CLUSTER with NEW_TYPE. */ - -static inline void -update_fields_mapping (struct field_cluster *cluster, tree new_type, - struct field_entry * fields, int num_fields) -{ - int i; - - for (i = 0; i < num_fields; i++) - if (TEST_BIT (cluster->fields_in_cluster, i)) - fields[i].field_mapping = new_type; -} - -/* This functions builds structure with FIELDS, - NAME and attributes similar to ORIG_STRUCT. - It returns the newly created structure. */ - -static tree -build_basic_struct (tree fields, tree name, tree orig_struct) -{ - tree attributes = NULL_TREE; - tree ref = 0; - tree x; - - if (TYPE_ATTRIBUTES (orig_struct)) - attributes = unshare_expr (TYPE_ATTRIBUTES (orig_struct)); - ref = make_node (RECORD_TYPE); - TYPE_SIZE (ref) = 0; - decl_attributes (&ref, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); - TYPE_PACKED (ref) = TYPE_PACKED (orig_struct); - for (x = fields; x; x = TREE_CHAIN (x)) - { - DECL_CONTEXT (x) = ref; - DECL_PACKED (x) |= TYPE_PACKED (ref); - } - TYPE_FIELDS (ref) = fields; - layout_type (ref); - TYPE_NAME (ref) = name; - - return ref; -} - -/* This function copies FIELDS from CLUSTER into TREE_CHAIN as part - of preparation for new structure building. NUM_FIELDS is a total - number of fields in the structure. The function returns newly - generated fields. */ - -static tree -create_fields (struct field_cluster * cluster, - struct field_entry * fields, int num_fields) -{ - int i; - tree new_types = NULL_TREE; - tree last = NULL_TREE; - - for (i = 0; i < num_fields; i++) - if (TEST_BIT (cluster->fields_in_cluster, i)) - { - tree new_decl = unshare_expr (fields[i].decl); - - if (!new_types) - new_types = new_decl; - else - TREE_CHAIN (last) = new_decl; - last = new_decl; - } - - TREE_CHAIN (last) = NULL_TREE; - return new_types; - -} - -/* This function creates a cluster name. The name is based on - the original structure name, if it is present. It has a form: - - _sub. - - The original structure name is taken from the type of DECL. - If an original structure name is not present, it's generated to be: - - struct. - - The function returns identifier of the new cluster name. */ - -static inline tree -gen_cluster_name (tree decl, int clust_num, int str_num) -{ - const char * orig_name = get_type_name (decl); - char * tmp_name = NULL; - char * prefix; - char * new_name; - size_t len; - - if (!orig_name) - ASM_FORMAT_PRIVATE_NAME(tmp_name, "struct", str_num); - - len = strlen (tmp_name ? tmp_name : orig_name) + strlen ("_sub"); - prefix = XALLOCAVEC (char, len + 1); - memcpy (prefix, tmp_name ? tmp_name : orig_name, - strlen (tmp_name ? tmp_name : orig_name)); - strcpy (prefix + strlen (tmp_name ? tmp_name : orig_name), "_sub"); - - ASM_FORMAT_PRIVATE_NAME (new_name, prefix, clust_num); - return get_identifier (new_name); -} - -/* This function checks whether the structure STR has bitfields. - If yes, this structure type is added to UNSUITABLE_TYPES vector. */ - -static void -check_bitfields (d_str str, VEC (tree, heap) **unsuitable_types) -{ - tree type = str->decl; - int i; - - for (i = 0; i < str->num_fields; i++) - if (DECL_BIT_FIELD (str->fields[i].decl)) - { - add_unsuitable_type (unsuitable_types, type); - if (dump_file) - { - fprintf (dump_file, "\nType "); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, "\nescapes due to bitfield "); - print_generic_expr (dump_file, str->fields[i].decl, 0); - } - break; - } -} - -/* This function adds to UNSUITABLE_TYPES those types that escape - due to results of ipa-type-escape analysis. See ipa-type-escape.[c,h]. */ - -static void -exclude_escaping_types_1 (VEC (tree, heap) **unsuitable_types) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - check_type_escape (str, unsuitable_types); -} - -/* If a structure type is a return type of any function, - we cannot transform it. Such type is added to UNSUITABLE_TYPES vector. */ - -static void -exclude_returned_types (VEC (tree, heap) **unsuitable_types) -{ - struct cgraph_node *c_node; - - for (c_node = cgraph_nodes; c_node; c_node = c_node->next) - { - tree ret_t = TREE_TYPE (TREE_TYPE (c_node->decl)); - - if (ret_t) - { - ret_t = strip_type (ret_t); - if (TREE_CODE (ret_t) == RECORD_TYPE) - { - add_unsuitable_type (unsuitable_types, TYPE_MAIN_VARIANT (ret_t)); - if (dump_file) - { - fprintf (dump_file, "\nThe type \""); - print_generic_expr (dump_file, ret_t, 0); - fprintf (dump_file, - "\" is return type of function...Excluded."); - } - } - } - } -} - -/* This function looks for parameters of local functions - which are of structure types, or derived from them (arrays - of structures, pointers to structures, or their combinations). - We are not handling peeling of such structures right now. - The found structures types are added to UNSUITABLE_TYPES vector. */ - -static void -exclude_types_passed_to_local_func (VEC (tree, heap) **unsuitable_types) -{ - struct cgraph_node *c_node; - - for (c_node = cgraph_nodes; c_node; c_node = c_node->next) - if (cgraph_function_body_availability (c_node) == AVAIL_LOCAL) - { - tree fn = c_node->decl; - tree arg; - - for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg)) - { - tree type = TREE_TYPE (arg); - - type = strip_type (type); - if (TREE_CODE (type) == RECORD_TYPE) - { - add_unsuitable_type (unsuitable_types, - TYPE_MAIN_VARIANT (type)); - if (dump_file) - { - fprintf (dump_file, "\nPointer to type \""); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, - "\" is passed to local function...Excluded."); - } - } - } - } -} - -/* This function analyzes structure form of structures - potential for transformation. If we are not capable to transform - structure of some form, we remove it from the structures hashtable. - Right now we cannot handle nested structs, when nesting is - through any level of pointers or arrays. - - TBD: release these constrains in future. - - Note, that in this function we suppose that all structures - in the program are members of the structures hashtable right now, - without excluding escaping types. */ - -static void -check_struct_form (d_str str, VEC (tree, heap) **unsuitable_types) -{ - int i; - - for (i = 0; i < str->num_fields; i++) - { - tree f_type = strip_type(TREE_TYPE (str->fields[i].decl)); - - if (TREE_CODE (f_type) == RECORD_TYPE) - { - add_unsuitable_type (unsuitable_types, TYPE_MAIN_VARIANT (f_type)); - add_unsuitable_type (unsuitable_types, str->decl); - if (dump_file) - { - fprintf (dump_file, "\nType "); - print_generic_expr (dump_file, f_type, 0); - fprintf (dump_file, " is a field in the structure "); - print_generic_expr (dump_file, str->decl, 0); - fprintf (dump_file, ". Escaping..."); - } - } - } -} - -/* This function adds a structure TYPE to the vector of structures, - if it's not already there. */ - -static void -add_structure (tree type) -{ - struct data_structure node; - unsigned i; - int num_fields; - - type = TYPE_MAIN_VARIANT (type); - - i = find_structure (type); - - if (i != VEC_length (structure, structures)) - return; - - num_fields = fields_length (type); - node.decl = type; - node.num_fields = num_fields; - node.fields = get_fields (type, num_fields); - node.struct_clustering = NULL; - node.accs = htab_create (32, acc_hash, acc_eq, NULL); - node.new_types = VEC_alloc (tree, heap, num_fields); - node.count = 0; - - VEC_safe_push (structure, heap, structures, &node); - - if (dump_file) - { - fprintf (dump_file, "\nAdding data structure \""); - print_generic_expr (dump_file, type, 0); - fprintf (dump_file, "\" to data_struct_list."); - } -} - -/* This function adds an allocation site to alloc_sites hashtable. - The allocation site appears in STMT of function FN_DECL and - allocates the structure represented by STR. */ - -static void -add_alloc_site (tree fn_decl, gimple stmt, d_str str) -{ - fallocs_t fallocs = NULL; - alloc_site_t m_call; - - m_call.stmt = stmt; - m_call.str = str; - - fallocs = - (fallocs_t) htab_find_with_hash (alloc_sites, - fn_decl, htab_hash_pointer (fn_decl)); - - if (!fallocs) - { - void **slot; - - fallocs = XNEW (struct func_alloc_sites); - fallocs->func = fn_decl; - fallocs->allocs = VEC_alloc (alloc_site_t, heap, 1); - slot = htab_find_slot_with_hash (alloc_sites, fn_decl, - htab_hash_pointer (fn_decl), INSERT); - *slot = fallocs; - } - VEC_safe_push (alloc_site_t, heap, - fallocs->allocs, &m_call); - - if (dump_file) - { - fprintf (dump_file, "\nAdding stmt "); - print_gimple_stmt (dump_file, stmt, 0, 0); - fprintf (dump_file, " to list of mallocs."); - } -} - -/* This function returns true if the result of STMT, that contains a call - to an allocation function, is cast to one of the structure types. - STMT should be of the form: T.2 = (T.1); - If true, I_P contains an index of an allocated structure. - Otherwise I_P contains the length of the vector of structures. */ - -static bool -is_alloc_of_struct (gimple stmt, unsigned *i_p) -{ - tree lhs; - tree type; - gimple final_stmt; - - final_stmt = get_final_alloc_stmt (stmt); - - if (!final_stmt) - return false; - - /* final_stmt should be of the form: - T.3 = (struct_type *) T.2; */ - - if (gimple_code (final_stmt) != GIMPLE_ASSIGN) - return false; - - lhs = gimple_assign_lhs (final_stmt); - - type = get_type_of_var (lhs); - - if (!type) - return false; - - if (!POINTER_TYPE_P (type) - || TREE_CODE (strip_type (type)) != RECORD_TYPE) - return false; - - *i_p = find_structure (strip_type (type)); - - if (*i_p == VEC_length (structure, structures)) - return false; - - return true; -} - -/* This function prints non-field and field accesses - of the structure STR. */ - -static void -dump_accs (d_str str) -{ - int i; - - fprintf (dump_file, "\nAccess sites of struct "); - print_generic_expr (dump_file, str->decl, 0); - - for (i = 0; i < str->num_fields; i++) - { - fprintf (dump_file, "\nAccess site of field "); - print_generic_expr (dump_file, str->fields[i].decl, 0); - dump_field_acc_sites (str->fields[i].acc_sites); - fprintf (dump_file, ":\n"); - } - fprintf (dump_file, "\nGeneral access sites\n"); - dump_access_sites (str->accs); -} - -/* This function checks whether an access statement, pointed by SLOT, - is a condition we are capable to transform. It returns false if not, - setting bool *DATA to false. */ - -static int -safe_cond_expr_check (void **slot, void *data) -{ - struct access_site *acc = *(struct access_site **) slot; - - if (gimple_code (acc->stmt) == GIMPLE_COND - && !is_safe_cond_expr (acc->stmt)) - { - if (dump_file) - { - fprintf (dump_file, "\nUnsafe conditional statement "); - print_gimple_stmt (dump_file, acc->stmt, 0, 0); - } - *(bool *) data = false; - return 0; - } - return 1; -} - -/* This function excludes statements that are part of allocation sites and - field accesses from the hashtable of general accesses of the structure - type STR. Only accesses that belong to the function represented by - NODE are treated. */ - -static void -exclude_alloc_and_field_accs_1 (d_str str, struct cgraph_node *node) -{ - struct exclude_data dt; - dt.str = str; - dt.fn_decl = node->decl; - - if (dt.str->accs) - htab_traverse (dt.str->accs, exclude_from_accs, &dt); -} - -/* Collect accesses to the structure types that appear in basic block BB. */ - -static void -collect_accesses_in_bb (basic_block bb) -{ - gimple_stmt_iterator bsi; - struct walk_stmt_info wi; - - memset (&wi, 0, sizeof (wi)); - - for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) - { - gimple stmt = gsi_stmt (bsi); - - /* In asm stmt we cannot always track the arguments, - so we just give up. */ - if (gimple_code (stmt) == GIMPLE_ASM) - { - free_structures (); - break; - } - - wi.info = (void *) stmt; - walk_gimple_op (stmt, get_stmt_accesses, &wi); - } -} - -/* This function generates cluster substructure that contains FIELDS. - The cluster added to the set of clusters of the structure STR. */ - -static void -gen_cluster (sbitmap fields, d_str str) -{ - struct field_cluster *crr_cluster = XCNEW (struct field_cluster); - - crr_cluster->sibling = str->struct_clustering; - str->struct_clustering = crr_cluster; - crr_cluster->fields_in_cluster = fields; -} - -/* This function peels a field with the index I from the structure DS. */ - -static void -peel_field (int i, d_str ds) -{ - struct field_cluster *crr_cluster = XCNEW (struct field_cluster); - - crr_cluster->sibling = ds->struct_clustering; - ds->struct_clustering = crr_cluster; - crr_cluster->fields_in_cluster = - sbitmap_alloc ((unsigned int) ds->num_fields); - sbitmap_zero (crr_cluster->fields_in_cluster); - SET_BIT (crr_cluster->fields_in_cluster, i); -} - -/* This function calculates maximum field count in - the structure STR. */ - -static gcov_type -get_max_field_count (d_str str) -{ - gcov_type max = 0; - int i; - - for (i = 0; i < str->num_fields; i++) - if (str->fields[i].count > max) - max = str->fields[i].count; - - return max; -} - -/* Do struct-reorg transformation for individual function - represented by NODE. All structure types relevant - for this function are transformed. */ - -static void -do_reorg_for_func (struct cgraph_node *node) -{ - create_new_local_vars (); - create_new_alloc_sites_for_func (node); - create_new_accesses_for_func (); - update_ssa (TODO_update_ssa); - cleanup_tree_cfg (); - cgraph_rebuild_references (); - - /* Free auxiliary data representing local variables. */ - free_new_vars_htab (new_local_vars); -} - -/* Print structure TYPE, its name, if it exists, and body. - INDENT defines the level of indentation (similar - to the option -i of indent command). SHIFT parameter - defines a number of spaces by which a structure will - be shifted right. */ - -static void -dump_struct_type (tree type, unsigned HOST_WIDE_INT indent, - unsigned HOST_WIDE_INT shift) -{ - const char *struct_name; - tree field; - - if (!type || !dump_file) - return; - - if (TREE_CODE (type) != RECORD_TYPE) - { - print_generic_expr (dump_file, type, 0); - return; - } - - print_shift (shift); - struct_name = get_type_name (type); - fprintf (dump_file, "struct "); - if (struct_name) - fprintf (dump_file, "%s\n",struct_name); - print_shift (shift); - fprintf (dump_file, "{\n"); - - for (field = TYPE_FIELDS (type); field; - field = TREE_CHAIN (field)) - { - unsigned HOST_WIDE_INT s = indent; - tree f_type = TREE_TYPE (field); - - print_shift (shift); - while (s--) - fprintf (dump_file, " "); - dump_struct_type (f_type, indent, shift + indent); - fprintf(dump_file, " "); - print_generic_expr (dump_file, field, 0); - fprintf(dump_file, ";\n"); - } - print_shift (shift); - fprintf (dump_file, "}\n"); -} - -/* This function creates new structure types to replace original type, - indicated by STR->decl. The names of the new structure types are - derived from the original structure type. If the original structure - type has no name, we assume that its name is 'struct.'. */ - -static void -create_new_type (d_str str, int *str_num) -{ - int cluster_num = 0; - - struct field_cluster *cluster = str->struct_clustering; - while (cluster) - { - tree name = gen_cluster_name (str->decl, cluster_num, - *str_num); - tree fields; - tree new_type; - cluster_num++; - - fields = create_fields (cluster, str->fields, - str->num_fields); - new_type = build_basic_struct (fields, name, str->decl); - - update_fields_mapping (cluster, new_type, - str->fields, str->num_fields); - - VEC_safe_push (tree, heap, str->new_types, new_type); - cluster = cluster->sibling; - } - (*str_num)++; -} - -/* This function is a callback for alloc_sites hashtable - traversal. SLOT is a pointer to fallocs_t. - This function frees memory pointed by *SLOT. */ - -static int -free_falloc_sites (void **slot, void *data ATTRIBUTE_UNUSED) -{ - fallocs_t fallocs = *(fallocs_t *) slot; - - VEC_free (alloc_site_t, heap, fallocs->allocs); - free (fallocs); - return 1; -} - -/* Remove structures collected in UNSUITABLE_TYPES - from structures vector. */ - -static void -remove_unsuitable_types (VEC (tree, heap) *unsuitable_types) -{ - d_str str; - tree type; - unsigned i, j; - - FOR_EACH_VEC_ELT (tree, unsuitable_types, j, type) - FOR_EACH_VEC_ELT (structure, structures, i, str) - if (is_equal_types (str->decl, type)) - { - remove_structure (i); - break; - } -} - -/* Exclude structure types with bitfields. - We would not want to interfere with other optimizations - that can be done in this case. The structure types with - bitfields are added to UNSUITABLE_TYPES vector. */ - -static void -exclude_types_with_bit_fields (VEC (tree, heap) **unsuitable_types) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - check_bitfields (str, unsuitable_types); -} - -/* This function checks three types of escape. A structure type escapes: - - 1. if it's a type of parameter of a local function. - 2. if it's a type of function return value. - 3. if it escapes as a result of ipa-type-escape analysis. - - The escaping structure types are added to UNSUITABLE_TYPES vector. */ - -static void -exclude_escaping_types (VEC (tree, heap) **unsuitable_types) -{ - exclude_types_passed_to_local_func (unsuitable_types); - exclude_returned_types (unsuitable_types); - exclude_escaping_types_1 (unsuitable_types); -} - -/* This function analyzes whether the form of - structure is such that we are capable to transform it. - Nested structures are checked here. Unsuitable structure - types are added to UNSUITABLE_TYPE vector. */ - -static void -analyze_struct_form (VEC (tree, heap) **unsuitable_types) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - check_struct_form (str, unsuitable_types); -} - -/* This function looks for structure types instantiated in the program. - The candidate types are added to the structures vector. - Unsuitable types are collected into UNSUITABLE_TYPES vector. */ - -static void -build_data_structure (VEC (tree, heap) **unsuitable_types) -{ - tree var, type; - struct varpool_node *current_varpool; - struct cgraph_node *c_node; - - /* Check global variables. */ - FOR_EACH_STATIC_VARIABLE (current_varpool) - { - var = current_varpool->decl; - if (is_candidate (var, &type, unsuitable_types)) - add_structure (type); - } - - /* Now add structures that are types of function parameters and - local variables. */ - for (c_node = cgraph_nodes; c_node; c_node = c_node->next) - { - enum availability avail = - cgraph_function_body_availability (c_node); - - /* We need AVAIL_AVAILABLE for main function. */ - if (avail == AVAIL_LOCAL || avail == AVAIL_AVAILABLE) - { - struct function *fn = DECL_STRUCT_FUNCTION (c_node->decl); - unsigned ix; - - for (var = DECL_ARGUMENTS (c_node->decl); var; - var = TREE_CHAIN (var)) - if (is_candidate (var, &type, unsuitable_types)) - add_structure (type); - - if (fn == NULL) - { - /* Skip cones that haven't been materialized yet. */ - gcc_assert (c_node->clone_of - && c_node->clone_of->decl != c_node->decl); - continue; - } - - /* Check function local variables. */ - FOR_EACH_LOCAL_DECL (fn, ix, var) - if (is_candidate (var, &type, unsuitable_types)) - add_structure (type); - } - } -} - -/* This function returns true if the program contains - a call to user defined allocation function, or other - functions that can interfere with struct-reorg optimizations. */ - -static bool -program_redefines_malloc_p (void) -{ - struct cgraph_node *c_node; - struct cgraph_node *c_node2; - struct cgraph_edge *c_edge; - tree fndecl2; - - for (c_node = cgraph_nodes; c_node; c_node = c_node->next) - { - for (c_edge = c_node->callees; c_edge; c_edge = c_edge->next_callee) - { - c_node2 = c_edge->callee; - fndecl2 = c_node2->decl; - if (is_gimple_call (c_edge->call_stmt)) - { - const char * fname = get_name (fndecl2); - - if ((gimple_call_flags (c_edge->call_stmt) & ECF_MALLOC) - && (DECL_FUNCTION_CODE (fndecl2) != BUILT_IN_MALLOC) - && (DECL_FUNCTION_CODE (fndecl2) != BUILT_IN_CALLOC) - && (DECL_FUNCTION_CODE (fndecl2) != BUILT_IN_ALLOCA)) - return true; - - /* Check that there is no __builtin_object_size, - __builtin_offsetof, or realloc's in the program. */ - if (DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_OBJECT_SIZE - || !strcmp (fname, "__builtin_offsetof") - || !strcmp (fname, "realloc")) - return true; - } - } - } - - return false; -} - -/* In this function we assume that an allocation statement - - var = (type_cast) malloc (size); - - is converted into the following set of statements: - - T.1 = size; - T.2 = malloc (T.1); - T.3 = (type_cast) T.2; - var = T.3; - - In this function we collect into alloc_sites the allocation - sites of variables of structure types that are present - in structures vector. */ - -static void -collect_alloc_sites (void) -{ - struct cgraph_node *node; - struct cgraph_edge *cs; - - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && node->decl) - { - for (cs = node->callees; cs; cs = cs->next_callee) - { - gimple stmt = cs->call_stmt; - - if (stmt) - { - tree decl; - - if (is_gimple_call (stmt) - && (decl = gimple_call_fndecl (stmt)) - && gimple_call_lhs (stmt)) - { - unsigned i; - - if (is_alloc_of_struct (stmt, &i)) - { - /* We support only malloc now. */ - if (DECL_FUNCTION_CODE (decl) == BUILT_IN_MALLOC) - { - d_str str; - - str = VEC_index (structure, structures, i); - add_alloc_site (node->decl, stmt, str); - } - else - { - if (dump_file) - { - fprintf (dump_file, - "\nUnsupported allocation function "); - print_gimple_stmt (dump_file, stmt, 0, 0); - } - remove_structure (i); - } - } - } - } - } - } -} - -/* Print collected accesses. */ - -static void -dump_accesses (void) -{ - d_str str; - unsigned i; - - if (!dump_file) - return; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - dump_accs (str); -} - -/* This function checks whether the accesses of structures in condition - expressions are of the kind we are capable to transform. - If not, such structures are removed from the vector of structures. */ - -static void -check_cond_exprs (void) -{ - d_str str; - unsigned i; - - i = 0; - while (VEC_iterate (structure, structures, i, str)) - { - bool safe_p = true; - - if (str->accs) - htab_traverse (str->accs, safe_cond_expr_check, &safe_p); - if (!safe_p) - remove_structure (i); - else - i++; - } -} - -/* We exclude from non-field accesses of the structure - all statements that will be treated as part of the structure - allocation sites or field accesses. */ - -static void -exclude_alloc_and_field_accs (struct cgraph_node *node) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - exclude_alloc_and_field_accs_1 (str, node); -} - -/* This function collects accesses of the fields of the structures - that appear at function FN. */ - -static void -collect_accesses_in_func (struct function *fn) -{ - basic_block bb; - - if (! fn) - return; - - /* Collect accesses for each basic blocks separately. */ - FOR_EACH_BB_FN (bb, fn) - collect_accesses_in_bb (bb); -} - -/* This function summarizes counts of the fields into the structure count. */ - -static void -sum_counts (d_str str, gcov_type *hottest) -{ - int i; - - str->count = 0; - for (i = 0; i < str->num_fields; i++) - { - if (dump_file) - { - fprintf (dump_file, "\nCounter of field \""); - print_generic_expr (dump_file, str->fields[i].decl, 0); - fprintf (dump_file, "\" is " HOST_WIDEST_INT_PRINT_DEC, - str->fields[i].count); - } - str->count += str->fields[i].count; - } - - if (dump_file) - { - fprintf (dump_file, "\nCounter of struct \""); - print_generic_expr (dump_file, str->decl, 0); - fprintf (dump_file, "\" is " HOST_WIDEST_INT_PRINT_DEC, str->count); - } - - if (str->count > *hottest) - *hottest = str->count; -} - -/* This function peels the field into separate structure if it's - sufficiently hot, i.e. if its count provides at least 90% of - the maximum field count in the structure. */ - -static void -peel_hot_fields (d_str str) -{ - gcov_type max_field_count; - sbitmap fields_left = sbitmap_alloc (str->num_fields); - int i; - - sbitmap_ones (fields_left); - max_field_count = - (gcov_type) (get_max_field_count (str)/100)*90; - - str->struct_clustering = NULL; - - for (i = 0; i < str->num_fields; i++) - { - if (str->count >= max_field_count) - { - RESET_BIT (fields_left, i); - peel_field (i, str); - } - } - - i = sbitmap_first_set_bit (fields_left); - if (i != -1) - gen_cluster (fields_left, str); - else - sbitmap_free (fields_left); -} - -/* This function is a helper for do_reorg. It goes over - functions in call graph and performs actual transformation - on them. */ - -static void -do_reorg_1 (void) -{ - struct cgraph_node *node; - - /* Initialize the default bitmap obstack. */ - bitmap_obstack_initialize (NULL); - - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && node->decl) - { - push_cfun (DECL_STRUCT_FUNCTION (node->decl)); - current_function_decl = node->decl; - if (dump_file) - fprintf (dump_file, "\nFunction to do reorg is %s: \n", - (const char *) IDENTIFIER_POINTER (DECL_NAME (node->decl))); - do_reorg_for_func (node); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - current_function_decl = NULL; - pop_cfun (); - } - - set_cfun (NULL); - bitmap_obstack_release (NULL); -} - -/* This function creates new global struct variables. - For each original variable, the set of new variables - is created with the new structure types corresponding - to the structure type of original variable. - Only VAR_DECL variables are treated by this function. */ - -static void -create_new_global_vars (void) -{ - struct varpool_node *current_varpool; - unsigned HOST_WIDE_INT i; - unsigned HOST_WIDE_INT varpool_size = 0; - - for (i = 0; i < 2; i++) - { - if (i) - new_global_vars = htab_create (varpool_size, - new_var_hash, new_var_eq, NULL); - FOR_EACH_STATIC_VARIABLE(current_varpool) - { - tree var_decl = current_varpool->decl; - - if (!var_decl || TREE_CODE (var_decl) != VAR_DECL) - continue; - if (!i) - varpool_size++; - else - create_new_var (var_decl, new_global_vars); - } - } - - if (new_global_vars) - htab_traverse (new_global_vars, update_varpool_with_new_var, NULL); -} - -/* Dump all new types generated by this optimization. */ - -static void -dump_new_types (void) -{ - d_str str; - tree type; - unsigned i, j; - - if (!dump_file) - return; - - fprintf (dump_file, "\nThe following are the new types generated by" - " this optimization:\n"); - - FOR_EACH_VEC_ELT (structure, structures, i, str) - { - if (dump_file) - { - fprintf (dump_file, "\nFor type "); - dump_struct_type (str->decl, 2, 0); - fprintf (dump_file, "\nthe number of new types is %d\n", - VEC_length (tree, str->new_types)); - } - FOR_EACH_VEC_ELT (tree, str->new_types, j, type) - dump_struct_type (type, 2, 0); - } -} - -/* This function creates new types to replace old structure types. */ - -static void -create_new_types (void) -{ - d_str str; - unsigned i; - int str_num = 0; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - create_new_type (str, &str_num); -} - -/* Free allocation sites hashtable. */ - -static void -free_alloc_sites (void) -{ - if (alloc_sites) - htab_traverse (alloc_sites, free_falloc_sites, NULL); - htab_delete (alloc_sites); - alloc_sites = NULL; -} - -/* This function collects structures potential - for peeling transformation, and inserts - them into structures hashtable. */ - -static void -collect_structures (void) -{ - VEC (tree, heap) *unsuitable_types = VEC_alloc (tree, heap, 32); - - structures = VEC_alloc (structure, heap, 32); - - /* If program contains user defined mallocs, we give up. */ - if (program_redefines_malloc_p ()) - return; - - /* Build data structures hashtable of all data structures - in the program. */ - build_data_structure (&unsuitable_types); - - /* This function analyzes whether the form of - structure is such that we are capable to transform it. - Nested structures are checked here. */ - analyze_struct_form (&unsuitable_types); - - /* This function excludes those structure types - that escape compilation unit. */ - exclude_escaping_types (&unsuitable_types); - - /* We do not want to change data layout of the structures with bitfields. */ - exclude_types_with_bit_fields (&unsuitable_types); - - remove_unsuitable_types (unsuitable_types); - VEC_free (tree, heap, unsuitable_types); -} - -/* Collect structure allocation sites. In case of arrays - we have nothing to do. */ - -static void -collect_allocation_sites (void) -{ - alloc_sites = htab_create (32, malloc_hash, malloc_eq, NULL); - collect_alloc_sites (); -} - -/* This function collects data accesses for the - structures to be transformed. For each structure - field it updates the count field in field_entry. */ - -static void -collect_data_accesses (void) -{ - struct cgraph_node *c_node; - - for (c_node = cgraph_nodes; c_node; c_node = c_node->next) - { - enum availability avail = cgraph_function_body_availability (c_node); - - if (avail == AVAIL_LOCAL || avail == AVAIL_AVAILABLE) - { - struct function *func = DECL_STRUCT_FUNCTION (c_node->decl); - - collect_accesses_in_func (func); - exclude_alloc_and_field_accs (c_node); - } - } - - check_cond_exprs (); - /* Print collected accesses. */ - dump_accesses (); -} - -/* We do not bother to transform cold structures. - Coldness of the structure is defined relatively - to the highest structure count among the structures - to be transformed. It's triggered by the compiler parameter - - --param struct-reorg-cold-struct-ratio= - - where ranges from 0 to 100. Structures with count ratios - that are less than this parameter are considered to be cold. */ - -static void -exclude_cold_structs (void) -{ - gcov_type hottest = 0; - unsigned i; - d_str str; - - /* We summarize counts of fields of a structure into the structure count. */ - FOR_EACH_VEC_ELT (structure, structures, i, str) - sum_counts (str, &hottest); - - /* Remove cold structures from structures vector. */ - i = 0; - while (VEC_iterate (structure, structures, i, str)) - if (str->count * 100 < (hottest * STRUCT_REORG_COLD_STRUCT_RATIO)) - { - if (dump_file) - { - fprintf (dump_file, "\nThe structure "); - print_generic_expr (dump_file, str->decl, 0); - fprintf (dump_file, " is cold."); - } - remove_structure (i); - } - else - i++; -} - -/* This function decomposes original structure into substructures, - i.e.clusters. */ - -static void -peel_structs (void) -{ - d_str str; - unsigned i; - - FOR_EACH_VEC_ELT (structure, structures, i, str) - peel_hot_fields (str); -} - -/* Stage 3. */ -/* Do the actual transformation for each structure - from the structures hashtable. */ - -static void -do_reorg (void) -{ - /* Check that there is a work to do. */ - if (!VEC_length (structure, structures)) - { - if (dump_file) - fprintf (dump_file, "\nNo structures to transform. Exiting..."); - return; - } - else - { - if (dump_file) - { - fprintf (dump_file, "\nNumber of structures to transform is %d", - VEC_length (structure, structures)); - } - } - - /* Generate new types. */ - create_new_types (); - dump_new_types (); - - /* Create new global variables. */ - create_new_global_vars (); - dump_new_vars (new_global_vars); - - /* Decompose structures for each function separately. */ - do_reorg_1 (); - - /* Free auxiliary data collected for global variables. */ - free_new_vars_htab (new_global_vars); -} - -/* Free all auxiliary data used by this optimization. */ - -static void -free_data_structs (void) -{ - free_structures (); - free_alloc_sites (); -} - -/* Perform structure decomposition (peeling). */ - -static void -reorg_structs (void) -{ - - /* Stage1. */ - /* Collect structure types. */ - collect_structures (); - - /* Collect structure allocation sites. */ - collect_allocation_sites (); - - /* Collect structure accesses. */ - collect_data_accesses (); - - /* We transform only hot structures. */ - exclude_cold_structs (); - - /* Stage2. */ - /* Decompose structures into substructures, i.e. clusters. */ - peel_structs (); - - /* Stage3. */ - /* Do the actual transformation for each structure - from the structures hashtable. */ - do_reorg (); - - /* Free all auxiliary data used by this optimization. */ - free_data_structs (); -} - -/* Struct-reorg optimization entry point function. */ - -static unsigned int -reorg_structs_drive (void) -{ - /* IPA struct-reorg is completely broken - its analysis phase is - non-conservative (which is not the only reason it is broken). */ - if (0) - reorg_structs (); - return 0; -} - -/* Struct-reorg optimization gate function. */ - -static bool -struct_reorg_gate (void) -{ - return flag_ipa_struct_reorg - && flag_whole_program - && (optimize > 0); -} - -struct simple_ipa_opt_pass pass_ipa_struct_reorg = -{ - { - SIMPLE_IPA_PASS, - "ipa_struct_reorg", /* name */ - struct_reorg_gate, /* gate */ - reorg_structs_drive, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_INTEGRATION, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - TODO_verify_ssa, /* todo_flags_start */ - TODO_dump_func | TODO_verify_ssa /* todo_flags_finish */ - } -}; diff --git a/gcc/ipa-struct-reorg.h b/gcc/ipa-struct-reorg.h deleted file mode 100644 index e6df1cf..0000000 --- a/gcc/ipa-struct-reorg.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Struct-reorg optimization. - Copyright (C) 2002, 2003-2007, 2008, 2009 Free Software Foundation, Inc. - Contributed by Olga Golovanevsky - -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 3 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; see the file COPYING3. If not see -. */ - -#ifndef IPA_STRUCT_REORG_H -#define IPA_STRUCT_REORG_H - -/* This file contains data structures and interfaces required - for struct-reorg optimizations. */ - -/* An access site of the structure field. - We consider an access to be of the following form: - - D.2166_21 = i.6_20 * 8; - D.2167_22 = (struct str_t *) D.2166_21; - D.2168_24 = D.2167_22 + p.5_23; - D.2169_25 = D.2168_24->b; -*/ - -struct field_access_site -{ - /* Statement in which the access site occurs. */ - gimple stmt; /* D.2169_25 = D.2168_24->b; */ - tree comp_ref; /* D.2168_24->b */ - tree field_decl; /* b */ - tree ref; /* D.2168_24 */ - tree num; /* i.6_20 */ - tree offset; /* D2167_22 */ - tree base; /* p.5_23 */ - gimple ref_def_stmt; /* D.2168_24 = D.2167_22 + p.5_23; */ - gimple cast_stmt; /* D.2167_22 = (struct str_t *) D.2166_21; - This statement is not always present. */ -}; - -/* A non-field structure access site. */ -struct access_site -{ - /* A statement in which the access site occurs. */ - gimple stmt; - /* A list of structure variables in the access site. */ - VEC (tree, heap) *vars; -}; - -/* A field of the structure. */ -struct field_entry -{ - /* A field index. */ - int index; - /* Number of times the field is accessed (according to profiling). */ - gcov_type count; - tree decl; - /* A type of a new structure this field belongs to. */ - tree field_mapping; - htab_t acc_sites; -}; - -/* This structure represents a result of the structure peeling. - The original structure is decomposed into substructures, or clusters. */ -struct field_cluster -{ - /* A bitmap of field indices. The set bit indicates that the field - corresponding to it is a part of this cluster. */ - sbitmap fields_in_cluster; - struct field_cluster *sibling; -}; - -/* An information about an individual structure type (RECORD_TYPE) required - by struct-reorg optimizations to perform a transformation. */ -struct data_structure -{ - - /* A main variant of the structure type. */ - tree decl; - - /* Number of fields in the structure. */ - int num_fields; - - /* A structure access count collected through profiling. */ - gcov_type count; - - /* An array of the structure fields, indexed by field ID. */ - struct field_entry *fields; - - /* Non-field accesses of the structure. */ - htab_t accs; - - /* A data structure representing a reorganization decision. */ - struct field_cluster *struct_clustering; - - /* New types to replace the original structure type. */ - VEC(tree, heap) *new_types; -}; - -typedef struct data_structure * d_str; - -#endif /* IPA_STRUCT_REORG_H */ diff --git a/gcc/ipa-type-escape.c b/gcc/ipa-type-escape.c deleted file mode 100644 index 1ecf68e..0000000 --- a/gcc/ipa-type-escape.c +++ /dev/null @@ -1,2126 +0,0 @@ -/* Escape analysis for types. - Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 - 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 3, 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; 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. - Those types that are encapsulated must also pass the further - requirement that there be no bad operations on any instances of - those types. - - A great deal of freedom in compilation is allowed for the instances - of those types that pass these conditions. -*/ - -/* The code in this module is called by the ipa pass manager. It - should be one of the later passes since its information is used by - the rest of the compilation. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "tree-flow.h" -#include "tree-inline.h" -#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 "gimple.h" -#include "cgraph.h" -#include "output.h" -#include "flags.h" -#include "timevar.h" -#include "diagnostic.h" -#include "tree-pretty-print.h" -#include "langhooks.h" - -/* Some of the aliasing is called very early, before this phase is - called. To assure that this is not a problem, we keep track of if - this phase has been run. */ -static bool initialized = false; - -/* Scratch bitmap for avoiding work. */ -static bitmap been_there_done_that; -static bitmap bitmap_tmp; - -/* There are two levels of escape that types can undergo. - - EXPOSED_PARAMETER - some instance of the variable is - passed by value into an externally visible function or some - instance of the variable is passed out of an externally visible - function as a return value. In this case any of the fields of the - variable that are pointer types end up having their types marked as - FULL_ESCAPE. - - FULL_ESCAPE - when bad things happen to good types. One of the - following things happens to the type: (a) either an instance of the - variable has its address passed to an externally visible function, - (b) the address is taken and some bad cast happens to the address - or (c) explicit arithmetic is done to the address. -*/ - -enum escape_t -{ - EXPOSED_PARAMETER, - FULL_ESCAPE -}; - -/* The following two bit vectors global_types_* correspond to - previous cases above. During the analysis phase, a bit is set in - one of these vectors if an operation of the offending class is - discovered to happen on the associated type. */ - -static bitmap global_types_exposed_parameter; -static bitmap global_types_full_escape; - -/* All of the types seen in this compilation unit. */ -static bitmap global_types_seen; -/* Reverse map to take a canon uid and map it to a canon type. Uid's - are never manipulated unless they are associated with a canon - type. */ -static splay_tree uid_to_canon_type; - -/* Internal structure of type mapping code. This maps a canon type - name to its canon type. */ -static splay_tree all_canon_types; - -/* Map from type clones to the single canon type. */ -static splay_tree type_to_canon_type; - -/* A splay tree of bitmaps. An element X in the splay tree has a bit - set in its bitmap at TYPE_UID (TYPE_MAIN_VARIANT (Y)) if there was - an operation in the program of the form "&X.Y". */ -static splay_tree uid_to_addressof_down_map; - -/* A splay tree of bitmaps. An element Y in the splay tree has a bit - set in its bitmap at TYPE_UID (TYPE_MAIN_VARIANT (X)) if there was - an operation in the program of the form "&X.Y". */ -static splay_tree uid_to_addressof_up_map; - -/* Tree to hold the subtype maps used to mark subtypes of escaped - types. */ -static splay_tree uid_to_subtype_map; - -/* Records tree nodes seen in cgraph_create_edges. Simply using - walk_tree_without_duplicates doesn't guarantee each node is visited - once because it gets a new htab upon each recursive call from - 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 const char* -get_name_of_type (tree type) -{ - tree name = TYPE_NAME (type); - - if (!name) - /* Unnamed type, do what you like here. */ - return ""; - - /* It will be a TYPE_DECL in the case of a typedef, otherwise, an - identifier_node */ - if (TREE_CODE (name) == TYPE_DECL) - { - /* Each DECL has a DECL_NAME field which contains an - IDENTIFIER_NODE. (Some decls, most often labels, may have - zero as the DECL_NAME). */ - if (DECL_NAME (name)) - return IDENTIFIER_POINTER (DECL_NAME (name)); - else - /* Unnamed type, do what you like here. */ - return ""; - } - else if (TREE_CODE (name) == IDENTIFIER_NODE) - return IDENTIFIER_POINTER (name); - else - return ""; -} - -struct type_brand_s -{ - const char* name; - int seq; -}; - -/* Splay tree comparison function on type_brand_s structures. */ - -static int -compare_type_brand (splay_tree_key sk1, splay_tree_key sk2) -{ - struct type_brand_s * k1 = (struct type_brand_s *) sk1; - struct type_brand_s * k2 = (struct type_brand_s *) sk2; - - int value = strcmp(k1->name, k2->name); - if (value == 0) - return k2->seq - k1->seq; - else - return value; -} - -/* All of the "unique_type" code is a hack to get around the sleazy - implementation used to compile more than file. Currently gcc does - not get rid of multiple instances of the same type that have been - collected from different compilation units. */ -/* 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 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) -{ - struct type_brand_s * brand = XNEW (struct type_brand_s); - int i = 0; - splay_tree_node result; - - brand->name = get_name_of_type (type); - - while (1) - { - brand->seq = i++; - result = splay_tree_lookup (all_canon_types, (splay_tree_key) brand); - - if (result) - { - /* Create an alias since this is just the same as - other_type. */ - tree other_type = (tree) result->value; - if (types_compatible_p (type, other_type)) - { - free (brand); - /* Insert this new type as an alias for other_type. */ - splay_tree_insert (type_to_canon_type, - (splay_tree_key) type, - (splay_tree_value) other_type); - return other_type; - } - /* Not compatible, look for next instance with same name. */ - } - else - { - /* No more instances, create new one since this is the first - time we saw this type. */ - brand->seq = i++; - /* Insert the new brand. */ - splay_tree_insert (all_canon_types, - (splay_tree_key) brand, - (splay_tree_value) type); - - /* Insert this new type as an alias for itself. */ - splay_tree_insert (type_to_canon_type, - (splay_tree_key) type, - (splay_tree_value) type); - - /* Insert the uid for reverse lookup; */ - splay_tree_insert (uid_to_canon_type, - (splay_tree_key) TYPE_UID (type), - (splay_tree_value) type); - - bitmap_set_bit (global_types_seen, TYPE_UID (type)); - return type; - } - } -} - -/* Return true if TYPE is one of the type classes that we are willing - to analyze. This skips the goofy types like arrays of pointers to - methods. */ -static bool -type_to_consider (tree type) -{ - /* Strip the *'s off. */ - type = TYPE_MAIN_VARIANT (type); - while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - - switch (TREE_CODE (type)) - { - case BOOLEAN_TYPE: - case COMPLEX_TYPE: - case ENUMERAL_TYPE: - case INTEGER_TYPE: - case QUAL_UNION_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case RECORD_TYPE: - case UNION_TYPE: - case VECTOR_TYPE: - case VOID_TYPE: - return true; - - default: - return false; - } -} - -/* Get the canon type of TYPE. If SEE_THRU_PTRS is true, remove all - the POINTER_TOs and if SEE_THRU_ARRAYS is true, remove all of the - ARRAY_OFs and POINTER_TOs. */ - -static tree -get_canon_type (tree type, bool see_thru_ptrs, bool see_thru_arrays) -{ - splay_tree_node result; - /* Strip the *'s off. */ - if (!type || !type_to_consider (type)) - return NULL; - - type = TYPE_MAIN_VARIANT (type); - if (see_thru_arrays) - while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - - else if (see_thru_ptrs) - while (POINTER_TYPE_P (type)) - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - - result = splay_tree_lookup (type_to_canon_type, (splay_tree_key) type); - - if (result == NULL) - return discover_unique_type (type); - else return (tree) result->value; -} - -/* Same as GET_CANON_TYPE, except return the TYPE_ID rather than the - TYPE. */ - -static int -get_canon_type_uid (tree type, bool see_thru_ptrs, bool see_thru_arrays) -{ - type = get_canon_type (type, see_thru_ptrs, see_thru_arrays); - if (type) - return TYPE_UID(type); - else return 0; -} - -/* Return 0 if TYPE is a record or union type. Return a positive - number if TYPE is a pointer to a record or union. The number is - the number of pointer types stripped to get to the record or union - type. Return -1 if TYPE is none of the above. */ - -int -ipa_type_escape_star_count_of_interesting_type (tree type) -{ - int count = 0; - /* Strip the *'s off. */ - if (!type) - return -1; - type = TYPE_MAIN_VARIANT (type); - while (POINTER_TYPE_P (type)) - { - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - count++; - } - - /* We are interested in records, and unions only. */ - if (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE - || TREE_CODE (type) == UNION_TYPE) - return count; - else - return -1; -} - - -/* Return 0 if TYPE is a record or union type. Return a positive - number if TYPE is a pointer to a record or union. The number is - the number of pointer types stripped to get to the record or union - type. Return -1 if TYPE is none of the above. */ - -int -ipa_type_escape_star_count_of_interesting_or_array_type (tree type) -{ - int count = 0; - /* Strip the *'s off. */ - if (!type) - return -1; - type = TYPE_MAIN_VARIANT (type); - while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) - { - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - count++; - } - - /* We are interested in records, and unions only. */ - if (TREE_CODE (type) == RECORD_TYPE - || TREE_CODE (type) == QUAL_UNION_TYPE - || TREE_CODE (type) == UNION_TYPE) - return count; - else - return -1; -} - - -/* Return true if the record, or union TYPE passed in escapes this - compilation unit. Note that all of the pointer-to's are removed - before testing since these may not be correct. */ - -bool -ipa_type_escape_type_contained_p (tree type) -{ - if (!initialized) - return false; - return !bitmap_bit_p (global_types_full_escape, - get_canon_type_uid (type, true, false)); -} - -/* Return true if a modification to a field of type FIELD_TYPE cannot - clobber a record of RECORD_TYPE. */ - -bool -ipa_type_escape_field_does_not_clobber_p (tree record_type, tree field_type) -{ - splay_tree_node result; - int uid; - - if (!initialized) - return false; - - /* Strip off all of the pointer tos on the record type. Strip the - same number of pointer tos from the field type. If the field - type has fewer, it could not have been aliased. */ - record_type = TYPE_MAIN_VARIANT (record_type); - field_type = TYPE_MAIN_VARIANT (field_type); - while (POINTER_TYPE_P (record_type)) - { - record_type = TYPE_MAIN_VARIANT (TREE_TYPE (record_type)); - if (POINTER_TYPE_P (field_type)) - field_type = TYPE_MAIN_VARIANT (TREE_TYPE (field_type)); - else - /* However, if field_type is a union, this quick test is not - correct since one of the variants of the union may be a - pointer to type and we cannot see across that here. So we - just strip the remaining pointer tos off the record type - and fall thru to the more precise code. */ - if (TREE_CODE (field_type) == QUAL_UNION_TYPE - || TREE_CODE (field_type) == UNION_TYPE) - { - while (POINTER_TYPE_P (record_type)) - record_type = TYPE_MAIN_VARIANT (TREE_TYPE (record_type)); - break; - } - else - return true; - } - - record_type = get_canon_type (record_type, true, true); - /* The record type must be contained. The field type may - escape. */ - if (!ipa_type_escape_type_contained_p (record_type)) - return false; - - uid = TYPE_UID (record_type); - result = splay_tree_lookup (uid_to_addressof_down_map, (splay_tree_key) uid); - - if (result) - { - bitmap field_type_map = (bitmap) result->value; - uid = get_canon_type_uid (field_type, true, true); - /* If the bit is there, the address was taken. If not, it - wasn't. */ - return !bitmap_bit_p (field_type_map, uid); - } - else - /* No bitmap means no addresses were taken. */ - return true; -} - - -/* Add TYPE to the suspect type set. Return true if the bit needed to - be marked. */ - -static tree -mark_type (tree type, enum escape_t escape_status) -{ - bitmap map = NULL; - int uid; - - type = get_canon_type (type, true, true); - if (!type) - return NULL; - - switch (escape_status) - { - case EXPOSED_PARAMETER: - map = global_types_exposed_parameter; - break; - case FULL_ESCAPE: - map = global_types_full_escape; - break; - } - - uid = TYPE_UID (type); - if (!bitmap_set_bit (map, uid)) - return type; - else if (escape_status == FULL_ESCAPE) - /* Efficiency hack. When things are bad, do not mess around - with this type anymore. */ - bitmap_set_bit (global_types_exposed_parameter, uid); - - return type; -} - -/* Add interesting TYPE to the suspect type set. If the set is - EXPOSED_PARAMETER and the TYPE is a pointer type, the set is - changed to FULL_ESCAPE. */ - -static void -mark_interesting_type (tree type, enum escape_t escape_status) -{ - if (!type) return; - if (ipa_type_escape_star_count_of_interesting_type (type) >= 0) - { - if ((escape_status == EXPOSED_PARAMETER) - && POINTER_TYPE_P (type)) - /* EXPOSED_PARAMETERs are only structs or unions are passed by - value. Anything passed by reference to an external - function fully exposes the type. */ - mark_type (type, FULL_ESCAPE); - else - mark_type (type, escape_status); - } -} - -/* Return true if PARENT is supertype of CHILD. Both types must be - known to be structures or unions. */ - -static bool -parent_type_p (tree parent, tree child) -{ - int i; - tree binfo, base_binfo; - if (TYPE_BINFO (parent)) - for (binfo = TYPE_BINFO (parent), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - { - tree binfotype = BINFO_TYPE (base_binfo); - if (binfotype == child) - return true; - else if (parent_type_p (binfotype, child)) - return true; - } - if (TREE_CODE (parent) == UNION_TYPE - || TREE_CODE (parent) == QUAL_UNION_TYPE) - { - tree field; - /* Search all of the variants in the union to see if one of them - is the child. */ - for (field = TYPE_FIELDS (parent); - field; - field = TREE_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = TREE_TYPE (field); - if (field_type == child) - return true; - } - - /* If we did not find it, recursively ask the variants if one of - their children is the child type. */ - for (field = TYPE_FIELDS (parent); - field; - field = TREE_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = TREE_TYPE (field); - if (TREE_CODE (field_type) == RECORD_TYPE - || TREE_CODE (field_type) == QUAL_UNION_TYPE - || TREE_CODE (field_type) == UNION_TYPE) - if (parent_type_p (field_type, child)) - return true; - } - } - - if (TREE_CODE (parent) == RECORD_TYPE) - { - tree field; - for (field = TYPE_FIELDS (parent); - field; - field = TREE_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = TREE_TYPE (field); - if (field_type == child) - return true; - /* You can only cast to the first field so if it does not - match, quit. */ - if (TREE_CODE (field_type) == RECORD_TYPE - || TREE_CODE (field_type) == QUAL_UNION_TYPE - || TREE_CODE (field_type) == UNION_TYPE) - { - if (parent_type_p (field_type, child)) - return true; - else - break; - } - } - } - return false; -} - -/* Return the number of pointer tos for TYPE and return TYPE with all - of these stripped off. */ - -static int -count_stars (tree* type_ptr) -{ - tree type = *type_ptr; - int i = 0; - type = TYPE_MAIN_VARIANT (type); - while (POINTER_TYPE_P (type)) - { - type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); - i++; - } - - *type_ptr = type; - return i; -} - -enum cast_type { - 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 - the two types have already passed the - ipa_type_escape_star_count_of_interesting_type test. */ - -static enum cast_type -check_cast_type (tree to_type, tree from_type) -{ - int to_stars = count_stars (&to_type); - int from_stars = count_stars (&from_type); - if (to_stars != from_stars) - return CT_SIDEWAYS; - - if (to_type == from_type) - return CT_USELESS; - - if (parent_type_p (to_type, from_type)) return CT_UP; - if (parent_type_p (from_type, to_type)) return CT_DOWN; - 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. 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 cast; - - to_interesting_type = - ipa_type_escape_star_count_of_interesting_type (to_type) >= 0; - from_interesting_type = - ipa_type_escape_star_count_of_interesting_type (from_type) >= 0; - - if (to_interesting_type) - if (from_interesting_type) - { - /* Both types are interesting. This can be one of four types - of cast: useless, up, down, or sideways. We do not care - about up or useless. Sideways casts are always bad and - both sides get marked as escaping. Downcasts are not - interesting here because if type is marked as escaping, all - of its subtypes escape. */ - cast = check_cast_type (to_type, from_type); - switch (cast) - { - case CT_UP: - case CT_USELESS: - case CT_DOWN: - break; - - case CT_SIDEWAYS: - mark_type (to_type, FULL_ESCAPE); - mark_type (from_type, FULL_ESCAPE); - break; - - default: - break; - } - } - else - { - /* 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); - 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 - ESCAPES if the function is visible outside of the compilation - unit. */ -static void -check_function_parameter_and_return_types (tree fn, bool escapes) -{ - tree arg; - - if (prototype_p (TREE_TYPE (fn))) - { - for (arg = TYPE_ARG_TYPES (TREE_TYPE (fn)); - arg && TREE_VALUE (arg) != void_type_node; - arg = TREE_CHAIN (arg)) - { - tree type = get_canon_type (TREE_VALUE (arg), false, false); - if (escapes) - mark_interesting_type (type, EXPOSED_PARAMETER); - } - } - else - { - /* 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. However, Geoff is wrong, this code - does seem to be live. */ - - for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg)) - { - tree type = get_canon_type (TREE_TYPE (arg), false, false); - if (escapes) - mark_interesting_type (type, EXPOSED_PARAMETER); - } - } - if (escapes) - { - tree type = get_canon_type (TREE_TYPE (TREE_TYPE (fn)), false, false); - mark_interesting_type (type, EXPOSED_PARAMETER); - } -} - -/* Return true if the variable T is the right kind of static variable to - perform compilation unit scope escape analysis. */ - -static inline void -has_proper_scope_for_analysis (tree t) -{ - /* If the variable has the "used" attribute, treat it as if it had a - been touched by the devil. */ - tree type = get_canon_type (TREE_TYPE (t), false, false); - if (!type) return; - - if (DECL_PRESERVE_P (t)) - { - mark_interesting_type (type, FULL_ESCAPE); - return; - } - - /* Do not want to do anything with volatile except mark any - function that uses one to be not const or pure. */ - if (TREE_THIS_VOLATILE (t)) - return; - - /* Do not care about a local automatic that is not static. */ - if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) - return; - - if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) - { - /* If the front end set the variable to be READONLY and - constant, we can allow this variable in pure or const - functions but the scope is too large for our analysis to set - these bits ourselves. */ - - if (TREE_READONLY (t) - && DECL_INITIAL (t) - && is_gimple_min_invariant (DECL_INITIAL (t))) - ; /* Read of a constant, do not change the function state. */ - else - { - /* The type escapes for all public and externs. */ - mark_interesting_type (type, FULL_ESCAPE); - } - } -} - -/* If T is a VAR_DECL for a static that we are interested in, add the - uid to the bitmap. */ - -static void -check_operand (tree t) -{ - if (!t) return; - - /* This is an assignment from a function, register the types as - escaping. */ - if (TREE_CODE (t) == FUNCTION_DECL) - check_function_parameter_and_return_types (t, true); - - else if (TREE_CODE (t) == VAR_DECL) - has_proper_scope_for_analysis (t); -} - -/* Examine tree T for references. */ - -static void -check_tree (tree 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)); - t = TREE_OPERAND (t, 0); - } - - if (INDIRECT_REF_P (t)) -/* || TREE_CODE (t) == MEM_REF) */ - check_tree (TREE_OPERAND (t, 0)); - - if (SSA_VAR_P (t) || (TREE_CODE (t) == FUNCTION_DECL)) - { - check_operand (t); - if (DECL_P (t) && DECL_INITIAL (t)) - check_tree (DECL_INITIAL (t)); - } -} - -/* Create an address_of edge FROM_TYPE.TO_TYPE. */ -static void -mark_interesting_addressof (tree to_type, tree from_type) -{ - int from_uid; - int to_uid; - bitmap type_map; - splay_tree_node result; - - from_type = get_canon_type (from_type, false, false); - to_type = get_canon_type (to_type, false, false); - - if (!from_type || !to_type) - return; - - from_uid = TYPE_UID (from_type); - to_uid = TYPE_UID (to_type); - - gcc_assert (ipa_type_escape_star_count_of_interesting_type (from_type) == 0); - - /* Process the Y into X map pointer. */ - result = splay_tree_lookup (uid_to_addressof_down_map, - (splay_tree_key) from_uid); - - if (result) - type_map = (bitmap) result->value; - else - { - type_map = BITMAP_ALLOC (&ipa_obstack); - splay_tree_insert (uid_to_addressof_down_map, - from_uid, - (splay_tree_value)type_map); - } - bitmap_set_bit (type_map, TYPE_UID (to_type)); - - /* Process the X into Y reverse map pointer. */ - result = - splay_tree_lookup (uid_to_addressof_up_map, (splay_tree_key) to_uid); - - if (result) - type_map = (bitmap) result->value; - else - { - type_map = BITMAP_ALLOC (&ipa_obstack); - splay_tree_insert (uid_to_addressof_up_map, - to_uid, - (splay_tree_value)type_map); - } - bitmap_set_bit (type_map, TYPE_UID (from_type)); -} - -/* Scan tree T to see if there are any addresses taken in within T. */ - -static void -look_for_address_of (tree t) -{ - if (TREE_CODE (t) == ADDR_EXPR) - { - tree x = get_base_var (t); - tree cref = TREE_OPERAND (t, 0); - - /* If we have an expression of the form "&a.b.c.d", mark a.b, - b.c and c.d. as having its address taken. */ - tree fielddecl = NULL_TREE; - while (cref!= x) - { - if (TREE_CODE (cref) == COMPONENT_REF) - { - fielddecl = TREE_OPERAND (cref, 1); - mark_interesting_addressof (TREE_TYPE (fielddecl), - DECL_FIELD_CONTEXT (fielddecl)); - } - else if (TREE_CODE (cref) == ARRAY_REF) - get_canon_type (TREE_TYPE (cref), false, false); - - cref = TREE_OPERAND (cref, 0); - } - - if (TREE_CODE (x) == VAR_DECL) - has_proper_scope_for_analysis (x); - } -} - - -/* Scan tree T to see if there are any casts within it. */ - -static unsigned int -look_for_casts (tree t) -{ - unsigned int cast = 0; - - if (CONVERT_EXPR_P (t) || TREE_CODE (t) == VIEW_CONVERT_EXPR) - { - tree castfromvar = TREE_OPERAND (t, 0); - cast = cast | check_cast (TREE_TYPE (t), castfromvar); - } - 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 - we are interested in analyzing. */ - -static void -check_rhs_var (tree t) -{ - look_for_address_of (t); - check_tree (t); -} - -/* Check to see if T is an assignment to a static var we are - interested in analyzing. */ - -static void -check_lhs_var (tree t) -{ - check_tree (t); -} - -/* This is a scaled down version of get_asm_expr_operands from - tree_ssa_operands.c. The version there runs much later and assumes - that aliasing information is already available. Here we are just - trying to find if the set of inputs and outputs contain references - or address of operations to local. FN is the function being - analyzed and STMT is the actual asm statement. */ - -static void -check_asm (gimple stmt) -{ - size_t i; - - 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, - but that appears to be wrong. In other parts of the compiler, - the asm memory clobbers are assumed to only clobber variables - that are addressable. All types with addressable instances are - assumed to already escape. So, we are protected here. */ -} - - -/* 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 (gimple call) -{ - tree callee_t = gimple_call_fndecl (call); - struct cgraph_node* callee; - enum availability avail = AVAIL_NOT_AVAILABLE; - size_t i; - - for (i = 0; i < gimple_call_num_args (call); i++) - check_rhs_var (gimple_call_arg (call, i)); - - if (callee_t) - { - tree arg_type; - tree last_arg_type = NULL; - callee = cgraph_node(callee_t); - avail = cgraph_function_body_availability (callee); - - /* Check that there are no implicit casts in the passing of - parameters. */ - if (prototype_p (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 - && i < gimple_call_num_args (call); - arg_type = TREE_CHAIN (arg_type), i++) - { - tree operand = gimple_call_arg (call, i); - if (operand) - { - last_arg_type = TREE_VALUE(arg_type); - check_cast (last_arg_type, operand); - } - else - /* The code reaches here for some unfortunate - builtin functions that do not have a list of - argument types. */ - break; - } - } - else - { - /* 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), i = 0; - arg_type && i < gimple_call_num_args (call); - arg_type = TREE_CHAIN (arg_type), i++) - { - tree operand = gimple_call_arg (call, i); - if (operand) - { - last_arg_type = TREE_TYPE (arg_type); - check_cast (last_arg_type, operand); - } - else - /* The code reaches here for some unfortunate - builtin functions that do not have a list of - argument types. */ - break; - } - } - - /* 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 ( ; i < gimple_call_num_args (call); i++) - { - tree operand = gimple_call_arg (call, i); - if (arg_type) - check_cast (arg_type, operand); - else - { - /* The code reaches here for some unfortunate - builtin functions that do not have a list of - 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 (operand), false, false); - mark_interesting_type (type, FULL_ESCAPE); - } - } - } - - /* The callee is either unknown (indirect call) or there is just no - scannable code for it (external call) . We look to see if there - 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 (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) - { - tree type = - get_canon_type (TREE_TYPE (TREE_TYPE (callee_t)), false, false); - mark_interesting_type (type, EXPOSED_PARAMETER); - } - } -} - -/* CODE is the operation on OP0 and OP1. OP0 is the operand that we - *know* is a pointer type. OP1 may be a pointer type. */ -static bool -okay_pointer_operation (enum tree_code code, tree op0, tree op1) -{ - tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0)); - - switch (code) - { - case MULT_EXPR: - /* Multiplication does not change alignment. */ - return true; - break; - case MINUS_EXPR: - 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; -} - - - -/* Helper for scan_for_refs. Check the operands of an assignment to - mark types that may escape. */ - -static void -check_assign (gimple t) -{ - /* 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 */ - - /* Next check the operands on the rhs to see if they are ok. */ - switch (TREE_CODE_CLASS (gimple_assign_rhs_code (t))) - { - 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 tcc_unary: - { - 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; - - case tcc_reference: - look_for_casts (gimple_assign_rhs1 (t)); - check_rhs_var (gimple_assign_rhs1 (t)); - break; - - case tcc_declaration: - check_rhs_var (gimple_assign_rhs1 (t)); - break; - - 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; - - default: - break; - } -} - - -/* 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 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); - break; - - case GIMPLE_ASM: - check_asm (t); - break; - - default: - break; - } - - return; -} - - -/* The init routine for analyzing global static variable usage. See - comments at top for description. */ -static void -ipa_init (void) -{ - bitmap_obstack_initialize (&ipa_obstack); - global_types_exposed_parameter = BITMAP_ALLOC (&ipa_obstack); - global_types_full_escape = BITMAP_ALLOC (&ipa_obstack); - global_types_seen = 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); - type_to_canon_type = splay_tree_new (splay_tree_compare_pointers, 0, 0); - uid_to_subtype_map = splay_tree_new (splay_tree_compare_ints, 0, 0); - uid_to_addressof_down_map = splay_tree_new (splay_tree_compare_ints, 0, 0); - uid_to_addressof_up_map = splay_tree_new (splay_tree_compare_ints, 0, 0); - - /* There are some shared nodes, in particular the initializers on - static declarations. We do not need to scan them more than once - since all we would be interested in are the addressof - operations. */ - visited_nodes = pointer_set_create (); - initialized = true; -} - -/* 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 - compilation unit but their right hand sides may contain references - to variables defined within this unit. */ - -static void -analyze_variable (struct varpool_node *vnode) -{ - tree global = vnode->decl; - tree type = get_canon_type (TREE_TYPE (global), false, false); - - /* If this variable has exposure beyond the compilation unit, add - its type to the global types. */ - - if (vnode->externally_visible) - mark_interesting_type (type, FULL_ESCAPE); - - gcc_assert (TREE_CODE (global) == VAR_DECL); - - if (DECL_INITIAL (global)) - check_tree (DECL_INITIAL (global)); -} - -/* This is the main routine for finding the reference patterns for - global variables within a function FN. */ - -static void -analyze_function (struct cgraph_node *fn) -{ - tree decl = fn->decl; - check_function_parameter_and_return_types (decl, - fn->local.externally_visible); - if (dump_file) - fprintf (dump_file, "\n local analysis of %s", cgraph_node_name (fn)); - - { - struct function *this_cfun = DECL_STRUCT_FUNCTION (decl); - basic_block this_block; - - FOR_EACH_BB_FN (this_block, this_cfun) - { - gimple_stmt_iterator gsi; - for (gsi = gsi_start_bb (this_block); !gsi_end_p (gsi); gsi_next (&gsi)) - scan_for_refs (gsi_stmt (gsi)); - } - } - - /* There may be const decls with interesting right hand sides. */ - if (DECL_STRUCT_FUNCTION (decl)) - { - tree var; - unsigned ix; - - FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (decl), ix, var) - { - if (TREE_CODE (var) == VAR_DECL - && DECL_INITIAL (var) - && !TREE_STATIC (var)) - check_tree (DECL_INITIAL (var)); - get_canon_type (TREE_TYPE (var), false, false); - } - } -} - - - -/* Convert a type_UID into a type. */ -static tree -type_for_uid (int uid) -{ - splay_tree_node result = - splay_tree_lookup (uid_to_canon_type, (splay_tree_key) uid); - - if (result) - return (tree) result->value; - else return NULL; -} - -/* 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. */ - -static bitmap -subtype_map_for_uid (int uid, bool create) -{ - splay_tree_node result = splay_tree_lookup (uid_to_subtype_map, - (splay_tree_key) uid); - - if (result) - return (bitmap) result->value; - else if (create) - { - bitmap subtype_map = BITMAP_ALLOC (&ipa_obstack); - splay_tree_insert (uid_to_subtype_map, - uid, - (splay_tree_value)subtype_map); - return subtype_map; - } - else return NULL; -} - -/* Mark all of the supertypes and field types of TYPE as being seen. - Also accumulate the subtypes for each type so that - close_types_full_escape can mark a subtype as escaping if the - supertype escapes. */ - -static void -close_type_seen (tree type) -{ - tree field; - int i, uid; - tree binfo, base_binfo; - - /* See thru all pointer tos and array ofs. */ - type = get_canon_type (type, true, true); - if (!type) - return; - - uid = TYPE_UID (type); - - if (!bitmap_set_bit (been_there_done_that, uid)) - return; - - /* If we are doing a language with a type hierarchy, mark all of - the superclasses. */ - if (TYPE_BINFO (type)) - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - { - tree binfo_type = BINFO_TYPE (base_binfo); - bitmap subtype_map = subtype_map_for_uid - (TYPE_UID (TYPE_MAIN_VARIANT (binfo_type)), true); - bitmap_set_bit (subtype_map, uid); - close_type_seen (get_canon_type (binfo_type, true, true)); - } - - /* If the field is a struct or union type, mark all of the - subfields. */ - for (field = TYPE_FIELDS (type); - field; - field = DECL_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = TREE_TYPE (field); - if (ipa_type_escape_star_count_of_interesting_or_array_type (field_type) >= 0) - close_type_seen (get_canon_type (field_type, true, true)); - } -} - -/* Take a TYPE that has been passed by value to an external function - and mark all of the fields that have pointer types as escaping. For - any of the non pointer types that are structures or unions, - recurse. TYPE is never a pointer type. */ - -static void -close_type_exposed_parameter (tree type) -{ - tree field; - int uid; - - type = get_canon_type (type, false, false); - if (!type) - return; - uid = TYPE_UID (type); - gcc_assert (!POINTER_TYPE_P (type)); - - if (!bitmap_set_bit (been_there_done_that, uid)) - return; - - /* If the field is a struct or union type, mark all of the - subfields. */ - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - tree field_type; - - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = get_canon_type (TREE_TYPE (field), false, false); - mark_interesting_type (field_type, EXPOSED_PARAMETER); - - /* Only recurse for non pointer types of structures and unions. */ - if (ipa_type_escape_star_count_of_interesting_type (field_type) == 0) - close_type_exposed_parameter (field_type); - } -} - -/* The next function handles the case where a type fully escapes. - This means that not only does the type itself escape, - - a) the type of every field recursively escapes - b) the type of every subtype escapes as well as the super as well - as all of the pointer to types for each field. - - Note that pointer to types are not marked as escaping. If the - pointed to type escapes, the pointer to type also escapes. - - Take a TYPE that has had the address taken for an instance of it - and mark all of the types for its fields as having their addresses - taken. */ - -static void -close_type_full_escape (tree type) -{ - tree field; - unsigned int i; - int uid; - tree binfo, base_binfo; - bitmap_iterator bi; - bitmap subtype_map; - splay_tree_node address_result; - - /* Strip off any pointer or array types. */ - type = get_canon_type (type, true, true); - if (!type) - return; - uid = TYPE_UID (type); - - if (!bitmap_set_bit (been_there_done_that, uid)) - return; - - subtype_map = subtype_map_for_uid (uid, false); - - /* If we are doing a language with a type hierarchy, mark all of - the superclasses. */ - if (TYPE_BINFO (type)) - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) - { - tree binfotype = BINFO_TYPE (base_binfo); - binfotype = mark_type (binfotype, FULL_ESCAPE); - close_type_full_escape (binfotype); - } - - /* Mark as escaped any types that have been down casted to - this type. */ - if (subtype_map) - EXECUTE_IF_SET_IN_BITMAP (subtype_map, 0, i, bi) - { - tree subtype = type_for_uid (i); - subtype = mark_type (subtype, FULL_ESCAPE); - close_type_full_escape (subtype); - } - - /* If the field is a struct or union type, mark all of the - subfields. */ - for (field = TYPE_FIELDS (type); - field; - field = TREE_CHAIN (field)) - { - tree field_type; - if (TREE_CODE (field) != FIELD_DECL) - continue; - - field_type = TREE_TYPE (field); - if (ipa_type_escape_star_count_of_interesting_or_array_type (field_type) >= 0) - { - field_type = mark_type (field_type, FULL_ESCAPE); - close_type_full_escape (field_type); - } - } - - /* For all of the types A that contain this type B and were part of - an expression like "&...A.B...", mark the A's as escaping. */ - address_result = splay_tree_lookup (uid_to_addressof_up_map, - (splay_tree_key) uid); - if (address_result) - { - bitmap containing_classes = (bitmap) address_result->value; - EXECUTE_IF_SET_IN_BITMAP (containing_classes, 0, i, bi) - { - close_type_full_escape (type_for_uid (i)); - } - } -} - -/* Transitively close the addressof bitmap for the type with UID. - This means that if we had a.b and b.c, a would have both b and c in - its maps. */ - -static bitmap -close_addressof_down (int uid) -{ - bitmap_iterator bi; - splay_tree_node result = - splay_tree_lookup (uid_to_addressof_down_map, (splay_tree_key) uid); - bitmap map = NULL; - bitmap new_map; - unsigned int i; - - if (result) - map = (bitmap) result->value; - else - return NULL; - - if (!bitmap_set_bit (been_there_done_that, uid)) - return map; - - /* If the type escapes, get rid of the addressof map, it will not be - needed. */ - if (bitmap_bit_p (global_types_full_escape, uid)) - { - BITMAP_FREE (map); - splay_tree_remove (uid_to_addressof_down_map, (splay_tree_key) uid); - return NULL; - } - - /* The new_map will have all of the bits for the enclosed fields and - will have the unique id version of the old map. */ - new_map = BITMAP_ALLOC (&ipa_obstack); - - EXECUTE_IF_SET_IN_BITMAP (map, 0, i, bi) - { - bitmap submap = close_addressof_down (i); - bitmap_set_bit (new_map, i); - if (submap) - bitmap_ior_into (new_map, submap); - } - result->value = (splay_tree_value) new_map; - - BITMAP_FREE (map); - return new_map; -} - - -/* The main entry point for type escape analysis. */ - -static unsigned int -type_escape_execute (void) -{ - struct cgraph_node *node; - struct varpool_node *vnode; - unsigned int i; - bitmap_iterator bi; - splay_tree_node result; - - ipa_init (); - - /* Process all of the variables first. */ - FOR_EACH_STATIC_VARIABLE (vnode) - analyze_variable (vnode); - - /* 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 - AVAIL_OVERWRITABLE functions (these are never clones) because - they may cause a type variable to escape. - */ - for (node = cgraph_nodes; node; node = node->next) - if (node->analyzed && !node->clone_of) - analyze_function (node); - - - pointer_set_destroy (visited_nodes); - visited_nodes = NULL; - - /* Do all of the closures to discover which types escape the - compilation unit. */ - - been_there_done_that = BITMAP_ALLOC (&ipa_obstack); - bitmap_tmp = BITMAP_ALLOC (&ipa_obstack); - - /* Examine the types that we have directly seen in scanning the code - and add to that any contained types or superclasses. */ - - bitmap_copy (bitmap_tmp, global_types_seen); - EXECUTE_IF_SET_IN_BITMAP (bitmap_tmp, 0, i, bi) - { - tree type = type_for_uid (i); - /* Only look at records and unions and pointer tos. */ - if (ipa_type_escape_star_count_of_interesting_or_array_type (type) >= 0) - close_type_seen (type); - } - bitmap_clear (been_there_done_that); - - /* Examine all of the types passed by value and mark any enclosed - pointer types as escaping. */ - bitmap_copy (bitmap_tmp, global_types_exposed_parameter); - EXECUTE_IF_SET_IN_BITMAP (bitmap_tmp, 0, i, bi) - { - close_type_exposed_parameter (type_for_uid (i)); - } - bitmap_clear (been_there_done_that); - - /* Close the types for escape. If something escapes, then any - enclosed types escape as well as any subtypes. */ - bitmap_copy (bitmap_tmp, global_types_full_escape); - EXECUTE_IF_SET_IN_BITMAP (bitmap_tmp, 0, i, bi) - { - close_type_full_escape (type_for_uid (i)); - } - bitmap_clear (been_there_done_that); - - /* Before this pass, the uid_to_addressof_down_map for type X - contained an entry for Y if there had been an operation of the - form &X.Y. This step adds all of the fields contained within Y - (recursively) to X's map. */ - - result = splay_tree_min (uid_to_addressof_down_map); - while (result) - { - int uid = result->key; - /* Close the addressof map, i.e. copy all of the transitive - substructures up to this level. */ - close_addressof_down (uid); - result = splay_tree_successor (uid_to_addressof_down_map, uid); - } - - /* Do not need the array types and pointer types in the persistent - data structures. */ - result = splay_tree_min (all_canon_types); - while (result) - { - tree type = (tree) result->value; - tree key = (tree) result->key; - if (POINTER_TYPE_P (type) - || TREE_CODE (type) == ARRAY_TYPE) - { - splay_tree_remove (all_canon_types, (splay_tree_key) result->key); - splay_tree_remove (type_to_canon_type, (splay_tree_key) type); - splay_tree_remove (uid_to_canon_type, (splay_tree_key) TYPE_UID (type)); - bitmap_clear_bit (global_types_seen, TYPE_UID (type)); - } - result = splay_tree_successor (all_canon_types, (splay_tree_key) key); - } - - if (dump_file) - { - EXECUTE_IF_SET_IN_BITMAP (global_types_seen, 0, i, bi) - { - /* The pointer types are in the global_types_full_escape - bitmap but not in the backwards map. They also contain - no useful information since they are not marked. */ - tree type = type_for_uid (i); - fprintf(dump_file, "type %d ", i); - print_generic_expr (dump_file, type, 0); - if (bitmap_bit_p (global_types_full_escape, i)) - fprintf(dump_file, " escaped\n"); - else - fprintf(dump_file, " contained\n"); - } - } - - /* Get rid of uid_to_addressof_up_map and its bitmaps. */ - result = splay_tree_min (uid_to_addressof_up_map); - while (result) - { - int uid = (int)result->key; - bitmap bm = (bitmap)result->value; - - BITMAP_FREE (bm); - splay_tree_remove (uid_to_addressof_up_map, (splay_tree_key) uid); - result = splay_tree_successor (uid_to_addressof_up_map, uid); - } - - /* Get rid of the subtype map. */ - result = splay_tree_min (uid_to_subtype_map); - while (result) - { - bitmap b = (bitmap)result->value; - BITMAP_FREE(b); - splay_tree_remove (uid_to_subtype_map, result->key); - result = splay_tree_min (uid_to_subtype_map); - } - splay_tree_delete (uid_to_subtype_map); - uid_to_subtype_map = NULL; - - BITMAP_FREE (global_types_exposed_parameter); - BITMAP_FREE (been_there_done_that); - BITMAP_FREE (bitmap_tmp); - return 0; -} - -static bool -gate_type_escape_vars (void) -{ - return flag_ipa_struct_reorg && flag_whole_program && (optimize > 0); -} - -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 */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_IPA_TYPE_ESCAPE, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - 0 /* todo_flags_finish */ - } -}; diff --git a/gcc/ipa-type-escape.h b/gcc/ipa-type-escape.h deleted file mode 100644 index 0cb9a24..0000000 --- a/gcc/ipa-type-escape.h +++ /dev/null @@ -1,34 +0,0 @@ -/* Type based alias analysis. - Copyright (C) 2004, 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 3, 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; see the file COPYING3. If not see -. */ - -#ifndef GCC_IPA_TYPE_ESCAPE_H -#define GCC_IPA_TYPE_ESCAPE_H -#include "tree.h" - -bool ipa_type_escape_type_contained_p (tree type); -bool ipa_type_escape_field_does_not_clobber_p (tree, tree); -int ipa_type_escape_star_count_of_interesting_type (tree type); -int ipa_type_escape_star_count_of_interesting_or_array_type (tree type); -bool is_array_access_through_pointer_and_index (enum tree_code, tree, tree, - tree *, tree *, gimple *); - - -#endif /* GCC_IPA_TYPE_ESCAPE_H */ - diff --git a/gcc/opts.c b/gcc/opts.c index 5ea5fac..2c4e7da 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -777,7 +777,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, { /* These passes are not WHOPR compatible yet. */ opts->x_flag_ipa_pta = 0; - opts->x_flag_ipa_struct_reorg = 0; } if (opts->x_flag_lto) diff --git a/gcc/params.def b/gcc/params.def index 8ecda91..af304a2 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -39,16 +39,6 @@ along with GCC; see the file COPYING3. If not see Be sure to add an entry to invoke.texi summarizing the parameter. */ -/* The threshold ratio between current and hottest structure counts. - We say that if the ratio of the current structure count, - calculated by profiling, to the hottest structure count - in the program is less than this parameter, then structure - reorganization is not applied. The default is 10%. */ -DEFPARAM (PARAM_STRUCT_REORG_COLD_STRUCT_RATIO, - "struct-reorg-cold-struct-ratio", - "The threshold ratio between current and hottest structure counts", - 10, 0, 100) - /* When branch is predicted to be taken with probability lower than this threshold (in percent), then it is considered well predictable. */ DEFPARAM (PARAM_PREDICTABLE_BRANCH_OUTCOME, diff --git a/gcc/params.h b/gcc/params.h index e36a5ea..c4c12a4 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -118,8 +118,6 @@ extern int default_param_value (compiler_param num); extern void init_param_values (int *params); /* Macros for the various parameters. */ -#define STRUCT_REORG_COLD_STRUCT_RATIO \ - PARAM_VALUE (PARAM_STRUCT_REORG_COLD_STRUCT_RATIO) #define MAX_INLINE_INSNS_SINGLE \ PARAM_VALUE (PARAM_MAX_INLINE_INSNS_SINGLE) #define MAX_INLINE_INSNS \ diff --git a/gcc/passes.c b/gcc/passes.c index a33a6af..42a32398 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -798,9 +798,7 @@ init_optimization_passes (void) NEXT_PASS (pass_ipa_inline); NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_reference); - NEXT_PASS (pass_ipa_type_escape); NEXT_PASS (pass_ipa_pta); - NEXT_PASS (pass_ipa_struct_reorg); *p = NULL; p = &all_lto_gen_passes; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5e4e3d0..e6d799d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2011-03-23 Richard Guenther + + * gcc.dg/struct: Remove directory and contents. + 2011-03-23 Rainer Orth PR testsuite/48251 diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp deleted file mode 100644 index a18b11d..0000000 --- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2007, 2008, 2009, 2010 -# Free Software Foundation, Inc. - -# This program 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 3 of the License, or -# (at your option) any later version. -# -# This program 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 this program; see the file COPYING3. If not see -# . - -# Test the functionality of programs compiled with profile-directed structure -# rearrangement using -fprofile-generate followed by -fprofile-use. - -load_lib gcc-dg.exp -load_lib target-supports.exp - -set STRUCT_REORG_CFLAGS "-O3 -fipa-struct-reorg -fdump-ipa-all -fwhole-program" - -# Initialize `dg'. -dg-init - -dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_prof_*.c]] "" $STRUCT_REORG_CFLAGS - -dg-final - -# Some targets don't support tree profiling. -if { ![check_profiling_available ""] } { - return -} - -# The procedures in profopt.exp need these parameters. -set tool gcc -set prof_ext "gcda" - -# Override the list defined in profopt.exp. -set PROFOPT_OPTIONS [list {}] - -if $tracelevel then { - strace $tracelevel -} - -# Load support procs. -load_lib profopt.exp - -# These are globals used by profopt-execute. The first is options -# needed to generate profile data, the second is options to use the -# profile data. -set common "-O3 -fwhole-program" -set profile_option [concat $common " -fprofile-generate"] -set feedback_option [concat $common " -fprofile-use -fipa-struct-reorg -fdump-ipa-all"] - -foreach src [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] { - # If we're only testing specific files and this isn't one of them, skip it. - if ![runtest_file_p $runtests $src] then { - continue - } - profopt-execute $src -} - -set feedback_option [concat $feedback_option " --param struct-reorg-cold-struct-ratio=30"] - -foreach src [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] { - # If we're only testing specific files and this isn't one of them, skip it. - if ![runtest_file_p $runtests $src] then { - continue - } - profopt-execute $src -} diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c deleted file mode 100644 index ca3643e..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_prof_global_array.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -typedef struct -{ - int a; - float b; -}str_t; - -#define N 1000 -str_t A[N]; - -int -main () -{ - int i; - - for (i = 0; i < N; i++) - { - A[i].a = 0; - } - - for (i = 0; i < N; i++) - if (A[i].a != 0) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c deleted file mode 100644 index baff45d..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_prof_global_var.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -str_t *p; - -int -main () -{ - int i, sum; - - p = malloc (N * sizeof (str_t)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - p[i].b = i; - - for (i = 0; i < N; i++) - p[i].a = p[i].b + 1; - - for (i = 0; i < N; i++) - if (p[i].a != p[i].b + 1) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c deleted file mode 100644 index 8953264..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_prof_local_array.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i; - str_t A[N]; - - for (i = 0; i < N; i++) - { - A[i].a = 0; - } - - for (i = 0; i < N; i++) - if (A[i].a != 0) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c deleted file mode 100644 index 9a23f8d..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_prof_local_var.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i, sum; - - str_t * p = malloc (N * sizeof (str_t)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - p[i].b = i; - - for (i = 0; i < N; i++) - p[i].a = p[i].b + 1; - - for (i = 0; i < N; i++) - if (p[i].a != p[i].b + 1) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c deleted file mode 100644 index b020239..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_prof_single_str_global.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -typedef struct -{ - int a; - int b; -}str_t; - -#define N 3 - -str_t str; - -int -main () -{ - int i; - int res = 1<<(1< - -typedef struct -{ - int a; - float b; -}str_t1; - -typedef struct -{ - int c; - float d; -}str_t2; - -#ifdef STACK_SIZE -#if STACK_SIZE > 16000 -#define N 1000 -#else -#define N (STACK_SIZE/16) -#endif -#else -#define N 1000 -#endif - -str_t1 *p1; -str_t2 *p2; -int num; - -void -foo (void) -{ - int i; - - for (i=0; i < num; i++) - p2[i].c = 2; -} - -int -main () -{ - int i, r; - - r = rand (); - num = r > N ? N : r; - p1 = malloc (num * sizeof (str_t1)); - p2 = malloc (num * sizeof (str_t2)); - - if (p1 == NULL || p2 == NULL) - return 0; - - for (i = 0; i < num; i++) - p1[i].a = 1; - - foo (); - - for (i = 0; i < num; i++) - if (p1[i].a != 1 || p2[i].c != 2) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ - diff --git a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c b/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c deleted file mode 100644 index 3c26e3b..0000000 --- a/gcc/testsuite/gcc.dg/struct/w_ratio_cold_str.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -typedef struct -{ - int a; - int b; -}str_t1; - -typedef struct -{ - float a; - float b; -}str_t2; - -#define N1 1000 -#define N2 100 -str_t1 A1[N1]; -str_t2 A2[N2]; - -int -main () -{ - int i; - - for (i = 0; i < N1; i++) - A1[i].a = 0; - - for (i = 0; i < N2; i++) - A2[i].a = 0; - - for (i = 0; i < N1; i++) - if (A1[i].a != 0) - abort (); - - for (i = 0; i < N2; i++) - if (A2[i].a != 0) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final-use { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final-use { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c deleted file mode 100644 index 5d5e37b4..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_array_field.c +++ /dev/null @@ -1,27 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct basic -{ - int a; - int b[10]; -} type_struct; - -type_struct *str1; - -int main() -{ - int i; - - str1 = malloc (10 * sizeof (type_struct)); - - for (i=0; i<=9; i++) - str1[i].a = str1[i].b[0]; - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c deleted file mode 100644 index efb68be8..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_array_through_pointer.c +++ /dev/null @@ -1,39 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i; - str_t A[N]; - str_t *p = A; - - for (i = 0; i < N; i++) - p[i].a = 0; - - for (i = 0; i < N; i++) - if (p[i].a != 0) - abort (); - - return 0; -} - -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c b/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c deleted file mode 100644 index 77226b4..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_double_malloc.c +++ /dev/null @@ -1,30 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include - -typedef struct test_struct -{ - int a; - int b; -} type_struct; - -typedef type_struct **struct_pointer2; - -struct_pointer2 str1; - -int main() -{ - int i, j; - - str1 = malloc (2 * sizeof (type_struct *)); - - for (i = 0; i <= 1; i++) - str1[i] = malloc (2 * sizeof (type_struct)); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c b/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c deleted file mode 100644 index 09668fa..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_empty_str.c +++ /dev/null @@ -1,45 +0,0 @@ -/* { dg-do run } */ - -#include - -struct S { int a; struct V *b; }; -typedef struct { int c; } T; -typedef struct { int d; int e; } U; - -void * -fn (void *x) -{ - return x; -} - -int -foo (struct S *s) -{ - T x; - - T y = *(T *)fn (&x); - return y.c; -} - -int -bar (struct S *s) -{ - U x; - - U y = *(U *)fn (&x); - return y.d + s->a; -} - -int -main () -{ - struct S s; - - foo(&s) + bar (&s); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "No structures to transform" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c deleted file mode 100644 index 0116d81..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_arg_to_local.c +++ /dev/null @@ -1,44 +0,0 @@ -/* { dg-do run } */ - -#include -struct str -{ - int a; - float b; -}; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -foo (struct str * p_str) -{ - static int sum = 0; - - sum = sum + p_str->a; - return sum; -} - -int -main () -{ - int i, sum; - struct str * p = malloc (N * sizeof (struct str)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - sum = foo (p+i); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is passed to local function...Excluded." "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c deleted file mode 100644 index 21a6a7f3..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_return.c +++ /dev/null @@ -1,31 +0,0 @@ -/* { dg-do run } */ - -#include - -struct A { - int d; -}; - -struct A a; - -struct A foo () -{ - a.d = 5; - return a; -} - -int -main () -{ - a.d = 0; - foo (); - - if (a.d != 5) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is return type of function...Excluded" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c deleted file mode 100644 index 6da3420..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_str_init.c +++ /dev/null @@ -1,33 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - int b; -}str_t; - -#define N 2 - -str_t A[2] = {{1,1},{2,2}}; - -int -main () -{ - int i; - - for (i = 0; i < N; i++) - A[i].b = A[i].a; - - for (i = 0; i < N; i++) - if (A[i].b != A[i].a) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is initialized...Excluded" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ - diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c deleted file mode 100644 index bd03ec4..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_array.c +++ /dev/null @@ -1,34 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#define N 1000 - -typedef struct -{ - str_t A[N]; - int c; -}str_with_substr_t; - -str_with_substr_t a; - -int -main () -{ - int i; - - for (i = 0; i < N; i++) - a.A[i].b = 0; - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c deleted file mode 100644 index 59e0e48..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_pointer.c +++ /dev/null @@ -1,49 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 16000 -#define N 1000 -#else -#define N (STACK_SIZE/16) -#endif -#else -#define N 1000 -#endif - -typedef struct -{ - str_t * sub_str; - int c; -}str_with_substr_t; - -int foo; - -int -main (void) -{ - int i; - str_with_substr_t A[N]; - str_t a[N]; - - for (i=0; i < N; i++) - A[i].sub_str = &(a[i]); - - for (i=0; i < N; i++) - A[i].sub_str->a = 5; - - foo = A[56].sub_str->a; - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c b/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c deleted file mode 100644 index a6b32dd..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_escape_substr_value.c +++ /dev/null @@ -1,46 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - - -typedef struct -{ - str_t sub_str; - int c; -}str_with_substr_t; - -int -main () -{ - int i; - str_with_substr_t A[N]; - - for (i = 0; i < N; i++) - A[i].sub_str.a = 5; - - for (i = 0; i < N; i++) - if (A[i].sub_str.a != 5) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "is a field in the structure" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c deleted file mode 100644 index b61e26b..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_global_array.c +++ /dev/null @@ -1,33 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#define N 1000 -str_t A[N]; - -int -main () -{ - int i; - - for (i = 0; i < N; i++) - { - A[i].a = 0; - } - - for (i = 0; i < N; i++) - if (A[i].a != 0) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c deleted file mode 100644 index 39351e0..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_global_var.c +++ /dev/null @@ -1,46 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -str_t *p; - -int -main () -{ - int i, sum; - - p = malloc (N * sizeof (str_t)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - p[i].b = i; - - for (i = 0; i < N; i++) - p[i].b = p[i].a + 1; - - for (i = 0; i < N; i++) - if (p[i].b != p[i].a + 1) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c deleted file mode 100644 index 18d5a73..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_local_array.c +++ /dev/null @@ -1,41 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i; - str_t A[N]; - - for (i = 0; i < N; i++) - { - A[i].a = 0; - } - - for (i = 0; i < N; i++) - if (A[i].a != 0) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c deleted file mode 100644 index 26a9dbd..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_local_var.c +++ /dev/null @@ -1,44 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i, sum; - - str_t * p = malloc (N * sizeof (str_t)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - p[i].b = i; - - for (i = 0; i < N; i++) - p[i].b = p[i].a + 1; - - for (i = 0; i < N; i++) - if (p[i].b != p[i].a + 1) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c b/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c deleted file mode 100644 index 6caadcf..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_malloc_size_var.c +++ /dev/null @@ -1,48 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 8000 -#define N 1000 -#else -#define N (STACK_SIZE/8) -#endif -#else -#define N 1000 -#endif - -int -main () -{ - int i, num; - - num = rand(); - num = num > N ? N : num; - str_t * p = malloc (num * sizeof (str_t)); - - if (p == 0) - return 0; - - for (i = 0; i < num; i++) - p[i].b = i; - - for (i = 0; i < num; i++) - p[i].a = p[i].b + 1; - - for (i = 0; i < num; i++) - if (p[i].a != p[i].b + 1) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c b/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c deleted file mode 100644 index 8f116df..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_mult_field_peeling.c +++ /dev/null @@ -1,43 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - float b; - int c; - float d; -}str_t; - -#ifdef STACK_SIZE -#if STACK_SIZE > 1600 -#define N 100 -#else -#define N (STACK_SIZE/16) -#endif -#else -#define N 100 -#endif - -int -main () -{ - int i; - str_t *p = malloc (N * sizeof (str_t)); - if (p == NULL) - return 0; - for (i = 0; i < N; i++) - p[i].a = 5; - - for (i = 0; i < N; i++) - if (p[i].a != 5) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* The structure str_t is erroneously peeled into 4 structures instead of 2. */ -/* { dg-final { scan-ipa-dump "the number of new types is 2" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c b/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c deleted file mode 100644 index 812763d..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_single_str_global.c +++ /dev/null @@ -1,35 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include -typedef struct -{ - int a; - int b; -}str_t; - -#define N 3 - -str_t str; - -int -main () -{ - int i; - int res = 1<<(1< -typedef struct -{ - int a; - int b; -}str_t; - -#define N 3 - -int -main () -{ - int i; - int res = 1<<(1< -typedef struct -{ - int a; - int *b; -}str_t; - -#define N 3 - -str_t *p; - -int -main () -{ - str_t str; - int i; - int res = 1 << (1 << N); - p = &str; - str.a = 2; - - p->b = &(p->a); - - for (i=0; i < N; i++) - p->a = *(p->b)*(*(p->b)); - - if (p->a != res) - abort (); - - /* POSIX ignores all but the 8 low-order bits, but other - environments may not. */ - return (p->a & 255); -} - -/*--------------------------------------------------------------------------*/ -/* The access &(p->a) is handled incorrectly in ipa-struct-reorg.c. */ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c b/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c deleted file mode 100644 index 92da94d..0000000 --- a/gcc/testsuite/gcc.dg/struct/wo_prof_two_strs.c +++ /dev/null @@ -1,68 +0,0 @@ -/* { dg-do compile } */ -/* { dg-do run } */ - -#include - -typedef struct -{ - int a; - float b; -}str_t1; - -typedef struct -{ - int c; - float d; -}str_t2; - -#ifdef STACK_SIZE -#if STACK_SIZE > 16000 -#define N 1000 -#else -#define N (STACK_SIZE/16) -#endif -#else -#define N 1000 -#endif - -str_t1 *p1; -str_t2 *p2; -int num; - -void -foo (void) -{ - int i; - - for (i=0; i < num; i++) - p2[i].c = 2; -} - -int -main () -{ - int i, r; - - r = rand (); - num = r > N ? N : r; - p1 = malloc (num * sizeof (str_t1)); - p2 = malloc (num * sizeof (str_t2)); - - if (p1 == NULL || p2 == NULL) - return 0; - - for (i = 0; i < num; i++) - p1[i].a = 1; - - foo (); - - for (i = 0; i < num; i++) - if (p1[i].a != 1 || p2[i].c != 2) - abort (); - - return 0; -} - -/*--------------------------------------------------------------------------*/ -/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "ipa_struct_reorg" { xfail *-*-* } } } */ -/* { dg-final { cleanup-ipa-dump "*" } } */ diff --git a/gcc/timevar.def b/gcc/timevar.def index ec800aa..cd306b8 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -70,7 +70,6 @@ DEFTIMEVAR (TV_WHOPR_WPA_LTRANS_EXEC , "whopr wpa->ltrans") DEFTIMEVAR (TV_IPA_REFERENCE , "ipa reference") DEFTIMEVAR (TV_IPA_PROFILE , "ipa profile") DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") -DEFTIMEVAR (TV_IPA_TYPE_ESCAPE , "ipa type escape") DEFTIMEVAR (TV_IPA_PTA , "ipa points-to") DEFTIMEVAR (TV_IPA_SRA , "ipa SRA") DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data") diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index d7b122b..9520c17 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -463,9 +463,7 @@ extern struct simple_ipa_opt_pass pass_ipa_free_lang_data; extern struct ipa_opt_pass_d pass_ipa_cp; extern struct ipa_opt_pass_d pass_ipa_reference; extern struct ipa_opt_pass_d pass_ipa_pure_const; -extern struct simple_ipa_opt_pass pass_ipa_type_escape; extern struct simple_ipa_opt_pass pass_ipa_pta; -extern struct simple_ipa_opt_pass pass_ipa_struct_reorg; extern struct ipa_opt_pass_d pass_ipa_lto_wpa_fixup; extern struct ipa_opt_pass_d pass_ipa_lto_finish_out; extern struct ipa_opt_pass_d pass_ipa_profile; diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index bd8953b..f7fc7d2 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -40,7 +40,6 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "convert.h" #include "params.h" -#include "ipa-type-escape.h" #include "vec.h" #include "bitmap.h" #include "vecprim.h" -- cgit v1.1