diff options
author | ogolovanevsky <ogolovanevsky@ogolovanevsky-lnx.caveonetworks.com> | 2014-05-16 17:39:06 -0700 |
---|---|---|
committer | ogolovanevsky <ogolovanevsky@ogolovanevsky-lnx.caveonetworks.com> | 2014-05-16 17:39:06 -0700 |
commit | 5409db70319c88dbf65a5f545d597b928e1832a8 (patch) | |
tree | 39013c3a185923b9602650ec7eb55465b331f693 | |
parent | 173e24e00006cbd561d0b2733f25343fc5dd0b17 (diff) | |
download | gcc-5409db70319c88dbf65a5f545d597b928e1832a8.tar.gz |
Initial ipa-struct-reorg pass and struct_reorg_generate_summery function implementation.
-rw-r--r-- | gcc/Makefile.in | 3 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/expr.c | 17 | ||||
-rwxr-xr-x | gcc/ipa-struct-reorg.c | 643 | ||||
-rwxr-xr-x | gcc/ipa-struct-reorg.h | 112 | ||||
-rw-r--r-- | gcc/passes.def | 1 | ||||
-rw-r--r-- | gcc/timevar.def | 1 | ||||
-rw-r--r-- | gcc/tree-pass.h | 1 | ||||
-rw-r--r-- | gcc/tree.c | 15 | ||||
-rw-r--r-- | gcc/tree.h | 4 |
10 files changed, 781 insertions, 20 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index daaeabd392a..fe056d13f07 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1278,6 +1278,7 @@ OBJS = \ ipa-pure-const.o \ ipa-reference.o \ ipa-ref.o \ + ipa-struct-reorg.o \ ipa-utils.o \ ipa.o \ ira.o \ @@ -2244,7 +2245,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/cselib.h $(srcdir)/basic-block.h $(srcdir)/ipa-ref.h $(srcdir)/cgraph.h \ $(srcdir)/reload.h $(srcdir)/caller-save.c $(srcdir)/symtab.c \ $(srcdir)/alias.c $(srcdir)/bitmap.c $(srcdir)/cselib.c $(srcdir)/cgraph.c \ - $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-utils.h \ + $(srcdir)/ipa-prop.c $(srcdir)/ipa-cp.c $(srcdir)/ipa-struct-reorg.c $(srcdir)/ipa-utils.h \ $(srcdir)/dbxout.c \ $(srcdir)/dwarf2out.h \ $(srcdir)/dwarf2asm.c \ diff --git a/gcc/common.opt b/gcc/common.opt index 411361cbbd3..a1034e17c68 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1409,8 +1409,8 @@ Common Ignore Does nothing. Preserved for backward compatibility. fipa-struct-reorg -Common Ignore -Does nothing. Preserved for backward compatibility. +Common Report Var(flag_ipa_struct_reorg) +Perform structure layout optimizations. fira-algorithm= Common Joined RejectNegative Enum(ira_algorithm) Var(flag_ira_algorithm) Init(IRA_ALGORITHM_CB) diff --git a/gcc/expr.c b/gcc/expr.c index ea23f199bda..1262f8481dd 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -5869,23 +5869,6 @@ store_constructor_field (rtx target, unsigned HOST_WIDE_INT bitsize, store_field (target, bitsize, bitpos, 0, 0, mode, exp, alias_set, false); } - -/* Returns the number of FIELD_DECLs in TYPE. */ - -static int -fields_length (const_tree type) -{ - tree t = TYPE_FIELDS (type); - int count = 0; - - for (; t; t = DECL_CHAIN (t)) - if (TREE_CODE (t) == FIELD_DECL) - ++count; - - return count; -} - - /* Store the value of constructor EXP into the rtx TARGET. TARGET is either a REG or a MEM; we know it cannot conflict, since safe_from_p has been called. diff --git a/gcc/ipa-struct-reorg.c b/gcc/ipa-struct-reorg.c new file mode 100755 index 00000000000..fc47862a7f3 --- /dev/null +++ b/gcc/ipa-struct-reorg.c @@ -0,0 +1,643 @@ +/* Struct-reorg optimizations. + Copyright (C) 2007-2014 Free Software Foundation, Inc. + Contributed by Olga Golovanevsky <golovanevsky.olga@gmail.com> + +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 +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "flags.h" +#include "tree-pass.h" +#include "print-tree.h" // for debug_tree +#include "diagnostic.h" +#include "ipa-struct-reorg.h" +#include "tree-pretty-print.h" +#include "cgraph.h" +#include "internal-fn.h" +#include "gimple-expr.h" +#include "tree-ssa-alias.h" +#include "gimple.h" +#include "gimple-iterator.h" + + +/* Vector of structures to be transformed. */ +typedef struct data_structure structure; +vec<structure, va_heap, vl_ptr> *structures; + +/* Forward declarations. */ +static bool is_equal_types (tree type1, tree type2); + +/* 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 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; +} + +/* 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 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 ((*structures), i, str) + if (is_equal_types (str->decl, type)) + return i; + + return structures->length (); +} + + +/* 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 = 0; //htab_create (32, field_acc_hash, field_acc_eq, NULL); + list[idx].count = 0; + list[idx].field_mapping = NULL_TREE; + } + + return list; +} + + +/* This function adds a structure TYPE to the vector of structures, + if it's not already there. */ + +static void +add_structure (tree type) +{ + structure node; + unsigned i; + int num_fields; + + type = TYPE_MAIN_VARIANT (type); + + i = find_structure (type); + + if (i != structures->length ()) { + if (dump_file) + { + fprintf (dump_file, "\nType \""); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, "\" already in 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 = 0; //htab_create (32, acc_hash, acc_eq, NULL); + node.new_types = 0; // node.new_types.create (num_fields); + node.count = 0; + + structures->safe_push (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 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); +} + +/* 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; +} + + +/* 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. */ + +static bool +type_is_candidate (tree type, tree *type_p) +{ + *type_p = NULL; + + if (!type) + return false; + + if (type) + { + type = TYPE_MAIN_VARIANT (strip_type (type)); + if (TREE_CODE (type) != RECORD_TYPE) + return false; + else + { + *type_p = type; + return true; + } + } + else + return false; +} + +/* 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. */ + +static bool +var_is_candidate (tree var, tree *type_p) +{ + tree type; + + *type_p = NULL; + + if (!var) + return false; + + type = get_type_of_var (var); + + return type_is_candidate (type, type_p); +} + +/* This function looks for structure types instantiated in the program. + The candidate types are added to the structures vector. */ + +static void +build_data_structure (void) +{ + tree var, type, p; + struct varpool_node *current_varpool; + struct cgraph_node *c_node; + //struct cgraph_node *callee; + //struct cgraph_edge *edge; + + /* Check global and static (global and local) variables. */ + FOR_EACH_VARIABLE (current_varpool) + { + var = current_varpool->decl; + + if (dump_file) { + fprintf (dump_file, "\nConsidering var: "); + print_generic_expr (dump_file, var, 0); + fprintf (dump_file, "\n"); + } + + if (var_is_candidate (var, &type)) { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, " is candidate. Adding to list of candidates...\n"); + + } + add_structure (type); + } else { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, "is not candidate. Skipping...\n"); + } + } + } + + /* Now add structures that are types of function parameters and + local variables. */ + FOR_EACH_FUNCTION(c_node) + { + struct function *fn = DECL_STRUCT_FUNCTION (c_node->decl); + unsigned ix; + + + if (dump_file) { + fprintf (dump_file, "\nConsidering c_node: "); + dump_cgraph_node (dump_file, c_node); + fprintf (dump_file, "\n"); + } + + + if (c_node->decl) { + if (dump_file) { + fprintf (dump_file, "\nFunc:"); + print_generic_expr (dump_file, c_node->decl, 0); + } + } + + + for (p = TYPE_ARG_TYPES (TREE_TYPE(c_node->decl)); p; p = TREE_CHAIN (p)) + { + tree arg_type = TREE_VALUE (p); + fprintf (dump_file, "\n\tArg:"); + print_generic_expr (dump_file, arg_type, 0); + //debug_tree (arg_type); + if (type_is_candidate (arg_type, &type)) { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, " is candidate. Adding to list of candidates...\n"); + } + add_structure (type); + } else { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, "is not candidate. Skipping...\n"); + } + } + } + + if (fn) + { + /* Check function local variables. */ + FOR_EACH_LOCAL_DECL (fn, ix, var) + { + if (dump_file) { + fprintf (dump_file, "\nConsidering var: "); + print_generic_expr (dump_file, var, 0); + fprintf (dump_file, "\n"); + } + + if (var_is_candidate (var, &type)) { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, " is candidate. Adding to list of candidates...\n"); + } + add_structure (type); + } else { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, "is not candidate. Skipping...\n"); + } + } + } + } + } + /* Scan parameters of functions that have no forward declarations. */ + FOR_EACH_DEFINED_FUNCTION(c_node) + { + struct function *fn = DECL_STRUCT_FUNCTION (c_node->decl); + basic_block bb; + gimple_stmt_iterator gsi; + + FOR_EACH_BB_FN (bb, fn) + { + + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + + if (is_gimple_call(stmt)) + { + tree target = gimple_call_fndecl (stmt); + tree op; + unsigned int i; + + if (dump_file) { + fprintf (dump_file, "\nTarget:"); + print_generic_expr (dump_file, target, 0); + } + + p = TYPE_ARG_TYPES (TREE_TYPE(target)); + if (p) { + if (dump_file) + fprintf (dump_file, " Continuing..."); + continue; + } + + for (i = 0; i < gimple_num_ops (stmt); i++) + { + op = gimple_op (stmt, i); + + if (dump_file) + { + fprintf (dump_file, "\nOp %d:", i); + print_generic_expr (dump_file, op, 0); + debug_tree(op); + } + + if (var_is_candidate (op, &type)) { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, " is candidate. Adding to list of candidates...\n"); + + } + add_structure (type); + } else { + if (dump_file) { + fprintf (dump_file, " Type "); + print_generic_expr (dump_file, type, 0); + fprintf (dump_file, "is not candidate. Skipping...\n"); + } + } + + } + } + } + } + } +} + +/* This function collects structures potential + for peeling transformation, and inserts + them into structures hashtable. */ + +static void +collect_structures (void) +{ + vec_alloc (structures, 32); + + /* Build data structures hashtable of all data structures + in the program. */ + build_data_structure (); +} + +static unsigned int +propagate (void) +{ + return 0; +} + +/* Deserialize the ipa info for lto. */ + +static void +struct_reorg_read_summary (void) +{ +} + +/* Serialize the ipa info for lto. */ + +static void +struct_reorg_write_summary (void) +{ +} + +/* Analyze each function in the cgraph. */ + +static void +struct_reorg_generate_summary (void) +{ + + collect_structures (); + +} + +static bool +gate_struct_reorg (void) +{ + return (flag_ipa_struct_reorg + /* Don't bother doing anything if the program has errors. */ + && !seen_error ()); +} + +namespace { + +const pass_data pass_data_ipa_struct_reorg = +{ + IPA_PASS, /* type */ + "struct-reorg", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + true, /* has_gate */ + true, /* has_execute */ + TV_IPA_STRUCT_REORG, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_ipa_struct_reorg : public ipa_opt_pass_d +{ +public: + pass_ipa_struct_reorg (gcc::context *ctxt) + : ipa_opt_pass_d (pass_data_ipa_struct_reorg, ctxt, + struct_reorg_generate_summary, /* generate_summary */ + struct_reorg_write_summary, /* write_summary */ + struct_reorg_read_summary, /* read_summary */ + NULL, /* write_optimization_summary */ + NULL, /* read_optimization_summary */ + NULL, /* stmt_fixup */ + 0, /* function_transform_todo_flags_start */ + NULL, /* function_transform */ + NULL) /* variable_transform */ + {} + + /* opt_pass methods: */ + bool gate () { return gate_struct_reorg (); } + unsigned int execute () { return propagate (); } + +}; // class pass_ipa_struct_reorg + +} // anon namespace + +ipa_opt_pass_d * +make_pass_ipa_struct_reorg (gcc::context *ctxt) +{ + return new pass_ipa_struct_reorg (ctxt); +} + diff --git a/gcc/ipa-struct-reorg.h b/gcc/ipa-struct-reorg.h new file mode 100755 index 00000000000..fd958a27bd7 --- /dev/null +++ b/gcc/ipa-struct-reorg.h @@ -0,0 +1,112 @@ +/* Struct-reorg optimizations. + Copyright (C) 2007-2014 Free Software Foundation, Inc. + Contributed by Olga Golovanevsky <golovanevsky.olga@gmail.com> + +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 +<http://www.gnu.org/licenses/>. */ + +#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, va_heap, vl_ptr> *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, va_heap, vl_ptr> *new_types; +}; + +typedef struct data_structure *d_str; + +#endif /* IPA_STRUCT_REORG_H */ diff --git a/gcc/passes.def b/gcc/passes.def index ee5feeee648..d58a0fbb972 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -111,6 +111,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ipa_inline); NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_reference); + NEXT_PASS (pass_ipa_struct_reorg); TERMINATE_PASS_LIST () /* Simple IPA passes executed after the regular passes. In WHOPR mode the diff --git a/gcc/timevar.def b/gcc/timevar.def index 44a061af7f4..23a83cd2add 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -90,6 +90,7 @@ DEFTIMEVAR (TV_IPA_PROFILE , "ipa profile") DEFTIMEVAR (TV_IPA_PURE_CONST , "ipa pure const") DEFTIMEVAR (TV_IPA_PTA , "ipa points-to") DEFTIMEVAR (TV_IPA_SRA , "ipa SRA") +DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg") DEFTIMEVAR (TV_IPA_FREE_LANG_DATA , "ipa free lang data") DEFTIMEVAR (TV_IPA_FREE_INLINE_SUMMARY, "ipa free inline summary") /* Time spent by constructing CFG. */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index fb942724cb9..f1cca8cea26 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -478,6 +478,7 @@ extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt); +extern ipa_opt_pass_d *make_pass_ipa_struct_reorg (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_omp_simd_clone (gcc::context *ctxt); diff --git a/gcc/tree.c b/gcc/tree.c index efee5e69cf2..fdeb7545b27 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -2479,6 +2479,21 @@ list_length (const_tree t) return len; } +/* Returns the number of FIELD_DECLs in TYPE. */ + +int +fields_length (const_tree type) +{ + tree t = TYPE_FIELDS (type); + int count = 0; + + for (; t; t = DECL_CHAIN (t)) + if (TREE_CODE (t) == FIELD_DECL) + ++count; + + return count; +} + /* Returns the first FIELD_DECL in the TYPE_FIELDS of the RECORD_TYPE or UNION_TYPE TYPE, or NULL_TREE if none. */ diff --git a/gcc/tree.h b/gcc/tree.h index 71d68321a55..4aa981efb7b 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -3843,6 +3843,10 @@ extern tree nreverse (tree); extern int list_length (const_tree); +/* Returns the number of FIELD_DECLs in a type. */ + +extern int fields_length (const_tree); + /* Returns the first FIELD_DECL in a type. */ extern tree first_field (const_tree); |