Projects
home:lf14:branches:Mega:23.09
gcc
_service:tar_scm:0021-StructReorderFields-Struc...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:0021-StructReorderFields-Structure-reorder-fields.patch of Package gcc
From 6997c9ad8985f6f0bfc16cdb46e7386af299a226 Mon Sep 17 00:00:00 2001 From: h00564365 <huangxiaoquan1@huawei.com> Date: Mon, 31 Jul 2023 22:01:56 +0800 Subject: [PATCH 21/22] [StructReorderFields] Structure reorder fields Introduce structure fields reordering optimization, that change fields ordering of C-like structures in order to better utilize spatial locality. --- gcc/common.opt | 4 + gcc/doc/invoke.texi | 1 + gcc/gimple-ssa-warn-access.cc | 2 +- gcc/ipa-free-lang-data.cc | 4 +- gcc/ipa-struct-reorg/escapes.def | 3 + gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 2545 +++++++++++++---- gcc/ipa-struct-reorg/ipa-struct-reorg.h | 14 +- gcc/passes.def | 1 + gcc/symbol-summary.h | 4 +- .../struct/rf_DTE_struct_instance_field.c | 75 + gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c | 94 + .../gcc.dg/struct/rf_check_ptr_layers_bug.c | 24 + .../gcc.dg/struct/rf_create_fields_bug.c | 82 + .../gcc.dg/struct/rf_create_new_func_bug.c | 56 + .../gcc.dg/struct/rf_ele_minus_verify.c | 60 + .../gcc.dg/struct/rf_escape_by_base.c | 83 + .../gcc.dg/struct/rf_external_func_types.c | 69 + gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c | 72 + .../gcc.dg/struct/rf_mem_ref_offset.c | 58 + .../struct/rf_mul_layer_ptr_record_bug.c | 30 + .../gcc.dg/struct/rf_pass_conflict.c | 109 + gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c | 87 + gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c | 71 + .../gcc.dg/struct/rf_ptr_negate_expr.c | 55 + gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c | 34 + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c | 55 + gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c | 58 + .../gcc.dg/struct/rf_rescusive_type.c | 57 + .../struct/rf_rewrite_assign_more_cmp.c | 65 + .../gcc.dg/struct/rf_rewrite_cond_bug.c | 72 + .../gcc.dg/struct/rf_rewrite_cond_more_cmp.c | 58 + .../gcc.dg/struct/rf_rewrite_phi_bug.c | 81 + gcc/testsuite/gcc.dg/struct/rf_shwi.c | 23 + gcc/testsuite/gcc.dg/struct/rf_visible_func.c | 92 + .../gcc.dg/struct/rf_void_ptr_param_func.c | 54 + gcc/testsuite/gcc.dg/struct/struct-reorg.exp | 15 +- gcc/testsuite/gcc.dg/struct/struct_reorg-1.c | 8 +- gcc/testsuite/gcc.dg/struct/struct_reorg-3.c | 9 +- gcc/timevar.def | 1 + gcc/tree-pass.h | 1 + 40 files changed, 3796 insertions(+), 490 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_external_func_types.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_shwi.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_visible_func.c create mode 100644 gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c diff --git a/gcc/common.opt b/gcc/common.opt index 0c7bd2f6c..98169de7c 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1954,6 +1954,10 @@ fipa-matrix-reorg Common Ignore Does nothing. Preserved for backward compatibility. +fipa-reorder-fields +Common Var(flag_ipa_reorder_fields) Init(0) Optimization +Perform structure fields reorder optimizations. + fipa-struct-reorg Common Var(flag_ipa_struct_reorg) Init(0) Optimization Perform structure layout optimizations. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 3485cc8af..2b376e0e9 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -526,6 +526,7 @@ Objective-C and Objective-C++ Dialects}. -finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol -finline-small-functions -fipa-modref -fipa-cp -fipa-cp-clone @gol -fipa-bit-cp -fipa-vrp -fipa-pta -fipa-profile -fipa-pure-const @gol +-fipa-reorder-fields @gol -fipa-struct-reorg @gol -fipa-reference -fipa-reference-addressable @gol -fipa-stack-alignment -fipa-icf -fira-algorithm=@var{algorithm} @gol diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index a24645783..7f5c92c96 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -2198,7 +2198,7 @@ pass_waccess::gate (function *) In pass waccess, it will traverse all SSA and cause ICE when handling these unused SSA. So temporarily disable pass waccess when enable structure optimizations. */ - if (flag_ipa_struct_reorg) + if (flag_ipa_struct_reorg || flag_ipa_reorder_fields) return false; return (warn_free_nonheap_object diff --git a/gcc/ipa-free-lang-data.cc b/gcc/ipa-free-lang-data.cc index 5450be9fe..a88381ddb 100644 --- a/gcc/ipa-free-lang-data.cc +++ b/gcc/ipa-free-lang-data.cc @@ -105,7 +105,7 @@ fld_simplified_type_name (tree type) /* Simplify type will cause that struct A and struct A within struct B are different type pointers, so skip it in structure optimizations. */ - if (flag_ipa_struct_reorg) + if (flag_ipa_struct_reorg || flag_ipa_reorder_fields) return TYPE_NAME (type); if (!TYPE_NAME (type) || TREE_CODE (TYPE_NAME (type)) != TYPE_DECL) @@ -349,7 +349,7 @@ fld_simplified_type (tree t, class free_lang_data_d *fld) /* Simplify type will cause that struct A and struct A within struct B are different type pointers, so skip it in structure optimizations. */ - if (flag_ipa_struct_reorg) + if (flag_ipa_struct_reorg || flag_ipa_reorder_fields) return t; if (POINTER_TYPE_P (t)) return fld_incomplete_type_of (t, fld); diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def index d825eb3e6..996a09bac 100644 --- a/gcc/ipa-struct-reorg/escapes.def +++ b/gcc/ipa-struct-reorg/escapes.def @@ -58,5 +58,8 @@ DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled DEF_ESCAPE (escape_return, "Type escapes via a return [not handled yet]") DEF_ESCAPE (escape_separate_instance, "Type escapes via a separate instance") DEF_ESCAPE (escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt") +DEF_ESCAPE (escape_via_orig_escape, "Type escapes via a original escape type") +DEF_ESCAPE (escape_instance_field, "Type escapes via a field of instance") +DEF_ESCAPE (escape_via_empty_no_orig, "Type escapes via empty and no original") #undef DEF_ESCAPE diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc index 9f790b28b..3e5f9538b 100644 --- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc +++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc @@ -207,50 +207,88 @@ lang_c_p (void) if (!language_string) return false; - if (strcmp (language_string, "GNU GIMPLE") == 0) + if (lang_GNU_C ()) + return true; + else if (strcmp (language_string, "GNU GIMPLE") == 0) // For LTO check { unsigned i = 0; - tree t = NULL; - const char *unit_string = NULL; + tree t = NULL_TREE; FOR_EACH_VEC_SAFE_ELT (all_translation_units, i, t) { - unit_string = TRANSLATION_UNIT_LANGUAGE (t); - if (!unit_string - || (strncmp (unit_string, "GNU C", 5) != 0) - || (!ISDIGIT (unit_string[5]))) + language_string = TRANSLATION_UNIT_LANGUAGE (t); + if (language_string == NULL + || strncmp (language_string, "GNU C", 5) + || (language_string[5] != '\0' + && !(ISDIGIT (language_string[5])))) return false; } return true; } - else if (strncmp (language_string, "GNU C", 5) == 0 - && ISDIGIT (language_string[5])) - return true; - return false; } +/* Get the number of pointer layers. */ + +int +get_ptr_layers (tree expr) +{ + int layers = 0; + while (POINTER_TYPE_P (expr) || TREE_CODE (expr) == ARRAY_TYPE) + { + layers++; + expr = TREE_TYPE (expr); + } + return layers; +} + +/* Comparison pointer layers. */ + +bool +cmp_ptr_layers (tree a, tree b) +{ + return get_ptr_layers (a) == get_ptr_layers (b); +} + +/* Return true if the ssa_name comes from the void* parameter. */ + +bool +is_from_void_ptr_parm (tree ssa_name) +{ + gcc_assert (TREE_CODE (ssa_name) == SSA_NAME); + tree var = SSA_NAME_VAR (ssa_name); + return (var && TREE_CODE (var) == PARM_DECL + && VOID_POINTER_P (TREE_TYPE (ssa_name))); +} + enum srmode { NORMAL = 0, - COMPLETE_STRUCT_RELAYOUT + COMPLETE_STRUCT_RELAYOUT, + STRUCT_REORDER_FIELDS }; -static bool is_result_of_mult (tree, tree *, tree); +static bool is_result_of_mult (tree arg, tree *num, tree struct_size); +static bool isptrptr (tree type); -} // anon namespace +srmode current_mode; +} // anon namespace namespace struct_reorg { +hash_map <tree, auto_vec <tree>> fields_to_finish; + /* Constructor of srfunction. */ srfunction::srfunction (cgraph_node *n) : node (n), old (NULL), newnode (NULL), - newf (NULL) -{} + newf (NULL), + is_safe_func (false) +{ +} /* Add an ARG to the list of arguments for the function. */ @@ -400,12 +438,13 @@ srtype::add_field_site (srfield *field) /* Constructor of DECL. */ -srdecl::srdecl (srtype *tp, tree decl, int argnum) +srdecl::srdecl (srtype *tp, tree decl, int argnum, tree orig_type) : type (tp), decl (decl), func (NULL_TREE), argumentnum (argnum), - visited (false) + visited (false), + orig_type (orig_type) { if (TREE_CODE (decl) == SSA_NAME) func = current_function_decl; @@ -429,17 +468,23 @@ srfunction::find_decl (tree decl) /* Record DECL of the TYPE with argument num ARG. */ srdecl * -srfunction::record_decl (srtype *type, tree decl, int arg) +srfunction::record_decl (srtype *type, tree decl, int arg, tree orig_type) { // Search for the decl to see if it is already there. srdecl *decl1 = find_decl (decl); if (decl1) - return decl1; + { + /* Added the orig_type information. */ + if (!decl1->orig_type && orig_type && isptrptr (orig_type)) + decl1->orig_type = orig_type; + return decl1; + } gcc_assert (type); - decl1 = new srdecl (type, decl, arg); + orig_type = isptrptr (TREE_TYPE (decl)) ? TREE_TYPE (decl) : orig_type; + decl1 = new srdecl (type, decl, arg, isptrptr (orig_type) ? orig_type : NULL); decls.safe_push (decl1); return decl1; } @@ -503,31 +548,21 @@ srtype::dump (FILE *f) print_generic_expr (f, type); fprintf (f, "(%d) { ", TYPE_UID (type)); if (escapes != does_not_escape) - fprintf (f, " escapes = \"%s\"\n", escape_reason ()); - fprintf (f, " fields = { "); + fprintf (f, "escapes = \"%s\"", escape_reason ()); + fprintf (f, "\nfields = {\n"); FOR_EACH_VEC_ELT (fields, i, field) - { - if (i == 0) - fprintf (f, "\n "); - else - fprintf (f, "\n, "); - field->dump (f); - } - fprintf (f, " }\n "); - fprintf (f, "\n accesses = {"); + field->dump (f); + fprintf (f, "}\n "); + + fprintf (f, "\naccesses = {\n"); FOR_EACH_VEC_ELT (accesses, i, access) - { - fprintf (f, "\n"); - access->dump (f); - } - fprintf (f, " }\n "); - fprintf (f, "\n functions = {"); + access->dump (f); + fprintf (f, "}\n "); + + fprintf (f, "\nfunctions = {\n"); FOR_EACH_VEC_ELT (functions, i, fn) - { - fprintf (f, " \n"); - fn->simple_dump (f); - } - fprintf (f, "\n }\n"); + fn->simple_dump (f); + fprintf (f, "}\n"); fprintf (f, "}\n"); } @@ -537,6 +572,8 @@ void srtype::simple_dump (FILE *f) { print_generic_expr (f, type); + if (current_mode == STRUCT_REORDER_FIELDS) + fprintf (f, "(%d)", TYPE_UID (type)); } /* Analyze the type and decide what to be done with it. */ @@ -572,6 +609,12 @@ srfield::create_new_fields (tree newtype[max_split], tree newfields[max_split], tree newlast[max_split]) { + if (current_mode == STRUCT_REORDER_FIELDS) + { + create_new_reorder_fields (newtype, newfields, newlast); + return; + } + tree nt[max_split]; for (unsigned i = 0; i < max_split; i++) @@ -620,6 +663,104 @@ srfield::create_new_fields (tree newtype[max_split], } } +/* Reorder fields. */ + +void +srfield::reorder_fields (tree newfields[max_split], tree newlast[max_split], + tree &field) +{ + /* Reorder fields in descending. + newfields: always stores the first member of the chain + and with the largest size. + field: indicates the node to be inserted. */ + if (newfields[clusternum] == NULL) + { + newfields[clusternum] = field; + newlast[clusternum] = field; + } + else + { + tree tmp = newfields[clusternum]; + if (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field))) + > tree_to_uhwi (TYPE_SIZE (TREE_TYPE (tmp)))) + { + DECL_CHAIN (field) = tmp; + newfields[clusternum] = field; + } + else + { + while (DECL_CHAIN (tmp) + && (tree_to_uhwi (TYPE_SIZE (TREE_TYPE (field))) + <= tree_to_uhwi ( + TYPE_SIZE (TREE_TYPE (DECL_CHAIN (tmp)))))) + tmp = DECL_CHAIN (tmp); + + /* Now tmp size > field size + insert field: tmp -> xx ==> tmp -> field -> xx. */ + DECL_CHAIN (field) = DECL_CHAIN (tmp); // field -> xx + DECL_CHAIN (tmp) = field; // tmp -> field + } + } +} + +/* Create the new reorder fields for this field. + newtype[max_split]: srtype's member variable, + newfields[max_split]: created by create_new_type func, + newlast[max_split]: created by create_new_type func. */ + +void +srfield::create_new_reorder_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]) +{ + /* newtype, corresponding to newtype[max_split] in srtype. */ + tree nt = NULL_TREE; + if (type == NULL) + /* Common var. */ + nt = fieldtype; + else + { + /* RECORD_TYPE var. */ + if (type->has_escaped ()) + nt = type->type; + else + nt = type->newtype[0]; + } + tree field = make_node (FIELD_DECL); + + /* Used for recursive types. + fields_to_finish: hase_map in the format of "type: {fieldA, fieldB}", + key : indicates the original type, + vaule: filed that need to be updated to newtype. */ + if (nt == NULL) + { + nt = make_node (RECORD_TYPE); + auto_vec <tree> &fields + = fields_to_finish.get_or_insert (inner_type (type->type)); + fields.safe_push (field); + } + + DECL_NAME (field) = DECL_NAME (fielddecl); + if (type == NULL) + /* Common members do not need to reconstruct. + Otherwise, int* -> int** or void* -> void**. */ + TREE_TYPE (field) = nt; + else + TREE_TYPE (field) = reconstruct_complex_type (TREE_TYPE (fielddecl), nt); + DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (fielddecl); + SET_DECL_ALIGN (field, DECL_ALIGN (fielddecl)); + DECL_USER_ALIGN (field) = DECL_USER_ALIGN (fielddecl); + TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (fielddecl); + DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (fielddecl); + TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (fielddecl); + DECL_CONTEXT (field) = newtype[clusternum]; + + reorder_fields (newfields, newlast, field); + + /* srfield member variable, which stores the new field decl. */ + newfield[0] = field; +} + /* Create the new TYPE corresponding to THIS type. */ bool @@ -655,7 +796,8 @@ srtype::create_new_type (void) /* If the fields' types did have a change or we are not splitting the struct into two clusters, then just return false and don't change the type. */ - if (!createnewtype && maxclusters == 0) + if (!createnewtype && maxclusters == 0 + && current_mode != STRUCT_REORDER_FIELDS) { newtype[0] = type; return false; @@ -664,6 +806,7 @@ srtype::create_new_type (void) /* Should have at most max_split clusters. */ gcc_assert (maxclusters < max_split); + /* Record the first member of the field chain. */ tree newfields[max_split]; tree newlast[max_split]; @@ -682,7 +825,8 @@ srtype::create_new_type (void) sprintf (id, "%d", i); if (tname) { - name = concat (tname, ".reorg.", id, NULL); + name = concat (tname, current_mode == STRUCT_REORDER_FIELDS + ? ".reorder." : ".reorg.", id, NULL); TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier (name), @@ -718,6 +862,7 @@ srtype::create_new_type (void) for (unsigned i = 0; i < maxclusters; i++) { print_generic_expr (dump_file, newtype[i]); + fprintf (dump_file, "(%d)", TYPE_UID (newtype[i])); fprintf (dump_file, "\n"); } } @@ -776,8 +921,12 @@ srfunction::create_new_decls (void) tree newinner[max_split]; memset (newinner, 0, sizeof (newinner)); for (unsigned j = 0; j < max_split && type->newtype[j]; j++) - newtype1[j] = reconstruct_complex_type (TREE_TYPE (decls[i]->decl), - type->newtype[j]); + { + newtype1[j] = reconstruct_complex_type ( + isptrptr (decls[i]->orig_type) ? decls[i]->orig_type + : TREE_TYPE (decls[i]->decl), + type->newtype[j]); + } if (inner) { srdecl *in = find_decl (inner); @@ -825,7 +974,8 @@ srfunction::create_new_decls (void) sprintf (id, "%d", j); if (tname) { - name = concat (tname, ".reorg.", id, NULL); + name = concat (tname, current_mode == STRUCT_REORDER_FIELDS + ? ".reorder." : ".reorg.", id, NULL); new_name = get_identifier (name); free (name); } @@ -850,7 +1000,6 @@ srfunction::create_new_decls (void) if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Created New decls for decl:\n"); - fprintf (dump_file, "\n"); decls[i]->dump (dump_file); fprintf (dump_file, "\n"); for (unsigned j = 0; j < max_split && decls[i]->newdecl[j]; j++) @@ -876,7 +1025,7 @@ srfield::dump (FILE *f) fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset); fprintf (f, ", type = "); print_generic_expr (f, fieldtype); - fprintf (f, "\n}\n"); + fprintf (f, "}\n"); } /* A simplified dump out the field structure to FILE. */ @@ -908,7 +1057,7 @@ sraccess::dump (FILE *f) fprintf (f, " in function: %s/%d", node->name (), node->order); fprintf (f, ", stmt:\n"); print_gimple_stmt (f, stmt, 0); - fprintf (f, "\n }\n"); + fprintf (f, "}\n"); } /* Dump out the decl structure to FILE. */ @@ -1023,8 +1172,7 @@ public: // Constructors ipa_struct_reorg (void) : current_function (NULL), - done_recording (false), - current_mode (NORMAL) + done_recording (false) {} // Fields @@ -1032,9 +1180,10 @@ public: auto_vec_del<srfunction> functions; srglobal globals; srfunction *current_function; + hash_set <cgraph_node *> safe_functions; + auto_vec<srtype *> ext_func_types; bool done_recording; - srmode current_mode; // Methods unsigned execute (enum srmode mode); @@ -1042,6 +1191,7 @@ public: gimple *stmt = NULL); void dump_types (FILE *f); + void dump_newtypes (FILE *f); void dump_types_escaped (FILE *f); void dump_functions (FILE *f); void record_accesses (void); @@ -1049,6 +1199,9 @@ public: bool walk_field_for_cycles (srtype *); void prune_escaped_types (void); void propagate_escape (void); + void propagate_escape_via_original (void); + void propagate_escape_via_empty_with_no_original (void); + void propagate_escape_via_ext_func_types (void); void analyze_types (void); void clear_visited (void); bool create_new_types (void); @@ -1060,8 +1213,11 @@ public: srdecl *record_var (tree decl, escape_type escapes = does_not_escape, int arg = -1); + void record_safe_func_with_void_ptr_parm (void); srfunction *record_function (cgraph_node *node); srfunction *find_function (cgraph_node *node); + void record_field_type (tree field, srtype *base_srtype); + void record_struct_field_types (tree base_type, srtype *base_srtype); srtype *record_type (tree type); void process_union (tree type); srtype *find_type (tree type); @@ -1072,7 +1228,7 @@ public: void record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt); void mark_expr_escape (tree, escape_type, gimple *stmt); bool handled_allocation_stmt (gimple *stmt); - tree allocate_size (srtype *t, gimple *stmt); + tree allocate_size (srtype *t, srdecl *decl, gimple *stmt); void mark_decls_in_as_not_needed (tree fn); @@ -1087,21 +1243,23 @@ public: bool ignore_missing_decl = false); bool rewrite_lhs_rhs (tree lhs, tree rhs, tree newlhs[max_split], tree newrhs[max_split]); - bool get_type_field (tree expr, tree &base, bool &indirect, - srtype *&type, srfield *&field, - bool &realpart, bool &imagpart, - bool &address, bool should_create = false, - bool can_escape = false); + bool get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, + srfield *&field, bool &realpart, bool &imagpart, + bool &address, bool &escape_from_base, + bool should_create = false, bool can_escape = false); bool wholeaccess (tree expr, tree base, tree accesstype, srtype *t); void check_alloc_num (gimple *stmt, srtype *type); + void check_definition_assign (srdecl *decl, vec<srdecl *> &worklist); + void check_definition_call (srdecl *decl, vec<srdecl *> &worklist); void check_definition (srdecl *decl, vec<srdecl *> &); void check_uses (srdecl *decl, vec<srdecl *> &); void check_use (srdecl *decl, gimple *stmt, vec<srdecl *> &); - void check_type_and_push (tree newdecl, srtype *type, + void check_type_and_push (tree newdecl, srdecl *decl, vec<srdecl *> &worklist, gimple *stmt); void check_other_side (srdecl *decl, tree other, gimple *stmt, vec<srdecl *> &worklist); + void check_ptr_layers (tree a_expr, tree b_expr, gimple *stmt); void find_vars (gimple *stmt); void find_var (tree expr, gimple *stmt); @@ -1703,9 +1861,42 @@ ipa_struct_reorg::dump_types (FILE *f) srtype *type; FOR_EACH_VEC_ELT (types, i, type) { + fprintf (f, "======= the %dth type: ======\n", i); type->dump (f); + fprintf (f, "\n"); + } +} + +/* Dump all of the created newtypes to file F. */ + +void +ipa_struct_reorg::dump_newtypes (FILE *f) +{ + unsigned i = 0; + srtype *type = NULL; + FOR_EACH_VEC_ELT (types, i, type) + { + if (type->has_escaped ()) + continue; + fprintf (f, "======= the %dth newtype: ======\n", i); + fprintf (f, "type : "); + print_generic_expr (f, type->newtype[0]); + fprintf (f, "(%d) ", TYPE_UID (type->newtype[0])); + fprintf (f, "{ "); + fprintf (f, "\nfields = {\n"); + + for (tree field = TYPE_FIELDS (TYPE_MAIN_VARIANT (type->newtype[0])); + field; field = DECL_CHAIN (field)) + { + fprintf (f, "field (%d) ", DECL_UID (field)); + fprintf (f, "{"); + fprintf (f, "type = "); + print_generic_expr (f, TREE_TYPE (field)); + fprintf (f, "}\n"); + } + fprintf (f, "}\n "); + fprintf (f, "\n"); } - fprintf (f, "\n"); } /* Dump all of the recorded types to file F. */ @@ -1803,6 +1994,8 @@ isarraytype (tree type) static bool isptrptr (tree type) { + if (type == NULL) + return false; bool firstptr = false; while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE) { @@ -1817,154 +2010,740 @@ isptrptr (tree type) return false; } -/* Return the escape type which corresponds to if - this is an volatile type, an array type or a pointer - to a pointer type. */ +/* Adding node to map and stack. */ -static escape_type -escape_type_volatile_array_or_ptrptr (tree type) +bool +add_node (tree node, int layers, hash_map <tree, int> &map, + auto_vec <tree> &stack) { - if (isvolatile_type (type)) - return escape_volatile; - if (isarraytype (type)) - return escape_array; - if (isptrptr (type)) - return escape_ptr_ptr; - return does_not_escape; + if (TREE_CODE (node) != SSA_NAME) + return false; + if (map.get (node) == NULL) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, " "); + fprintf (dump_file, "add node: \t\t"); + print_generic_expr (dump_file, node); + fprintf (dump_file, ",\t\tptr layers: %d: \n", layers); + } + map.put (node, layers); + stack.safe_push (node); + } + else if (*map.get (node) != layers) + return false; + return true; } -/* Record TYPE if not already recorded. */ +/* Check the number of pointer layers of the gimple phi in definition. */ -srtype * -ipa_struct_reorg::record_type (tree type) +bool +check_def_phi (tree def_node, hash_map <tree, int> &ptr_layers) { - unsigned typeuid; - - /* Get the main variant as we are going - to record that type only. */ - type = TYPE_MAIN_VARIANT (type); - typeuid = TYPE_UID (type); + bool res = true; + gimple *def_stmt = SSA_NAME_DEF_STMT (def_node); + for (unsigned j = 0; j < gimple_phi_num_args (def_stmt); j++) + { + tree phi_node = gimple_phi_arg_def (def_stmt, j); + if (integer_zerop (phi_node)) + continue; + if (ptr_layers.get (phi_node) == NULL) + return false; + res &= *ptr_layers.get (def_node) == *ptr_layers.get (phi_node); + } + return res; +} - srtype *type1; +/* Check the number of pointer layers of the gimple assign in definition. */ - type1 = find_type (type); - if (type1) - return type1; +bool +check_def_assign (tree def_node, hash_map <tree, int> &ptr_layers) +{ + bool res = true; + gimple *def_stmt = SSA_NAME_DEF_STMT (def_node); + gimple_rhs_class rhs_class = gimple_assign_rhs_class (def_stmt); + tree_code rhs_code = gimple_assign_rhs_code (def_stmt); + tree rhs1 = gimple_assign_rhs1 (def_stmt); + tree rhs1_base = TREE_CODE (rhs1) == MEM_REF ? TREE_OPERAND (rhs1, 0) : rhs1; + if (ptr_layers.get (rhs1_base) == NULL) + return false; + if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS) + { + if (TREE_CODE (rhs1) == SSA_NAME) + res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); + else if (TREE_CODE (rhs1) == MEM_REF) + res = *ptr_layers.get (def_node) + == *ptr_layers.get (TREE_OPERAND (rhs1, 0)); + else + { + return false; + } + } + else if (rhs_class == GIMPLE_BINARY_RHS) + { + if (rhs_code == POINTER_PLUS_EXPR) + res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); + else if (rhs_code == BIT_AND_EXPR) + res = *ptr_layers.get (def_node) == *ptr_layers.get (rhs1); + else + return false; + } + else + return false; + return res; +} - /* If already done recording just return NULL. */ - if (done_recording) - return NULL; +/* Check node definition. */ +bool +check_node_def (hash_map <tree, int> &ptr_layers) +{ + bool res = true; if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "Recording new type: %u.\n", typeuid); - - type1 = new srtype (type); - types.safe_push (type1); - - /* If the type has an user alignment set, - that means the user most likely already setup the type. */ - if (TYPE_USER_ALIGN (type)) - type1->mark_escape (escape_user_alignment, NULL); - - for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + fprintf (dump_file, "\n======== check node definition ========\n"); + for (unsigned i = 1; i < num_ssa_names; ++i) { - if (TREE_CODE (field) == FIELD_DECL) + tree name = ssa_name (i); + if (name && ptr_layers.get (name) != NULL) { - tree t = TREE_TYPE (field); - process_union (t); - if (TREE_CODE (inner_type (t)) == UNION_TYPE - || TREE_CODE (inner_type (t)) == QUAL_UNION_TYPE) - type1->mark_escape (escape_union, NULL); - if (isvolatile_type (t)) - type1->mark_escape (escape_volatile, NULL); - escape_type e = escape_type_volatile_array_or_ptrptr (t); - if (e != does_not_escape) - type1->mark_escape (e, NULL); - if (handled_type (t)) - { - srtype *t1 = record_type (inner_type (t)); - srfield *f = type1->find_field (int_byte_position (field)); - /* We might have an variable sized type which - we don't set the handle. */ - if (f) - { - f->type = t1; - t1->add_field_site (f); - } - if (t1 == type1 && current_mode != COMPLETE_STRUCT_RELAYOUT) - type1->mark_escape (escape_rescusive_type, NULL); - } + gimple *def_stmt = SSA_NAME_DEF_STMT (name); + if (dump_file && (dump_flags & TDF_DETAILS) + && gimple_code (def_stmt) != GIMPLE_DEBUG) + print_gimple_stmt (dump_file, def_stmt, 0); + + if (gimple_code (def_stmt) == GIMPLE_PHI) + res = check_def_phi (name, ptr_layers); + else if (gimple_code (def_stmt) == GIMPLE_ASSIGN) + res = check_def_assign (name, ptr_layers); + else if (gimple_code (def_stmt) == GIMPLE_NOP) + continue; + else + return false; } } + return res; +} - return type1; +/* Check pointer usage. */ + +bool +check_record_ptr_usage (gimple *use_stmt, tree ¤t_node, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack) +{ + gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); + tree rhs1 = gimple_assign_rhs1 (use_stmt); + tree lhs = gimple_assign_lhs (use_stmt); + if (rhs_class != GIMPLE_SINGLE_RHS + || (TREE_CODE (rhs1) != COMPONENT_REF && TREE_CODE (rhs1) != SSA_NAME) + || (TREE_CODE (lhs) != MEM_REF && TREE_CODE (lhs) != SSA_NAME)) + return false; + + bool res = true; + /* MEM[(long int *)a_1] = _1; (record). + If lhs is ssa_name, lhs cannot be the current node. + _2 = _1->flow; (No record). */ + if (TREE_CODE (rhs1) == SSA_NAME) + { + tree tmp = (rhs1 != current_node) ? rhs1 : lhs; + if (TREE_CODE (tmp) == MEM_REF) + res = add_node (TREE_OPERAND (tmp, 0), + *ptr_layers.get (current_node) + 1, + ptr_layers, ssa_name_stack); + else + res = add_node (tmp, *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + } + else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == COMPONENT_REF) + res = !(POINTER_TYPE_P (TREE_TYPE (rhs1))); + else + res = false; + return res; } -/* Mark TYPE as escaping with ESCAPES as the reason. */ +/* Check and record a single node. */ -void -ipa_struct_reorg::mark_type_as_escape (tree type, - escape_type escapes, - gimple *stmt) +bool +check_record_single_node (gimple *use_stmt, tree ¤t_node, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack) { - if (handled_type (type)) - { - srtype *stype = record_type (inner_type (type)); + gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); + tree rhs1 = gimple_assign_rhs1 (use_stmt); + tree lhs = gimple_assign_lhs (use_stmt); + gcc_assert (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS); - if (!stype) - return; + if ((TREE_CODE (rhs1) != SSA_NAME && TREE_CODE (rhs1) != MEM_REF) + || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (lhs) != MEM_REF)) + return false; - stype->mark_escape (escapes, stmt); + bool res = true; + if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == MEM_REF) + /* Add such as: _2 = MEM[(struct arc_t * *)_1]. */ + res = add_node (lhs, *ptr_layers.get (current_node) - 1, + ptr_layers, ssa_name_stack); + else if (TREE_CODE (lhs) == MEM_REF && TREE_CODE (rhs1) == SSA_NAME) + { + /* Add such as: MEM[(long int *)a_1] = _1. */ + if (rhs1 == current_node) + res = add_node (TREE_OPERAND (lhs, 0), + *ptr_layers.get (current_node) + 1, + ptr_layers, ssa_name_stack); + else + res = add_node (rhs1, *ptr_layers.get (current_node) - 1, + ptr_layers, ssa_name_stack); } + else if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == SSA_NAME) + res = add_node (lhs, *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + else + res = false; + + return res; } -/* Maybe process the union of type TYPE, such that marking all of the fields' - types as being escaping. */ +/* Check and record multiple nodes. */ -void -ipa_struct_reorg::process_union (tree type) +bool +check_record_mult_node (gimple *use_stmt, tree ¤t_node, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack) { - static hash_set<tree> unions_recorded; + gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); + tree_code rhs_code = gimple_assign_rhs_code (use_stmt); + tree rhs1 = gimple_assign_rhs1 (use_stmt); + tree lhs = gimple_assign_lhs (use_stmt); + tree rhs2 = gimple_assign_rhs2 (use_stmt); + gcc_assert (rhs_class == GIMPLE_BINARY_RHS); + + if ((rhs_code != POINTER_PLUS_EXPR && rhs_code != POINTER_DIFF_EXPR + && rhs_code != BIT_AND_EXPR) + || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (rhs1) != SSA_NAME)) + return false; - type = inner_type (type); - if (TREE_CODE (type) != UNION_TYPE - && TREE_CODE (type) != QUAL_UNION_TYPE) - return; + bool res = true; + if (rhs_code == POINTER_PLUS_EXPR) + res = add_node (lhs == current_node ? rhs1 : lhs, + *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + else if (rhs_code == POINTER_DIFF_EXPR) + res = add_node (rhs1 != current_node ? rhs1 : rhs2, + *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + else if (rhs_code == BIT_AND_EXPR) + { + if (TREE_CODE (rhs2) != INTEGER_CST) + return false; + res = add_node (lhs == current_node ? rhs1 : lhs, + *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + } + return res; +} - type = TYPE_MAIN_VARIANT (type); +/* Check whether gimple assign is correctly used and record node. */ - /* We already processed this type. */ - if (unions_recorded.add (type)) - return; +bool +check_record_assign (tree ¤t_node, gimple *use_stmt, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack) +{ + gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt); + if (*ptr_layers.get (current_node) == 1) + return check_record_ptr_usage (use_stmt, current_node, + ptr_layers, ssa_name_stack); + else if (*ptr_layers.get (current_node) > 1) + { + if (rhs_class != GIMPLE_BINARY_RHS + && rhs_class != GIMPLE_UNARY_RHS + && rhs_class != GIMPLE_SINGLE_RHS) + return false; - for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS) + return check_record_single_node (use_stmt, current_node, + ptr_layers, ssa_name_stack); + else if (rhs_class == GIMPLE_BINARY_RHS) + return check_record_mult_node (use_stmt, current_node, + ptr_layers, ssa_name_stack); + } + else + return false; + + return true; +} + +/* Check whether gimple phi is correctly used and record node. */ + +bool +check_record_phi (tree ¤t_node, gimple *use_stmt, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack) +{ + bool res = true; + res &= add_node (gimple_phi_result (use_stmt), *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); + + for (unsigned i = 0; i < gimple_phi_num_args (use_stmt); i++) { - if (TREE_CODE (field) == FIELD_DECL) - { - mark_type_as_escape (TREE_TYPE (field), escape_union); - process_union (TREE_TYPE (field)); - } + if (integer_zerop (gimple_phi_arg_def (use_stmt, i))) + continue; + res &= add_node (gimple_phi_arg_def (use_stmt, i), + *ptr_layers.get (current_node), + ptr_layers, ssa_name_stack); } + return res; } -/* Used by record_var function as a callback to walk_tree. - Mark the type as escaping if it has expressions which - cannot be converted for global initializations. */ +/* Check the use of callee. */ -static tree -record_init_types (tree *tp, int *walk_subtrees, void *data) +bool +check_callee (cgraph_node *node, gimple *stmt, + hash_map <tree, int> &ptr_layers, int input_layers) { - ipa_struct_reorg *c = (ipa_struct_reorg *)data; - switch (TREE_CODE (*tp)) + /* caller main () + { spec_qsort.constprop (_649, _651); } + def spec_qsort.constprop (void * a, size_t n) + { spec_qsort.constprop (a_1, _139); } */ + /* In safe functions, only call itself is allowed. */ + if (node->get_edge (stmt)->callee != node) + return false; + tree input_node = gimple_call_arg (stmt, 0); + if (ptr_layers.get (input_node) == NULL + || *ptr_layers.get (input_node) != input_layers) + return false; + if (SSA_NAME_VAR (input_node) != DECL_ARGUMENTS (node->decl)) + return false; + + for (unsigned i = 1; i < gimple_call_num_args (stmt); i++) { - CASE_CONVERT: - case COMPONENT_REF: - case VIEW_CONVERT_EXPR: - case ARRAY_REF: - { - tree typeouter = TREE_TYPE (*tp); - tree typeinner = TREE_TYPE (TREE_OPERAND (*tp, 0)); - c->mark_type_as_escape (typeouter, escape_via_global_init); + if (ptr_layers.get (gimple_call_arg (stmt, i)) != NULL) + return false; + } + return true; +} + +/* Check the usage of input nodes and related nodes. */ + +bool +check_node_use (cgraph_node *node, tree current_node, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack, + int input_layers) +{ + imm_use_iterator imm_iter; + gimple *use_stmt = NULL; + bool res = true; + /* Use FOR_EACH_IMM_USE_STMT as an indirect edge + to search for possible related nodes and push to stack. */ + FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, current_node) + { + if (dump_file && (dump_flags & TDF_DETAILS) + && gimple_code (use_stmt) != GIMPLE_DEBUG) + { + fprintf (dump_file, "%*s", 4, ""); + print_gimple_stmt (dump_file, use_stmt, 0); + } + /* For other types of gimple, do not record the node. */ + if (res) + { + if (gimple_code (use_stmt) == GIMPLE_PHI) + res = check_record_phi (current_node, use_stmt, + ptr_layers, ssa_name_stack); + else if (gimple_code (use_stmt) == GIMPLE_ASSIGN) + res = check_record_assign (current_node, use_stmt, + ptr_layers, ssa_name_stack); + else if (gimple_code (use_stmt) == GIMPLE_CALL) + res = check_callee (node, use_stmt, ptr_layers, input_layers); + else if (gimple_code (use_stmt) == GIMPLE_RETURN) + res = false; + } + } + return res; +} + +/* Trace the pointer layers of void node. */ + +bool +get_void_node_ptr_layers (tree input, int &input_layers) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "input type is void* node\n"); + imm_use_iterator imm_iter; + gimple *use_stmt = NULL; + FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, input) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + print_gimple_stmt (dump_file, use_stmt, 0); + if (gimple_code (use_stmt) == GIMPLE_ASSIGN + && gimple_assign_rhs_class (use_stmt) == GIMPLE_SINGLE_RHS) + { + tree rhs1 = gimple_assign_rhs1 (use_stmt); + tree lhs = gimple_assign_lhs (use_stmt); + if (TREE_CODE (lhs) == SSA_NAME && handled_type (TREE_TYPE (lhs))) + { + if (TREE_CODE (rhs1) == MEM_REF) + { + input_layers = get_ptr_layers (TREE_TYPE (lhs)) + 1; + return true; + } + } + } + } + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "end trace pointer layers of void* node\n"); + return false; +} + +/* Preparing the First Node for DFS. */ + +bool +set_init_node (cgraph_node *node, cgraph_edge *caller, + hash_map <tree, int> &ptr_layers, + auto_vec <tree> &ssa_name_stack, int &input_layers) +{ + /* Set input_layer + caller spec_qsort.constprop (_649, _651) + |-- Obtains the actual ptr layer + from the input node. */ + caller->caller->get_untransformed_body (); + if (caller->call_stmt == NULL + || gimple_call_num_args (caller->call_stmt) == 0) + return false; + tree input = gimple_call_arg (caller->call_stmt, 0); + if (!(POINTER_TYPE_P (TREE_TYPE (input)) + || TREE_CODE (TREE_TYPE (input)) == ARRAY_TYPE)) + return false; + if (handled_type (TREE_TYPE (input))) + input_layers = get_ptr_layers (TREE_TYPE (input)); + else + { + if (VOID_POINTER_P (TREE_TYPE (input))) + { + if (!get_void_node_ptr_layers (input, input_layers)) + return false; + } + } + + /* Set initial node + def spec_qsort.constprop (void * a, size_t n) + |-- Find the initial ssa_name + from the parameter node. */ + tree parm = DECL_ARGUMENTS (node->decl); + for (unsigned j = 1; j < num_ssa_names; ++j) + { + tree name = ssa_name (j); + if (!name || has_zero_uses (name) || virtual_operand_p (name)) + continue; + if (SSA_NAME_VAR (name) == parm + && gimple_code (SSA_NAME_DEF_STMT (name)) == GIMPLE_NOP) + { + if (!add_node (name, input_layers, ptr_layers, ssa_name_stack)) + return false; + } + } + return !ssa_name_stack.is_empty (); +} + +/* Check the usage of each call. */ + +bool +check_each_call (cgraph_node *node, cgraph_edge *caller) +{ + hash_map <tree, int> ptr_layers; + auto_vec <tree> ssa_name_stack; + int input_layers = 0; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "======== check each call : %s/%u ========\n", + node->name (), node->order); + if (!set_init_node (node, caller, ptr_layers, ssa_name_stack, input_layers)) + return false; + int i = 0; + while (!ssa_name_stack.is_empty ()) + { + tree current_node = ssa_name_stack.pop (); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\ncur node %d: \t", i++); + print_generic_expr (dump_file, current_node); + fprintf (dump_file, ",\t\tptr layers: %d: \n", + *ptr_layers.get (current_node)); + } + if (get_ptr_layers (TREE_TYPE (current_node)) + > *ptr_layers.get (current_node)) + return false; + if (!check_node_use (node, current_node, ptr_layers, ssa_name_stack, + input_layers)) + return false; + } + + if (!check_node_def (ptr_layers)) + return false; + return true; +} + +/* Filter out function: void func (void*, int n), + and the function has no static variable, no structure-related variable, + and no global variable is used. */ + +bool +filter_func (cgraph_node *node) +{ + tree parm = DECL_ARGUMENTS (node->decl); + if (!(parm && VOID_POINTER_P (TREE_TYPE (parm)) + && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (node->decl))))) + return false; + + for (parm = DECL_CHAIN (parm); parm; parm = DECL_CHAIN (parm)) + { + if (TREE_CODE (TREE_TYPE (parm)) != INTEGER_TYPE) + return false; + } + + if (DECL_STRUCT_FUNCTION (node->decl)->static_chain_decl) + return false; + + tree var = NULL_TREE; + unsigned int i = 0; + bool res = true; + FOR_EACH_LOCAL_DECL (cfun, i, var) + { + if (TREE_CODE (var) == VAR_DECL && handled_type (TREE_TYPE (var))) + res = false; + } + if (!res) + return false; + + for (unsigned j = 1; j < num_ssa_names; ++j) + { + tree name = ssa_name (j); + if (!name || has_zero_uses (name) || virtual_operand_p (name)) + continue; + tree var = SSA_NAME_VAR (name); + if (var && TREE_CODE (var) == VAR_DECL && is_global_var (var)) + return false; + } + return true; +} + +/* Check whether the function with the void* parameter and uses the input node + safely. + In these functions only component_ref can be used to dereference the last + layer of the input structure pointer. The hack operation pointer offset + after type cast cannot be used. +*/ + +bool +is_safe_func_with_void_ptr_parm (cgraph_node *node) +{ + if (!filter_func (node)) + return false; + + /* Distinguish Recursive Callers + normal_callers: main () + { spec_qsort.constprop (_649, _651); } + definition: spec_qsort.constprop (void * a, size_t n) + recursive_callers: { spec_qsort.constprop (a_1, _139); } */ + auto_vec<cgraph_edge *> callers = node->collect_callers (); + auto_vec<cgraph_edge *> normal_callers; + for (unsigned i = 0; i < callers.length (); i++) + { + if (callers[i]->caller != node) + normal_callers.safe_push (callers[i]); + } + if (normal_callers.length () == 0) + return false; + + for (unsigned i = 0; i < normal_callers.length (); i++) + { + if (!check_each_call (node, normal_callers[i])) + return false; + } + return true; +} + +/* Return the escape type which corresponds to if + this is an volatile type, an array type or a pointer + to a pointer type. */ + +static escape_type +escape_type_volatile_array_or_ptrptr (tree type) +{ + if (isvolatile_type (type)) + return escape_volatile; + if (isarraytype (type)) + return escape_array; + if (isptrptr (type) && (current_mode != STRUCT_REORDER_FIELDS)) + return escape_ptr_ptr; + return does_not_escape; +} + +/* Record field type. */ + +void +ipa_struct_reorg::record_field_type (tree field, srtype *base_srtype) +{ + tree field_type = TREE_TYPE (field); + /* The uid of the type in the structure is different + from that outside the structure. */ + srtype *field_srtype = record_type (inner_type (field_type)); + srfield *field_srfield = base_srtype->find_field (int_byte_position (field)); + /* We might have an variable sized type which we don't set the handle. */ + if (field_srfield) + { + field_srfield->type = field_srtype; + field_srtype->add_field_site (field_srfield); + } + if (field_srtype == base_srtype && current_mode != COMPLETE_STRUCT_RELAYOUT + && current_mode != STRUCT_REORDER_FIELDS) + base_srtype->mark_escape (escape_rescusive_type, NULL); + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ + if (current_mode == STRUCT_REORDER_FIELDS + && TREE_CODE (field_type) == RECORD_TYPE) + field_srtype->mark_escape (escape_instance_field, NULL); +} + +/* Record structure all field types. */ + +void +ipa_struct_reorg::record_struct_field_types (tree base_type, + srtype *base_srtype) +{ + for (tree field = TYPE_FIELDS (base_type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL) + { + tree field_type = TREE_TYPE (field); + process_union (field_type); + if (TREE_CODE (inner_type (field_type)) == UNION_TYPE + || TREE_CODE (inner_type (field_type)) == QUAL_UNION_TYPE) + base_srtype->mark_escape (escape_union, NULL); + if (isvolatile_type (field_type)) + base_srtype->mark_escape (escape_volatile, NULL); + escape_type e = escape_type_volatile_array_or_ptrptr (field_type); + if (e != does_not_escape) + base_srtype->mark_escape (e, NULL); + /* Types of non-pointer field are difficult to track the correctness + of the rewrite when it used by the escaped type. */ + if (current_mode == STRUCT_REORDER_FIELDS + && TREE_CODE (field_type) == RECORD_TYPE) + base_srtype->mark_escape (escape_instance_field, NULL); + if (handled_type (field_type)) + record_field_type (field, base_srtype); + } + } +} + +/* Record TYPE if not already recorded. */ + +srtype * +ipa_struct_reorg::record_type (tree type) +{ + unsigned typeuid; + + /* Get the main variant as we are going + to record that type only. */ + type = TYPE_MAIN_VARIANT (type); + typeuid = TYPE_UID (type); + + srtype *type1; + + type1 = find_type (type); + if (type1) + return type1; + + /* If already done recording just return NULL. */ + if (done_recording) + return NULL; + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Recording new type: %u.\n", typeuid); + const char *type_name = get_type_name (type); + if (type_name == NULL) + fprintf (dump_file, "Recording new type NULL name\n"); + else + fprintf (dump_file, "Recording new type name: %s.\n", type_name); + } + + type1 = new srtype (type); + types.safe_push (type1); + + /* If the type has an user alignment set, + that means the user most likely already setup the type. */ + if (TYPE_USER_ALIGN (type)) + type1->mark_escape (escape_user_alignment, NULL); + + record_struct_field_types (type, type1); + + return type1; +} + +/* Mark TYPE as escaping with ESCAPES as the reason. */ + +void +ipa_struct_reorg::mark_type_as_escape (tree type, + escape_type escapes, + gimple *stmt) +{ + if (handled_type (type)) + { + srtype *stype = record_type (inner_type (type)); + + if (!stype) + return; + + stype->mark_escape (escapes, stmt); + } +} + +/* Maybe process the union of type TYPE, such that marking all of the fields' + types as being escaping. */ + +void +ipa_struct_reorg::process_union (tree type) +{ + static hash_set<tree> unions_recorded; + + type = inner_type (type); + if (TREE_CODE (type) != UNION_TYPE + && TREE_CODE (type) != QUAL_UNION_TYPE) + return; + + type = TYPE_MAIN_VARIANT (type); + + /* We already processed this type. */ + if (unions_recorded.add (type)) + return; + + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL) + { + mark_type_as_escape (TREE_TYPE (field), escape_union); + process_union (TREE_TYPE (field)); + } + } +} + +/* Used by record_var function as a callback to walk_tree. + Mark the type as escaping if it has expressions which + cannot be converted for global initializations. */ + +static tree +record_init_types (tree *tp, int *walk_subtrees, void *data) +{ + ipa_struct_reorg *c = (ipa_struct_reorg *)data; + switch (TREE_CODE (*tp)) + { + CASE_CONVERT: + case COMPONENT_REF: + case VIEW_CONVERT_EXPR: + case ARRAY_REF: + { + tree typeouter = TREE_TYPE (*tp); + tree typeinner = TREE_TYPE (TREE_OPERAND (*tp, 0)); + c->mark_type_as_escape (typeouter, escape_via_global_init); c->mark_type_as_escape (typeinner, escape_via_global_init); break; } @@ -1996,6 +2775,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) process_union (TREE_TYPE (decl)); + /* Only the structure type RECORD_TYPE is recorded. + Therefore, the void* type is filtered out. */ if (handled_type (TREE_TYPE (decl))) { type = record_type (inner_type (TREE_TYPE (decl))); @@ -2035,7 +2816,8 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg) /* Separate instance is hard to trace in complete struct relayout optimization. */ - if (current_mode == COMPLETE_STRUCT_RELAYOUT + if ((current_mode == COMPLETE_STRUCT_RELAYOUT + || current_mode == STRUCT_REORDER_FIELDS) && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE) e = escape_separate_instance; @@ -2078,11 +2860,9 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) { tree r = TREE_OPERAND (expr, 0); tree orig_type = TREE_TYPE (expr); - if (handled_component_p (r) - || TREE_CODE (r) == MEM_REF) + if (handled_component_p (r) || TREE_CODE (r) == MEM_REF) { - while (handled_component_p (r) - || TREE_CODE (r) == MEM_REF) + while (handled_component_p (r) || TREE_CODE (r) == MEM_REF) { if (TREE_CODE (r) == VIEW_CONVERT_EXPR) { @@ -2114,8 +2894,10 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt) srtype *type; srfield *field; bool realpart, imagpart, address; + bool escape_from_base = false; + /* The should_create flag is true, the declaration can be recorded. */ get_type_field (expr, base, indirect, type, field, - realpart, imagpart, address, true, true); + realpart, imagpart, address, escape_from_base, true, true); } void @@ -2132,36 +2914,79 @@ ipa_struct_reorg::find_vars (gimple *stmt) tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); find_var (gimple_assign_lhs (stmt), stmt); + /* _2 = MEM[(struct arc_t * *)_1]; + records the right value _1 declaration. */ find_var (gimple_assign_rhs1 (stmt), stmt); - if (TREE_CODE (lhs) == SSA_NAME + + /* Add a safe func mechanism. */ + bool l_find = true; + bool r_find = true; + if (current_mode == STRUCT_REORDER_FIELDS) + { + l_find = !(current_function->is_safe_func + && TREE_CODE (lhs) == SSA_NAME + && is_from_void_ptr_parm (lhs)); + r_find = !(current_function->is_safe_func + && TREE_CODE (rhs) == SSA_NAME + && is_from_void_ptr_parm (rhs)); + } + + if ((TREE_CODE (lhs) == SSA_NAME) && VOID_POINTER_P (TREE_TYPE (lhs)) - && handled_type (TREE_TYPE (rhs))) + && handled_type (TREE_TYPE (rhs)) && l_find) { srtype *t = find_type (inner_type (TREE_TYPE (rhs))); srdecl *d = find_decl (lhs); if (!d && t) { - current_function->record_decl (t, lhs, -1); + current_function->record_decl (t, lhs, -1, + isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL); tree var = SSA_NAME_VAR (lhs); if (var && VOID_POINTER_P (TREE_TYPE (var))) - current_function->record_decl (t, var, -1); + current_function->record_decl (t, var, -1, + isptrptr (TREE_TYPE (rhs)) ? TREE_TYPE (rhs) : NULL); } } + /* Find void ssa_name such as: + void * _1; struct arc * _2; + _2 = _1 + _3; _1 = calloc (100, 40). */ if (TREE_CODE (rhs) == SSA_NAME && VOID_POINTER_P (TREE_TYPE (rhs)) - && handled_type (TREE_TYPE (lhs))) + && handled_type (TREE_TYPE (lhs)) && r_find) { srtype *t = find_type (inner_type (TREE_TYPE (lhs))); srdecl *d = find_decl (rhs); if (!d && t) { - current_function->record_decl (t, rhs, -1); + current_function->record_decl (t, rhs, -1, + isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL); tree var = SSA_NAME_VAR (rhs); if (var && VOID_POINTER_P (TREE_TYPE (var))) - current_function->record_decl (t, var, -1); + current_function->record_decl (t, var, -1, + isptrptr (TREE_TYPE (lhs)) ? TREE_TYPE (lhs) : NULL); } } } + else if ((current_mode == STRUCT_REORDER_FIELDS) + && (gimple_assign_rhs_code (stmt) == LE_EXPR + || gimple_assign_rhs_code (stmt) == LT_EXPR + || gimple_assign_rhs_code (stmt) == GE_EXPR + || gimple_assign_rhs_code (stmt) == GT_EXPR)) + { + find_var (gimple_assign_lhs (stmt), stmt); + find_var (gimple_assign_rhs1 (stmt), stmt); + find_var (gimple_assign_rhs2 (stmt), stmt); + } + /* Find void ssa_name from stmt such as: _2 = _1 - old_arcs_1. */ + else if ((current_mode == STRUCT_REORDER_FIELDS) + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR + && types_compatible_p ( + TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs1 (stmt))), + TYPE_MAIN_VARIANT (TREE_TYPE (gimple_assign_rhs2 (stmt))))) + { + find_var (gimple_assign_rhs1 (stmt), stmt); + find_var (gimple_assign_rhs2 (stmt), stmt); + } else { /* Because we won't handle these stmts in rewrite phase, @@ -2232,27 +3057,134 @@ ipa_struct_reorg::find_vars (gimple *stmt) } } -/* Maybe record access of statement for further analaysis. */ +/* Maybe record access of statement for further analaysis. */ + +void +ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) +{ + switch (gimple_code (stmt)) + { + case GIMPLE_ASSIGN: + maybe_record_assign (node, as_a <gassign *> (stmt)); + break; + case GIMPLE_CALL: + maybe_record_call (node, as_a <gcall *> (stmt)); + break; + case GIMPLE_DEBUG: + break; + case GIMPLE_GOTO: + case GIMPLE_SWITCH: + break; + default: + break; + } +} + +/* Calculate the multiplier. */ + +static bool +calculate_mult_num (tree arg, tree *num, tree struct_size) +{ + gcc_assert (TREE_CODE (arg) == INTEGER_CST); + bool sign = false; + HOST_WIDE_INT size = TREE_INT_CST_LOW (arg); + if (size < 0) + { + size = -size; + sign = true; + } + tree arg2 = build_int_cst (TREE_TYPE (arg), size); + if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size))) + { + tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size); + if (sign) + number = build_int_cst (TREE_TYPE (number), -tree_to_shwi (number)); + *num = number; + return true; + } + return false; +} + +/* Trace and calculate the multiplier of PLUS_EXPR. */ + +static bool +trace_calculate_plus (gimple *size_def_stmt, tree *num, tree struct_size) +{ + gcc_assert (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR); + + tree num1 = NULL_TREE; + tree num2 = NULL_TREE; + tree arg0 = gimple_assign_rhs1 (size_def_stmt); + tree arg1 = gimple_assign_rhs2 (size_def_stmt); + if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE) + return false; + if (!is_result_of_mult (arg1, &num2, struct_size) || num2 == NULL_TREE) + return false; + *num = size_binop (PLUS_EXPR, num1, num2); + return true; +} + +/* Trace and calculate the multiplier of MULT_EXPR. */ + +static bool +trace_calculate_mult (gimple *size_def_stmt, tree *num, tree struct_size) +{ + gcc_assert (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); + tree num1 = NULL_TREE; + + if (is_result_of_mult (arg0, &num1, struct_size) && num1 != NULL_TREE) + { + *num = size_binop (MULT_EXPR, arg1, num1); + return true; + } + if (is_result_of_mult (arg1, &num1, struct_size) && num1 != NULL_TREE) + { + *num = size_binop (MULT_EXPR, arg0, num1); + return true; + } + *num = NULL_TREE; + return false; +} + +/* Trace and calculate the multiplier of NEGATE_EXPR. */ + +static bool +trace_calculate_negate (gimple *size_def_stmt, tree *num, tree struct_size) +{ + gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NEGATE_EXPR); + + /* Support NEGATE_EXPR trace: _3 = -_2; _2 = _1 * 72. */ + tree num1 = NULL_TREE; + tree arg0 = gimple_assign_rhs1 (size_def_stmt); + if (!is_result_of_mult (arg0, &num1, struct_size) || num1 == NULL_TREE) + return false; + tree num0 = build_int_cst (TREE_TYPE (num1), -1); + *num = size_binop (MULT_EXPR, num0, num1); + return true; +} + +/* Trace and calculate the multiplier of POINTER_DIFF_EXPR. */ -void -ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt) +static bool +trace_calculate_diff (gimple *size_def_stmt, tree *num) { - switch (gimple_code (stmt)) + gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NOP_EXPR); + + /* Support POINTER_DIFF_EXPR trace: + _3 = (long unsigned int) _2; _2 = _1 - old_arcs_1. */ + tree arg = gimple_assign_rhs1 (size_def_stmt); + size_def_stmt = SSA_NAME_DEF_STMT (arg); + if (size_def_stmt && is_gimple_assign (size_def_stmt) + && gimple_assign_rhs_code (size_def_stmt) == POINTER_DIFF_EXPR) { - case GIMPLE_ASSIGN: - maybe_record_assign (node, as_a <gassign *> (stmt)); - break; - case GIMPLE_CALL: - maybe_record_call (node, as_a <gcall *> (stmt)); - break; - case GIMPLE_DEBUG: - break; - case GIMPLE_GOTO: - case GIMPLE_SWITCH: - break; - default: - break; + *num = NULL_TREE; + return true; } + *num = NULL_TREE; + return false; } /* This function checks whether ARG is a result of multiplication @@ -2269,26 +3201,8 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) /* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */ if (TREE_CODE (arg) == INTEGER_CST) - { - bool sign = false; - HOST_WIDE_INT size = TREE_INT_CST_LOW (arg); - if (size < 0) - { - size = -size; - sign = true; - } - tree arg2 = build_int_cst (TREE_TYPE (arg), size); - if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size))) - { - tree number = size_binop (FLOOR_DIV_EXPR, arg2, struct_size); - if (sign) - number = build_int_cst (TREE_TYPE (number), - -tree_to_shwi (number)); - *num = number; - return true; - } - return false; - } + return calculate_mult_num (arg, num, struct_size); + gimple *size_def_stmt = SSA_NAME_DEF_STMT (arg); /* If the allocation statement was of the form @@ -2304,43 +3218,20 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) return false; // FIXME: this should handle SHIFT also. - if (gimple_assign_rhs_code (size_def_stmt) == PLUS_EXPR) - { - tree num1, num2; - tree arg0 = gimple_assign_rhs1 (size_def_stmt); - tree arg1 = gimple_assign_rhs2 (size_def_stmt); - if (!is_result_of_mult (arg0, &num1, struct_size)) - return false; - if (!is_result_of_mult (arg1, &num2, struct_size)) - return false; - *num = size_binop (PLUS_EXPR, num1, num2); - return true; - } - else 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); - tree num1; - - if (is_result_of_mult (arg0, &num1, struct_size)) - { - *num = size_binop (MULT_EXPR, arg1, num1); - return true; - } - if (is_result_of_mult (arg1, &num1, struct_size)) - { - *num = size_binop (MULT_EXPR, arg0, num1); - return true; - } - - *num = NULL_TREE; - return false; - } - else if (gimple_assign_rhs_code (size_def_stmt) == SSA_NAME) + tree_code rhs_code = gimple_assign_rhs_code (size_def_stmt); + if (rhs_code == PLUS_EXPR) + return trace_calculate_plus (size_def_stmt, num, struct_size); + else if (rhs_code == MULT_EXPR) + return trace_calculate_mult (size_def_stmt, num, struct_size); + else if (rhs_code == SSA_NAME) { arg = gimple_assign_rhs1 (size_def_stmt); size_def_stmt = SSA_NAME_DEF_STMT (arg); } + else if (rhs_code == NEGATE_EXPR && current_mode == STRUCT_REORDER_FIELDS) + return trace_calculate_negate (size_def_stmt, num, struct_size); + else if (rhs_code == NOP_EXPR && current_mode == STRUCT_REORDER_FIELDS) + return trace_calculate_diff (size_def_stmt, num); else { *num = NULL_TREE; @@ -2357,18 +3248,22 @@ is_result_of_mult (tree arg, tree *num, tree struct_size) bool ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) { - if (current_mode == COMPLETE_STRUCT_RELAYOUT + if ((current_mode == STRUCT_REORDER_FIELDS) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))) + return true; + if ((current_mode == COMPLETE_STRUCT_RELAYOUT) && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)) return true; - - if (current_mode != COMPLETE_STRUCT_RELAYOUT) - if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) - || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) - || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) - || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC) - || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA) - || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) - return true; + if ((current_mode == NORMAL) + && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC) + || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA) + || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))) + return true; return false; } @@ -2376,7 +3271,7 @@ ipa_struct_reorg::handled_allocation_stmt (gimple *stmt) elements in the array allocated. */ tree -ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) +ipa_struct_reorg::allocate_size (srtype *type, srdecl *decl, gimple *stmt) { if (!stmt || gimple_code (stmt) != GIMPLE_CALL @@ -2396,6 +3291,10 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) tree struct_size = TYPE_SIZE_UNIT (type->type); + /* Specify the correct size to relax multi-layer pointer. */ + if (TREE_CODE (decl->decl) == SSA_NAME && isptrptr (decl->orig_type)) + struct_size = TYPE_SIZE_UNIT (decl->orig_type); + tree size = gimple_call_arg (stmt, 0); if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC) @@ -2409,8 +3308,10 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt) the size of structure. */ if (operand_equal_p (arg1, struct_size, 0)) return size; - /* ??? Check that first argument is a constant equal to - the size of structure. */ + /* ??? Check that first argument is a constant + equal to the size of structure. */ + /* If the allocated number is equal to the value of struct_size, + the value of arg1 is changed to the allocated number. */ if (operand_equal_p (size, struct_size, 0)) return arg1; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -2453,10 +3354,16 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, if (!d) { + /* MEM[(struct arc *)_1].head = _2; _2 = calloc (100, 104). */ if (VOID_POINTER_P (TREE_TYPE (side)) && TREE_CODE (side) == SSA_NAME) - current_function->record_decl (type, side, -1); + { + /* The type is other, the declaration is side. */ + current_function->record_decl (type, side, -1, + isptrptr (TREE_TYPE (other)) ? TREE_TYPE (other) : NULL); + } else + /* *_1 = &MEM[(void *)&x + 8B]. */ type->mark_escape (escape_cast_another_ptr, stmt); } else if (type != d->type) @@ -2464,6 +3371,17 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, type->mark_escape (escape_cast_another_ptr, stmt); d->type->mark_escape (escape_cast_another_ptr, stmt); } + /* x_1 = y.x_nodes; void *x; + Directly mark the structure pointer type assigned + to the void* variable as escape. */ + else if (current_mode == STRUCT_REORDER_FIELDS + && TREE_CODE (side) == SSA_NAME + && VOID_POINTER_P (TREE_TYPE (side)) + && SSA_NAME_VAR (side) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (side)))) + mark_type_as_escape (TREE_TYPE (other), escape_cast_void, stmt); + + check_ptr_layers (side, other, stmt); } /* Record accesses in an assignment statement STMT. */ @@ -2486,8 +3404,12 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) if (!handled_type (TREE_TYPE (lhs))) return; /* Check if rhs2 is a multiplication of the size of the type. */ + /* The size adjustment and judgment of multi-layer pointers + are added. */ if (is_result_of_mult (rhs2, &num, - TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))))) + isptrptr (TREE_TYPE (lhs)) + ? TYPE_SIZE_UNIT (TREE_TYPE (lhs)) + : TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs))))) { record_stmt_expr (lhs, node, stmt); record_stmt_expr (rhs1, node, stmt); @@ -2525,9 +3447,8 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt) } static bool -check_mem_ref_offset (tree expr) +check_mem_ref_offset (tree expr, tree *num) { - tree num = NULL; bool ret = false; if (TREE_CODE (expr) != MEM_REF) @@ -2538,15 +3459,18 @@ check_mem_ref_offset (tree expr) tree tmp = TREE_OPERAND (expr, 0); if (TREE_CODE (tmp) == ADDR_EXPR) tmp = TREE_OPERAND (tmp, 0); - tree size = TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp))); - ret = is_result_of_mult (field_off, &num, size); + /* Specify the correct size for the multi-layer pointer. */ + tree size = isptrptr (TREE_TYPE (tmp)) + ? TYPE_SIZE_UNIT (TREE_TYPE (tmp)) + : TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp))); + ret = is_result_of_mult (field_off, num, size); return ret; } static tree get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, - tree &accesstype) + tree &accesstype, tree *num) { offset = 0; realpart = false; @@ -2569,22 +3493,29 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, { case COMPONENT_REF: { + /* x.a = _1; If expr is the lvalue of stmt, + then field type is FIELD_DECL - POINTER_TYPE - RECORD_TYPE. */ tree field = TREE_OPERAND (expr, 1); tree field_off = byte_position (field); if (TREE_CODE (field_off) != INTEGER_CST) return NULL; offset += tree_to_shwi (field_off); + /* x.a = _1; If expr is the lvalue of stmt, + then expr type is VAR_DECL - RECORD_TYPE (fetch x) */ expr = TREE_OPERAND (expr, 0); accesstype = NULL; break; } case MEM_REF: { + /* _2 = MEM[(struct s * *)_1]; + If expr is the right value of stmt, then field_off type is + INTEGER_CST - POINTER_TYPE - POINTER_TYPE - RECORD_TYPE. */ tree field_off = TREE_OPERAND (expr, 1); gcc_assert (TREE_CODE (field_off) == INTEGER_CST); /* So we can mark the types as escaping if different. */ accesstype = TREE_TYPE (field_off); - if (!check_mem_ref_offset (expr)) + if (!check_mem_ref_offset (expr, num)) offset += tree_to_uhwi (field_off); return TREE_OPERAND (expr, 0); } @@ -2626,10 +3557,11 @@ ipa_struct_reorg::wholeaccess (tree expr, tree base, bool ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype *&type, srfield *&field, - bool &realpart, bool &imagpart, - bool &address, bool should_create, + bool &realpart, bool &imagpart, bool &address, + bool &escape_from_base, bool should_create, bool can_escape) { + tree num = NULL_TREE; HOST_WIDE_INT offset; tree accesstype; address = false; @@ -2641,8 +3573,9 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, mark_as_bit_field = true; } + /* Ref is classified into two types: COMPONENT_REF or MER_REF. */ base = get_ref_base_and_offset (expr, offset, realpart, imagpart, - accesstype); + accesstype, &num); /* Variable access, unkown type. */ if (base == NULL) @@ -2680,6 +3613,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, if (!t) return false; } + /* If no such decl is finded + or orig_type is not added to this decl, then add it. */ else if (!d && accesstype) { if (!should_create) @@ -2691,15 +3626,52 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, t = record_type (inner_type (accesstype)); if (!t || t->has_escaped ()) return false; - /* If base is not void* mark the type as escaping. */ - if (!VOID_POINTER_P (TREE_TYPE (base))) + /* If base is not void* mark the type as escaping. + release INTEGER_TYPE cast to struct pointer. + (If t has escpaed above, then directly returns + and doesn't mark escape follow.). */ + /* _1 = MEM[(struct arc_t * *)a_1]. + then base a_1: ssa_name - pointer_type - integer_type. */ + if (current_mode == STRUCT_REORDER_FIELDS) { - gcc_assert (can_escape); - t->mark_escape (escape_cast_another_ptr, NULL); - return false; + bool is_int_ptr = POINTER_TYPE_P (TREE_TYPE (base)) + && (TREE_CODE (inner_type (TREE_TYPE (base))) + == INTEGER_TYPE); + if (!(VOID_POINTER_P (TREE_TYPE (base)) + || (current_function->is_safe_func && is_int_ptr))) + { + gcc_assert (can_escape); + t->mark_escape (escape_cast_another_ptr, NULL); + return false; + } + if (TREE_CODE (base) == SSA_NAME + && !(current_function->is_safe_func && is_int_ptr)) + { + /* Add a safe func mechanism. */ + if (!(current_function->is_safe_func + && is_from_void_ptr_parm (base))) + /* Add auxiliary information of the multi-layer pointer + type. */ + current_function->record_decl (t, base, -1, + isptrptr (accesstype) ? accesstype : NULL); + } + } + else + { + if (!(VOID_POINTER_P (TREE_TYPE (base)))) + { + gcc_assert (can_escape); + t->mark_escape (escape_cast_another_ptr, NULL); + return false; + } + if (TREE_CODE (base) == SSA_NAME) + { + /* Add auxiliary information of the multi-layer pointer + type. */ + current_function->record_decl (t, base, -1, + isptrptr (accesstype) ? accesstype : NULL); + } } - if (TREE_CODE (base) == SSA_NAME) - current_function->record_decl (t, base, -1); } else if (!d) return false; @@ -2707,7 +3679,10 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, t = d->type; if (t->has_escaped ()) + { + escape_from_base = true; return false; + } if (mark_as_bit_field) { @@ -2716,6 +3691,17 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, return false; } + /* Escape the operation of fetching field with pointer offset such as: + *(&(t->right)) = malloc (0); -> MEM[(struct node * *)_1 + 8B] = malloc (0); + */ + if (current_mode != NORMAL + && (TREE_CODE (expr) == MEM_REF) && (offset != 0)) + { + gcc_assert (can_escape); + t->mark_escape (escape_non_multiply_size, NULL); + return false; + } + if (wholeaccess (expr, base, accesstype, t)) { field = NULL; @@ -2733,7 +3719,6 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, print_generic_expr (dump_file, expr); fprintf (dump_file, "\n"); print_generic_expr (dump_file, base); - fprintf (dump_file, "\n"); } gcc_assert (can_escape); t->mark_escape (escape_unkown_field, NULL); @@ -2747,9 +3732,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, print_generic_expr (dump_file, f->fieldtype); fprintf (dump_file, "\naccess type = "); print_generic_expr (dump_file, TREE_TYPE (expr)); - fprintf (dump_file, "original expr = "); + fprintf (dump_file, "\noriginal expr = "); print_generic_expr (dump_file, expr); - fprintf (dump_file, "\n"); } gcc_assert (can_escape); t->mark_escape (escape_unkown_field, NULL); @@ -2772,8 +3756,9 @@ ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes, srtype *type; srfield *field; bool realpart, imagpart, address; + bool escape_from_base = false; if (!get_type_field (expr, base, indirect, type, field, - realpart, imagpart, address)) + realpart, imagpart, address, escape_from_base)) return; type->mark_escape (escapes, stmt); @@ -2846,10 +3831,23 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) gimple_call_arg (stmt, i)); if (d) d->type->mark_escape (escapes, stmt); + + if (escapes == escape_external_function + && !gimple_call_builtin_p (stmt, BUILT_IN_MEMSET)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "escape_external_function: "); + print_gimple_stmt (dump_file, stmt, 0); + } + if (d) + ext_func_types.safe_push (d->type); + } } return; } + /* Get func param it's tree_list. */ argtype = TYPE_ARG_TYPES (gimple_call_fntype (stmt)); for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) { @@ -2857,9 +3855,14 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt) if (argtype) { tree argtypet = TREE_VALUE (argtype); - if (!free_or_realloc + /* callee_func (_1, _2); + Check the callee func, instead of current func. */ + if (!(free_or_realloc + || (current_mode == STRUCT_REORDER_FIELDS + && safe_functions.contains ( + node->get_edge (stmt)->callee))) && VOID_POINTER_P (argtypet)) - mark_type_as_escape (TREE_TYPE (arg), escape_cast_void); + mark_type_as_escape (TREE_TYPE (arg), escape_cast_void, stmt); else record_stmt_expr (arg, node, stmt); } @@ -2878,12 +3881,22 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt) srtype *type; srfield *field; bool realpart, imagpart, address; + bool escape_from_base = false; if (!get_type_field (expr, base, indirect, type, field, - realpart, imagpart, address)) + realpart, imagpart, address, escape_from_base)) return; - if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) - type->mark_escape (escape_non_optimize, stmt); + if (current_mode == STRUCT_REORDER_FIELDS) + { + if (!opt_for_fn (current_function_decl, flag_ipa_reorder_fields)) + type->mark_escape (escape_non_optimize, stmt); + } + else + { + if (!opt_for_fn (current_function_decl, flag_ipa_struct_reorg)) + type->mark_escape (escape_non_optimize, stmt); + } + /* Record it. */ type->add_access (new sraccess (stmt, node, type, field)); @@ -2901,10 +3914,10 @@ ipa_struct_reorg::find_function (cgraph_node *node) } void -ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, - vec<srdecl *> &worklist, - gimple *stmt) +ipa_struct_reorg::check_type_and_push (tree newdecl, srdecl *decl, + vec<srdecl *> &worklist, gimple *stmt) { + srtype *type = decl->type; if (integer_zerop (newdecl)) return; @@ -2916,7 +3929,8 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, type->mark_escape (escape_cast_another_ptr, stmt); return; } - if (d->type == type) + if (d->type == type + && cmp_ptr_layers (TREE_TYPE (newdecl), TREE_TYPE (decl->decl))) return; srtype *type1 = d->type; @@ -2967,7 +3981,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, /* Only add to the worklist if the decl is a SSA_NAME. */ if (TREE_CODE (newdecl) == SSA_NAME) worklist.safe_push (d); - if (d->type == type) + tree a_decl = d->orig_type ? d->orig_type : TREE_TYPE (newdecl); + tree b_decl = decl->orig_type ? decl->orig_type : TREE_TYPE (decl->decl); + if (d->type == type && cmp_ptr_layers (a_decl, b_decl)) return; srtype *type1 = d->type; @@ -3000,6 +4016,96 @@ ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type) } } +/* Check the definition of gimple assign. */ + +void +ipa_struct_reorg::check_definition_assign (srdecl *decl, + vec<srdecl *> &worklist) +{ + tree ssa_name = decl->decl; + srtype *type = decl->type; + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); + gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN); + /* a) if the SSA_NAME is sourced from a pointer plus, record the pointer and + check to make sure the addition was a multiple of the size. + check the pointer type too. */ + tree rhs = gimple_assign_rhs1 (stmt); + if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) + { + tree rhs2 = gimple_assign_rhs2 (stmt); + tree num = NULL_TREE; + /* Specify the correct size for the multi-layer pointer. */ + if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type) + ? TYPE_SIZE_UNIT (decl->orig_type) + : TYPE_SIZE_UNIT (type->type))) + type->mark_escape (escape_non_multiply_size, stmt); + + if (TREE_CODE (rhs) == SSA_NAME) + check_type_and_push (rhs, decl, worklist, stmt); + return; + } + + if (gimple_assign_rhs_code (stmt) == MAX_EXPR + || gimple_assign_rhs_code (stmt) == MIN_EXPR + || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR + || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR + || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) + { + tree rhs2 = gimple_assign_rhs2 (stmt); + if (TREE_CODE (rhs) == SSA_NAME) + check_type_and_push (rhs, decl, worklist, stmt); + if (TREE_CODE (rhs2) == SSA_NAME) + check_type_and_push (rhs2, decl, worklist, stmt); + return; + } + + /* Casts between pointers and integer are escaping. */ + if (gimple_assign_cast_p (stmt)) + { + type->mark_escape (escape_cast_int, stmt); + return; + } + + /* d) if the name is from a cast/assignment, make sure it is used as + that type or void* + i) If void* then push the ssa_name into worklist. */ + gcc_assert (gimple_assign_single_p (stmt)); + check_other_side (decl, rhs, stmt, worklist); + check_ptr_layers (decl->decl, rhs, stmt); +} + +/* Check the definition of gimple call. */ + +void +ipa_struct_reorg::check_definition_call (srdecl *decl, vec<srdecl *> &worklist) +{ + tree ssa_name = decl->decl; + srtype *type = decl->type; + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); + gcc_assert (gimple_code (stmt) == GIMPLE_CALL); + + /* For realloc, check the type of the argument. */ + if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) + check_type_and_push (gimple_call_arg (stmt, 0), decl, worklist, stmt); + + if (current_mode == STRUCT_REORDER_FIELDS) + { + if (!handled_allocation_stmt (stmt)) + type->mark_escape (escape_return, stmt); + if (!allocate_size (type, decl, stmt)) + type->mark_escape (escape_non_multiply_size, stmt); + } + else + { + if (!handled_allocation_stmt (stmt) + || !allocate_size (type, decl, stmt)) + type->mark_escape (escape_return, stmt); + } + + check_alloc_num (stmt, type); + return; +} + /* 2) Check SSA_NAMEs for non type usages (source or use) (worlist of srdecl) a) if the SSA_NAME is sourced from a pointer plus, record the pointer and @@ -3029,9 +4135,12 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist) if (var && TREE_CODE (var) == PARM_DECL && VOID_POINTER_P (TREE_TYPE (ssa_name))) - type->mark_escape (escape_cast_void, NULL); + type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); return; } + if (current_mode == STRUCT_REORDER_FIELDS && SSA_NAME_VAR (ssa_name) + && VOID_POINTER_P (TREE_TYPE (SSA_NAME_VAR (ssa_name)))) + type->mark_escape (escape_cast_void, SSA_NAME_DEF_STMT (ssa_name)); gimple *stmt = SSA_NAME_DEF_STMT (ssa_name); /* @@ -3039,17 +4148,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist) i) Add SSA_NAME (void*) to the worklist if allocated from realloc */ if (gimple_code (stmt) == GIMPLE_CALL) - { - /* For realloc, check the type of the argument. */ - if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)) - check_type_and_push (gimple_call_arg (stmt, 0), type, worklist, stmt); - - if (!handled_allocation_stmt (stmt) - || !allocate_size (type, stmt)) - type->mark_escape (escape_return, stmt); - check_alloc_num (stmt, type); - return; - } + check_definition_call (decl, worklist); /* If the SSA_NAME is sourced from an inline-asm, just mark the type as escaping. */ if (gimple_code (stmt) == GIMPLE_ASM) @@ -3065,58 +4164,11 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist) { for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) check_type_and_push (gimple_phi_arg_def (stmt, i), - type, worklist, stmt); - return; - } - - gcc_assert (gimple_code (stmt) == GIMPLE_ASSIGN); - /* - a) if the SSA_NAME is sourced from a pointer plus, record the pointer and - check to make sure the addition was a multiple of the size. - check the pointer type too. - */ - - tree rhs = gimple_assign_rhs1 (stmt); - if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) - { - tree rhs2 = gimple_assign_rhs2 (stmt); - tree num; - if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) - type->mark_escape (escape_non_multiply_size, stmt); - - if (TREE_CODE (rhs) == SSA_NAME) - check_type_and_push (rhs, type, worklist, stmt); - return; - } - - if (gimple_assign_rhs_code (stmt) == MAX_EXPR - || gimple_assign_rhs_code (stmt) == MIN_EXPR - || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR - || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR - || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR) - { - tree rhs2 = gimple_assign_rhs2 (stmt); - if (TREE_CODE (rhs) == SSA_NAME) - check_type_and_push (rhs, type, worklist, stmt); - if (TREE_CODE (rhs2) == SSA_NAME) - check_type_and_push (rhs2, type, worklist, stmt); - return; - } - - /* Casts between pointers and integer are escaping. */ - if (gimple_assign_cast_p (stmt)) - { - type->mark_escape (escape_cast_int, stmt); + decl, worklist, stmt); return; } - - /* - d) if the name is from a cast/assignment, make sure it is used as that - type or void* - i) If void* then push the ssa_name into worklist - */ - gcc_assert (gimple_assign_single_p (stmt)); - check_other_side (decl, rhs, stmt, worklist); + if (gimple_code (stmt) == GIMPLE_ASSIGN) + check_definition_assign (decl, worklist); } /* Mark the types used by the inline-asm as escaping. @@ -3149,45 +4201,121 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, { srtype *type = decl->type; - if (TREE_CODE (other) == SSA_NAME - || DECL_P (other) + if (TREE_CODE (other) == SSA_NAME || DECL_P (other) || TREE_CODE (other) == INTEGER_CST) { - check_type_and_push (other, type, worklist, stmt); + check_type_and_push (other, decl, worklist, stmt); + return; + } + + tree t = TREE_TYPE (other); + if (!handled_type (t)) + { + type->mark_escape (escape_cast_another_ptr, stmt); + return; + } + + srtype *t1 = find_type (inner_type (t)); + if (t1 == type) + { + /* In Complete Struct Relayout, if lhs type is the same + as rhs type, we could return without any harm. */ + if (current_mode == COMPLETE_STRUCT_RELAYOUT) + return; + + tree base; + bool indirect; + srtype *type1; + srfield *field; + bool realpart, imagpart, address; + bool escape_from_base = false; + if (!get_type_field (other, base, indirect, type1, field, + realpart, imagpart, address, escape_from_base)) + { + if (current_mode == STRUCT_REORDER_FIELDS) + { + /* Release INTEGER_TYPE cast to struct pointer. */ + bool cast_from_int_ptr = current_function->is_safe_func && base + && find_decl (base) == NULL && POINTER_TYPE_P (TREE_TYPE (base)) + && (TREE_CODE (inner_type (TREE_TYPE (base))) == INTEGER_TYPE); + + /* Add a safe func mechanism. */ + bool from_void_ptr_parm = current_function->is_safe_func + && TREE_CODE (base) == SSA_NAME && is_from_void_ptr_parm (base); + + /* Release type is used by a type which escapes. */ + if (escape_from_base || cast_from_int_ptr || from_void_ptr_parm) + return; + } + type->mark_escape (escape_cast_another_ptr, stmt); + } + return; } - tree t = TREE_TYPE (other); - if (!handled_type (t)) + if (t1) + t1->mark_escape (escape_cast_another_ptr, stmt); + + type->mark_escape (escape_cast_another_ptr, stmt); +} + + +/* Get the expr base. */ + +void +get_base (tree &base, tree expr) +{ + if (TREE_CODE (expr) == MEM_REF) + base = TREE_OPERAND (expr, 0); + else if (TREE_CODE (expr) == COMPONENT_REF) + { + base = TREE_OPERAND (expr, 0); + base = (TREE_CODE (base) == MEM_REF) ? TREE_OPERAND (base, 0) : base; + } + else if (TREE_CODE (expr) == ADDR_EXPR) + base = TREE_OPERAND (expr, 0); +} + +/* Check whether the number of pointer layers of exprs is equal, + marking unequals as escape. */ + +void +ipa_struct_reorg::check_ptr_layers (tree a_expr, tree b_expr, gimple *stmt) +{ + if (current_mode != STRUCT_REORDER_FIELDS || current_function->is_safe_func + || !(POINTER_TYPE_P (TREE_TYPE (a_expr))) + || !(POINTER_TYPE_P (TREE_TYPE (b_expr))) + || !handled_type (TREE_TYPE (a_expr)) + || !handled_type (TREE_TYPE (b_expr))) + return; + + tree a_base = a_expr; + tree b_base = b_expr; + get_base (a_base, a_expr); + get_base (b_base, b_expr); + + srdecl *a = find_decl (a_base); + srdecl *b = find_decl (b_base); + if (a && b == NULL && TREE_CODE (b_expr) != INTEGER_CST) { - type->mark_escape (escape_cast_another_ptr, stmt); + a->type->mark_escape (escape_cast_another_ptr, stmt); return; } - - srtype *t1 = find_type (inner_type (t)); - if (t1 == type) + else if (b && a == NULL && TREE_CODE (a_expr) != INTEGER_CST) { - /* In Complete Struct Relayout, if lhs type is the same - as rhs type, we could return without any harm. */ - if (current_mode == COMPLETE_STRUCT_RELAYOUT) - return; - - tree base; - bool indirect; - srtype *type1; - srfield *field; - bool realpart, imagpart, address; - if (!get_type_field (other, base, indirect, type1, field, - realpart, imagpart, address)) - type->mark_escape (escape_cast_another_ptr, stmt); - + b->type->mark_escape (escape_cast_another_ptr, stmt); return; } + else if (a == NULL && b == NULL) + return; - if (t1) - t1->mark_escape (escape_cast_another_ptr, stmt); + if (cmp_ptr_layers (TREE_TYPE (a_expr), TREE_TYPE (b_expr))) + return; - type->mark_escape (escape_cast_another_ptr, stmt); + if (a) + a->type->mark_escape (escape_cast_another_ptr, stmt); + if (b) + b->type->mark_escape (escape_cast_another_ptr, stmt); } void @@ -3205,7 +4333,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, check to make sure they are used correctly. */ if (gimple_code (stmt) == GIMPLE_PHI) { - check_type_and_push (gimple_phi_result (stmt), type, worklist, stmt); + check_type_and_push (gimple_phi_result (stmt), decl, worklist, stmt); return; } @@ -3221,10 +4349,15 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, tree rhs2 = gimple_cond_rhs (stmt); tree orhs = rhs1; enum tree_code code = gimple_cond_code (stmt); - if (code != EQ_EXPR && code != NE_EXPR - && (current_mode != COMPLETE_STRUCT_RELAYOUT - || (code != LT_EXPR && code != LE_EXPR - && code != GT_EXPR && code != GE_EXPR))) + if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) + || (current_mode == COMPLETE_STRUCT_RELAYOUT + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR)) + || (current_mode == STRUCT_REORDER_FIELDS + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR))) { mark_expr_escape (rhs1, escape_non_eq, stmt); mark_expr_escape (rhs2, escape_non_eq, stmt); @@ -3235,7 +4368,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, return; if (TREE_CODE (orhs) != SSA_NAME) mark_expr_escape (rhs1, escape_non_eq, stmt); - check_type_and_push (orhs, type, worklist, stmt); + check_type_and_push (orhs, decl, worklist, stmt); return; } @@ -3254,9 +4387,14 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, tree rhs2 = gimple_assign_rhs2 (stmt); tree orhs = rhs1; enum tree_code code = gimple_assign_rhs_code (stmt); - if (code != EQ_EXPR && code != NE_EXPR - && (current_mode != COMPLETE_STRUCT_RELAYOUT - || (code != LT_EXPR && code != LE_EXPR + if ((current_mode == NORMAL && (code != EQ_EXPR && code != NE_EXPR)) + || (current_mode == COMPLETE_STRUCT_RELAYOUT + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR + && code != GT_EXPR && code != GE_EXPR)) + || (current_mode == STRUCT_REORDER_FIELDS + && (code != EQ_EXPR && code != NE_EXPR + && code != LT_EXPR && code != LE_EXPR && code != GT_EXPR && code != GE_EXPR))) { mark_expr_escape (rhs1, escape_non_eq, stmt); @@ -3268,7 +4406,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, return; if (TREE_CODE (orhs) != SSA_NAME) mark_expr_escape (rhs1, escape_non_eq, stmt); - check_type_and_push (orhs, type, worklist, stmt); + check_type_and_push (orhs, decl, worklist, stmt); return; } @@ -3282,6 +4420,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, check_other_side (decl, lhs, stmt, worklist); return; } + check_ptr_layers (lhs, rhs, stmt); } if (is_gimple_assign (stmt) @@ -3291,9 +4430,26 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, tree lhs = gimple_assign_lhs (stmt); tree num; check_other_side (decl, lhs, stmt, worklist); - if (!is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (type->type))) + check_ptr_layers (lhs, decl->decl, stmt); + /* Specify the correct size for the multi-layer pointer. */ + if (!is_result_of_mult (rhs2, &num, isptrptr (decl->orig_type) + ? TYPE_SIZE_UNIT (decl->orig_type) + : TYPE_SIZE_UNIT (type->type))) type->mark_escape (escape_non_multiply_size, stmt); } + + if (is_gimple_assign (stmt) + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree other = rhs1 == decl->decl ? rhs2 : rhs1; + + check_other_side (decl, other, stmt, worklist); + check_ptr_layers (decl->decl, other, stmt); + return; + } + } /* @@ -3360,17 +4516,43 @@ ipa_struct_reorg::record_function (cgraph_node *node) if (DECL_PRESERVE_P (node->decl)) escapes = escape_marked_as_used; else if (!node->local) - escapes = escape_visible_function; + { + if (current_mode != STRUCT_REORDER_FIELDS) + escapes = escape_visible_function; + if (current_mode == STRUCT_REORDER_FIELDS && node->externally_visible) + escapes = escape_visible_function; + } else if (!node->can_change_signature) escapes = escape_cannot_change_signature; else if (!tree_versionable_function_p (node->decl)) escapes = escape_noclonable_function; - else if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) - escapes = escape_non_optimize; + + if (current_mode == STRUCT_REORDER_FIELDS) + { + if (!opt_for_fn (node->decl, flag_ipa_reorder_fields)) + escapes = escape_non_optimize; + } + else if (current_mode == NORMAL || current_mode == COMPLETE_STRUCT_RELAYOUT) + { + if (!opt_for_fn (node->decl, flag_ipa_struct_reorg)) + escapes = escape_non_optimize; + } basic_block bb; gimple_stmt_iterator si; + /* Add a safe func mechanism. */ + if (current_mode == STRUCT_REORDER_FIELDS) + { + current_function->is_safe_func = safe_functions.contains (node); + if (dump_file) + { + fprintf (dump_file, "\nfunction %s/%u: is_safe_func = %d\n", + node->name (), node->order, + current_function->is_safe_func); + } + } + /* Record the static chain decl. */ if (fn->static_chain_decl) { @@ -3503,6 +4685,42 @@ ipa_struct_reorg::record_function (cgraph_node *node) return sfn; } + +/* For a function that contains the void* parameter and passes the structure + pointer, check whether the function uses the input node safely. + For these functions, the void* parameter and related ssa_name are not + recorded in record_function (), and the input structure type is not escaped. +*/ + +void +ipa_struct_reorg::record_safe_func_with_void_ptr_parm () +{ + cgraph_node *node = NULL; + FOR_EACH_FUNCTION (node) + { + if (!node->real_symbol_p ()) + continue; + if (node->definition) + { + if (!node->has_gimple_body_p () || node->inlined_to) + continue; + node->get_body (); + function *fn = DECL_STRUCT_FUNCTION (node->decl); + if (!fn) + continue; + push_cfun (fn); + if (is_safe_func_with_void_ptr_parm (node)) + { + safe_functions.add (node); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\nfunction %s/%u is safe function.\n", + node->name (), node->order); + } + pop_cfun (); + } + } +} + /* Record all accesses for all types including global variables. */ void @@ -3534,6 +4752,10 @@ ipa_struct_reorg::record_accesses (void) record_var (var->decl, escapes); } + /* Add a safe func mechanism. */ + if (current_mode == STRUCT_REORDER_FIELDS) + record_safe_func_with_void_ptr_parm (); + FOR_EACH_FUNCTION (cnode) { if (!cnode->real_symbol_p ()) @@ -3552,11 +4774,14 @@ ipa_struct_reorg::record_accesses (void) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "all types (before pruning):\n"); + fprintf (dump_file, "\n"); + fprintf (dump_file, "==============================================\n\n"); + fprintf (dump_file, "======== all types (before pruning): ========\n\n"); dump_types (dump_file); - fprintf (dump_file, "all functions (before pruning):\n"); + fprintf (dump_file, "======= all functions (before pruning): =======\n"); dump_functions (dump_file); } + /* If record_var () is called later, new types will not be recorded. */ done_recording = true; } @@ -3580,6 +4805,7 @@ ipa_struct_reorg::walk_field_for_cycles (srtype *type) { if (!field->type) ; + /* If there are two members of the same structure pointer type? */ else if (field->type->visited || walk_field_for_cycles (field->type)) { @@ -3658,22 +4884,113 @@ ipa_struct_reorg::propagate_escape (void) } while (changed); } +/* If the original type (with members) has escaped, corresponding to the + struct pointer type (empty member) in the structure fields + should also marked as escape. */ + +void +ipa_struct_reorg::propagate_escape_via_original (void) +{ + for (unsigned i = 0; i < types.length (); i++) + { + for (unsigned j = 0; j < types.length (); j++) + { + const char *type1 = get_type_name (types[i]->type); + const char *type2 = get_type_name (types[j]->type); + if (type1 == NULL || type2 == NULL) + continue; + if (type1 == type2 && types[j]->has_escaped ()) + { + if (!types[i]->has_escaped ()) + types[i]->mark_escape (escape_via_orig_escape, NULL); + break; + } + } + } +} + +/* Marks the fileds as empty and does not have the original structure type + is escape. */ + +void +ipa_struct_reorg::propagate_escape_via_empty_with_no_original (void) +{ + for (unsigned i = 0; i < types.length (); i++) + { + if (types[i]->fields.length () == 0) + { + for (unsigned j = 0; j < types.length (); j++) + { + if (i != j && types[j]->fields.length ()) + { + const char *type1 = get_type_name (types[i]->type); + const char *type2 = get_type_name (types[j]->type); + if (type1 != NULL && type2 != NULL && type1 == type2) + break; + } + if (j == types.length () - 1) + types[i]->mark_escape (escape_via_empty_no_orig, NULL); + } + } + } +} + +/* Escape propagation is performed on types that escape through external + functions. */ + +void +ipa_struct_reorg::propagate_escape_via_ext_func_types (void) +{ + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "\n propagate_escape_via_ext_func_types: \n\n"); + unsigned i = 0; + hash_set<srtype *> visited_types; + while (i < ext_func_types.length ()) + { + visited_types.add (ext_func_types[i]); + unsigned j = 0; + srfield * field; + FOR_EACH_VEC_ELT (ext_func_types[i]->fields, j, field) + { + if (field->type) + { + if (!field->type->has_escaped ()) + field->type->mark_escape (escape_dependent_type_escapes, NULL); + if (!visited_types.contains (field->type)) + ext_func_types.safe_push (field->type); + } + } + i++; + } +} + /* Prune the escaped types and their decls from what was recorded. */ void ipa_struct_reorg::prune_escaped_types (void) { - if (current_mode != COMPLETE_STRUCT_RELAYOUT) + if (current_mode != COMPLETE_STRUCT_RELAYOUT + && current_mode != STRUCT_REORDER_FIELDS) { + /* Detect recusive types and mark them as escaping. */ detect_cycles (); + /* If contains or is contained by the escape type, + mark them as escaping. */ propagate_escape (); } + if (current_mode == STRUCT_REORDER_FIELDS) + { + propagate_escape_via_original (); + propagate_escape_via_empty_with_no_original (); + propagate_escape_via_ext_func_types (); + } if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "all types (after prop but before pruning):\n"); + fprintf (dump_file, "==============================================\n\n"); + fprintf (dump_file, "all types (after prop but before pruning): \n\n"); dump_types (dump_file); - fprintf (dump_file, "all functions (after prop but before pruning):\n"); + fprintf (dump_file, "all functions (after prop but before pruning): \n"); dump_functions (dump_file); } @@ -3721,7 +5038,8 @@ ipa_struct_reorg::prune_escaped_types (void) /* Prune functions which don't refer to any variables any more. */ if (function->args.is_empty () && function->decls.is_empty () - && function->globals.is_empty ()) + && function->globals.is_empty () + && current_mode != STRUCT_REORDER_FIELDS) { delete function; functions.ordered_remove (i); @@ -3746,24 +5064,31 @@ ipa_struct_reorg::prune_escaped_types (void) /* Prune types that escape, all references to those types will have been removed in the above loops. */ - for (unsigned i = 0; i < types.length ();) + /* The escape type is not deleted in STRUCT_REORDER_FIELDS, + Then the type that contains the escaped type fields + can find complete information. */ + if (current_mode != STRUCT_REORDER_FIELDS) { - srtype *type = types[i]; - if (type->has_escaped ()) + for (unsigned i = 0; i < types.length ();) { - /* All references to this type should have been removed now. */ - delete type; - types.ordered_remove (i); + srtype *type = types[i]; + if (type->has_escaped ()) + { + /* All references to this type should have been removed now. */ + delete type; + types.ordered_remove (i); + } + else + i++; } - else - i++; } if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "all types (after pruning):\n"); + fprintf (dump_file, "==============================================\n\n"); + fprintf (dump_file, "========= all types (after pruning): =========\n\n"); dump_types (dump_file); - fprintf (dump_file, "all functions (after pruning):\n"); + fprintf (dump_file, "======== all functions (after pruning): ========\n"); dump_functions (dump_file); } } @@ -3790,6 +5115,26 @@ ipa_struct_reorg::create_new_types (void) for (unsigned i = 0; i < types.length (); i++) newtypes += types[i]->create_new_type (); + if (current_mode == STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < types.length (); i++) + { + auto_vec <tree> *fields = fields_to_finish.get (types[i]->type); + if (fields) + { + for (unsigned j = 0; j < fields->length (); j++) + { + tree field = (*fields)[j]; + TREE_TYPE (field) + = reconstruct_complex_type (TREE_TYPE (field), + types[i]->newtype[0]); + } + } + } + for (unsigned i = 0; i < types.length (); i++) + layout_type (types[i]->newtype[0]); + } + if (dump_file) { if (newtypes) @@ -3894,7 +5239,8 @@ ipa_struct_reorg::create_new_args (cgraph_node *new_node) char *name = NULL; if (tname) { - name = concat (tname, ".reorg.0", NULL); + name = concat (tname, current_mode == STRUCT_REORDER_FIELDS + ? ".reorder.0" : ".reorg.0", NULL); new_name = get_identifier (name); free (name); } @@ -3980,9 +5326,10 @@ ipa_struct_reorg::create_new_functions (void) fprintf (dump_file, "\n"); } statistics_counter_event (NULL, "Create new function", 1); - new_node = node->create_version_clone_with_body (vNULL, NULL, - NULL, NULL, NULL, - "struct_reorg"); + new_node = node->create_version_clone_with_body ( + vNULL, NULL, NULL, NULL, NULL, + current_mode == STRUCT_REORDER_FIELDS + ? "struct_reorder" : "struct_reorg"); new_node->can_change_signature = node->can_change_signature; new_node->make_local (); f->newnode = new_node; @@ -4026,6 +5373,7 @@ ipa_struct_reorg::rewrite_expr (tree expr, srfield *f; bool realpart, imagpart; bool address; + bool escape_from_base = false; tree newbase[max_split]; memset (newexpr, 0, sizeof (tree[max_split])); @@ -4043,8 +5391,8 @@ ipa_struct_reorg::rewrite_expr (tree expr, return true; } - if (!get_type_field (expr, base, indirect, t, f, - realpart, imagpart, address)) + if (!get_type_field (expr, base, indirect, t, f, realpart, imagpart, + address, escape_from_base)) return false; /* If the type is not changed, then just return false. */ @@ -4107,7 +5455,38 @@ ipa_struct_reorg::rewrite_expr (tree expr, if (address) newbase1 = build_fold_addr_expr (newbase1); if (indirect) - newbase1 = build_simple_mem_ref (newbase1); + { + if (current_mode == STRUCT_REORDER_FIELDS) + { + /* Supports the MEM_REF offset. + _1 = MEM[(struct arc *)ap_1 + 72B].flow; + Old rewrite: _1 = ap.reorder.0_8->flow; + New rewrite: _1 + = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow; + */ + HOST_WIDE_INT offset_tmp = 0; + HOST_WIDE_INT mem_offset = 0; + bool realpart_tmp = false; + bool imagpart_tmp = false; + tree accesstype_tmp = NULL_TREE; + tree num = NULL_TREE; + get_ref_base_and_offset (expr, offset_tmp, + realpart_tmp, imagpart_tmp, + accesstype_tmp, &num); + + tree ptype = TREE_TYPE (newbase1); + /* Specify the correct size for the multi-layer pointer. */ + tree size = isptrptr (ptype) ? TYPE_SIZE_UNIT (ptype) : + TYPE_SIZE_UNIT (inner_type (ptype)); + mem_offset = (num != NULL) + ? TREE_INT_CST_LOW (num) * tree_to_shwi (size) + : 0; + newbase1 = build2 (MEM_REF, TREE_TYPE (ptype), newbase1, + build_int_cst (ptype, mem_offset)); + } + else + newbase1 = build_simple_mem_ref (newbase1); + } newexpr[i] = build3 (COMPONENT_REF, TREE_TYPE (f->newfield[i]), newbase1, f->newfield[i], NULL_TREE); if (imagpart) @@ -4151,8 +5530,12 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) return remove; } - if (gimple_assign_rhs_code (stmt) == EQ_EXPR - || gimple_assign_rhs_code (stmt) == NE_EXPR) + if ((current_mode != STRUCT_REORDER_FIELDS + && (gimple_assign_rhs_code (stmt) == EQ_EXPR + || gimple_assign_rhs_code (stmt) == NE_EXPR)) + || (current_mode == STRUCT_REORDER_FIELDS + && (TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) + == tcc_comparison))) { tree rhs1 = gimple_assign_rhs1 (stmt); tree rhs2 = gimple_assign_rhs2 (stmt); @@ -4160,6 +5543,10 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) tree newrhs2[max_split]; tree_code rhs_code = gimple_assign_rhs_code (stmt); tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; + if (current_mode == STRUCT_REORDER_FIELDS + && rhs_code != EQ_EXPR && rhs_code != NE_EXPR) + code = rhs_code; + if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) return false; tree newexpr = NULL_TREE; @@ -4201,20 +5588,78 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) internal_error ( "The rhs of pointer is not a multiplicate and it slips through"); - num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); + /* Add the judgment of num, support for POINTER_DIFF_EXPR. + _6 = _4 + _5; + _5 = (long unsigned int) _3; + _3 = _1 - old_2. */ + if (current_mode != STRUCT_REORDER_FIELDS + || (current_mode == STRUCT_REORDER_FIELDS && (num != NULL))) + num = gimplify_build1 (gsi, NOP_EXPR, sizetype, num); for (unsigned i = 0; i < max_split && newlhs[i]; i++) { gimple *new_stmt; - tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); - newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, newsize); - new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, - newrhs[i], newsize); + if (num != NULL) + { + tree newsize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (newlhs[i]))); + newsize = gimplify_build2 (gsi, MULT_EXPR, sizetype, num, + newsize); + new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, + newrhs[i], newsize); + } + else + new_stmt = gimple_build_assign (newlhs[i], POINTER_PLUS_EXPR, + newrhs[i], rhs2); gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); remove = true; } return remove; } + + /* Support POINTER_DIFF_EXPR rewriting. */ + if (current_mode == STRUCT_REORDER_FIELDS + && gimple_assign_rhs_code (stmt) == POINTER_DIFF_EXPR) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + tree rhs2 = gimple_assign_rhs2 (stmt); + tree newrhs1[max_split]; + tree newrhs2[max_split]; + + bool r1 = rewrite_expr (rhs1, newrhs1); + bool r2 = rewrite_expr (rhs2, newrhs2); + + if (r1 != r2) + { + /* Handle NULL pointer specially. */ + if (r1 && !r2 && integer_zerop (rhs2)) + { + r2 = true; + for (unsigned i = 0; i < max_split && newrhs1[i]; i++) + newrhs2[i] = fold_convert (TREE_TYPE (newrhs1[i]), rhs2); + } + else if (r2 && !r1 && integer_zerop (rhs1)) + { + r1 = true; + for (unsigned i = 0; i < max_split && newrhs2[i]; i++) + newrhs1[i] = fold_convert (TREE_TYPE (newrhs2[i]), rhs1); + } + else + return false; + } + else if (!r1 && !r2) + return false; + + /* The two operands always have pointer/reference type. */ + for (unsigned i = 0; i < max_split && newrhs1[i] && newrhs2[i]; i++) + { + gimple_assign_set_rhs1 (stmt, newrhs1[i]); + gimple_assign_set_rhs2 (stmt, newrhs2[i]); + update_stmt (stmt); + } + remove = false; + return remove; + } + if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS) { tree lhs = gimple_assign_lhs (stmt); @@ -4222,9 +5667,8 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "rewriting statement:\n"); + fprintf (dump_file, "\nrewriting stamtenet:\n"); print_gimple_stmt (dump_file, stmt, 0); - fprintf (dump_file, "\n"); } tree newlhs[max_split]; tree newrhs[max_split]; @@ -4271,7 +5715,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) if (!decl || !decl->type) return false; srtype *type = decl->type; - tree num = allocate_size (type, stmt); + tree num = allocate_size (type, decl, stmt); gcc_assert (num); memset (newrhs1, 0, sizeof (newrhs1)); @@ -4291,7 +5735,10 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) /* Go through each new lhs. */ for (unsigned i = 0; i < max_split && decl->newdecl[i]; i++) { - tree newsize = TYPE_SIZE_UNIT (type->type); + /* Specify the correct size for the multi-layer pointer. */ + tree newsize = isptrptr (decl->orig_type) + ? TYPE_SIZE_UNIT (decl->orig_type) + : TYPE_SIZE_UNIT (type->newtype[i]); gimple *g; /* Every allocation except for calloc needs the size multiplied out. */ @@ -4352,6 +5799,23 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) gcc_assert (node); srfunction *f = find_function (node); + /* Add a safe func mechanism. */ + if (current_mode == STRUCT_REORDER_FIELDS && f && f->is_safe_func) + { + tree expr = gimple_call_arg (stmt, 0); + tree newexpr[max_split]; + if (!rewrite_expr (expr, newexpr)) + return false; + + if (newexpr[1] == NULL) + { + gimple_call_set_arg (stmt, 0, newexpr[0]); + update_stmt (stmt); + return false; + } + return false; + } + /* Did not find the function or had not cloned it return saying don't change the function call. */ if (!f || !f->newf) @@ -4437,7 +5901,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) && TREE_CODE (gimple_vdef (new_stmt)) == SSA_NAME) SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt; - gsi_replace (gsi, new_stmt, false); + gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT); /* We need to defer cleaning EH info on the new statement to fixup-cfg. We may not have dominator information at this point @@ -4450,7 +5914,7 @@ ipa_struct_reorg::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi) add_stmt_to_eh_lp (new_stmt, lp_nr); } - return false; + return true; } /* Rewrite the conditional statement STMT. Return TRUE if the @@ -4462,50 +5926,52 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) tree_code rhs_code = gimple_cond_code (stmt); /* Handle only equals or not equals conditionals. */ - if (rhs_code != EQ_EXPR - && rhs_code != NE_EXPR) + if ((current_mode != STRUCT_REORDER_FIELDS + && (rhs_code != EQ_EXPR && rhs_code != NE_EXPR)) + || (current_mode == STRUCT_REORDER_FIELDS + && TREE_CODE_CLASS (rhs_code) != tcc_comparison)) return false; - tree rhs1 = gimple_cond_lhs (stmt); - tree rhs2 = gimple_cond_rhs (stmt); + tree lhs = gimple_cond_lhs (stmt); + tree rhs = gimple_cond_rhs (stmt); if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "COND: Rewriting\n"); + fprintf (dump_file, "\nCOND: Rewriting\n"); print_gimple_stmt (dump_file, stmt, 0); + print_generic_expr (dump_file, lhs); fprintf (dump_file, "\n"); - print_generic_expr (dump_file, rhs1); - fprintf (dump_file, "\n"); - print_generic_expr (dump_file, rhs2); + print_generic_expr (dump_file, rhs); fprintf (dump_file, "\n"); } - tree newrhs1[max_split]; - tree newrhs2[max_split]; - tree_code code = rhs_code == EQ_EXPR ? BIT_AND_EXPR : BIT_IOR_EXPR; - if (!rewrite_lhs_rhs (rhs1, rhs2, newrhs1, newrhs2)) + tree newlhs[max_split] = {}; + tree newrhs[max_split] = {}; + if (!rewrite_lhs_rhs (lhs, rhs, newlhs, newrhs)) { if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\nDid nothing to statement.\n"); + fprintf (dump_file, "Did nothing to statement.\n"); return false; } - tree newexpr = NULL_TREE; - for (unsigned i = 0; i < max_split && newrhs1[i]; i++) + /* Old rewrite: if (x_1 != 0B) + -> _1 = x.reorder.0_1 != 0B; if (_1 != 1) + The logic is incorrect. + New rewrite: if (x_1 != 0B) + -> if (x.reorder.0_1 != 0B); */ + for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++) { - tree expr = gimplify_build2 (gsi, rhs_code, boolean_type_node, - newrhs1[i], newrhs2[i]); - if (!newexpr) - newexpr = expr; - else - newexpr = gimplify_build2 (gsi, code, boolean_type_node, - newexpr, expr); - } - - if (newexpr) - { - gimple_cond_set_lhs (stmt, newexpr); - gimple_cond_set_rhs (stmt, boolean_true_node); + if (newlhs[i]) + gimple_cond_set_lhs (stmt, newlhs[i]); + if (newrhs[i]) + gimple_cond_set_rhs (stmt, newrhs[i]); update_stmt (stmt); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "replaced with:\n"); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, "\n"); + } } return false; } @@ -4516,6 +5982,9 @@ ipa_struct_reorg::rewrite_cond (gcond *stmt, gimple_stmt_iterator *gsi) bool ipa_struct_reorg::rewrite_debug (gimple *stmt, gimple_stmt_iterator *) { + if (current_mode == STRUCT_REORDER_FIELDS) + /* Delete debug gimple now. */ + return true; bool remove = false; if (gimple_debug_bind_p (stmt)) { @@ -4568,7 +6037,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "\nrewriting PHI:"); + fprintf (dump_file, "\nrewriting PHI:\n"); print_gimple_stmt (dump_file, phi, 0); } @@ -4579,7 +6048,15 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) { tree newrhs[max_split]; phi_arg_d rhs = *gimple_phi_arg (phi, i); - rewrite_expr (rhs.def, newrhs); + + /* Handling the NULL phi Node. */ + bool r = rewrite_expr (rhs.def, newrhs); + if (!r && integer_zerop (rhs.def)) + { + for (unsigned i = 0; i < max_split && newlhs[i]; i++) + newrhs[i] = fold_convert (TREE_TYPE (newlhs[i]), rhs.def); + } + for (unsigned j = 0; j < max_split && newlhs[j]; j++) { SET_PHI_ARG_DEF (newphi[j], i, newrhs[j]); @@ -4590,7 +6067,7 @@ ipa_struct_reorg::rewrite_phi (gphi *phi) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "\ninto\n:"); + fprintf (dump_file, "into:\n"); for (unsigned i = 0; i < max_split && newlhs[i]; i++) { print_gimple_stmt (dump_file, newphi[i], 0); @@ -4663,12 +6140,59 @@ ipa_struct_reorg::rewrite_functions (void) /* Create new types, if we did not create any new types, then don't rewrite any accesses. */ if (!create_new_types ()) - return 0; + { + if (current_mode == STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < functions.length (); i++) + { + srfunction *f = functions[i]; + cgraph_node *node = f->node; + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "\nNo rewrite:\n"); + dump_function_to_file (current_function_decl, dump_file, + dump_flags | TDF_VOPS); + } + pop_cfun (); + } + } + return 0; + } + + if (current_mode == STRUCT_REORDER_FIELDS && dump_file) + { + fprintf (dump_file, "=========== all created newtypes: ===========\n\n"); + dump_newtypes (dump_file); + } if (functions.length ()) { retval = TODO_remove_functions; create_new_functions (); + if (current_mode == STRUCT_REORDER_FIELDS) + { + prune_escaped_types (); + } + } + + if (current_mode == STRUCT_REORDER_FIELDS) + { + for (unsigned i = 0; i < functions.length (); i++) + { + srfunction *f = functions[i]; + cgraph_node *node = f->node; + push_cfun (DECL_STRUCT_FUNCTION (node->decl)); + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "==== Before create decls: %dth_%s ====\n\n", + i, f->node->name ()); + if (current_function_decl) + dump_function_to_file (current_function_decl, dump_file, + dump_flags | TDF_VOPS); + } + pop_cfun (); + } } create_new_decls (); @@ -4691,9 +6215,12 @@ ipa_struct_reorg::rewrite_functions (void) if (dump_file && (dump_flags & TDF_DETAILS)) { - fprintf (dump_file, "\nBefore rewrite:\n"); + fprintf (dump_file, "\nBefore rewrite: %dth_%s\n", + i, f->node->name ()); dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); + fprintf (dump_file, "\n======== Start to rewrite: %dth_%s ========\n", + i, f->node->name ()); } FOR_EACH_BB_FN (bb, cfun) { @@ -4761,9 +6288,10 @@ ipa_struct_reorg::rewrite_functions (void) free_dominance_info (CDI_DOMINATORS); - if (dump_file && (dump_flags & TDF_DETAILS)) + if (dump_file) { - fprintf (dump_file, "\nAfter rewrite:\n"); + fprintf (dump_file, "\nAfter rewrite: %dth_%s\n", + i, f->node->name ()); dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS); } @@ -4809,16 +6337,21 @@ ipa_struct_reorg::execute (enum srmode mode) { unsigned int ret = 0; - if (mode == NORMAL) + if (dump_file) + fprintf (dump_file, "\n\n====== ipa_struct_reorg level %d ======\n\n", + mode); + + if (mode == NORMAL || mode == STRUCT_REORDER_FIELDS) { - current_mode = NORMAL; - /* FIXME: If there is a top-level inline-asm, + current_mode = mode; + /* If there is a top-level inline-asm, the pass immediately returns. */ if (symtab->first_asm_symbol ()) return 0; record_accesses (); prune_escaped_types (); - analyze_types (); + if (current_mode == NORMAL) + analyze_types (); ret = rewrite_functions (); } @@ -4881,7 +6414,55 @@ pass_ipa_struct_reorg::gate (function *) && flag_lto_partition == LTO_PARTITION_ONE /* Only enable struct optimizations in C since other languages' grammar forbid. */ - && lang_c_p ()); + && lang_c_p () + /* Only enable struct optimizations in lto or whole_program. */ + && (in_lto_p || flag_whole_program)); +} + +const pass_data pass_data_ipa_reorder_fields = +{ + SIMPLE_IPA_PASS, // type + "reorder_fields", // name + OPTGROUP_NONE, // optinfo_flags + TV_IPA_REORDER_FIELDS, // tv_id + 0, // properties_required + 0, // properties_provided + 0, // properties_destroyed + 0, // todo_flags_start + 0, // todo_flags_finish +}; + +class pass_ipa_reorder_fields : public simple_ipa_opt_pass +{ +public: + pass_ipa_reorder_fields (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_reorder_fields, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *); + virtual unsigned int execute (function *) + { + unsigned int ret = 0; + ret = ipa_struct_reorg ().execute (STRUCT_REORDER_FIELDS); + return ret; + } + +}; // class pass_ipa_reorder_fields + +bool +pass_ipa_reorder_fields::gate (function *) +{ + return (optimize >= 3 + && flag_ipa_reorder_fields + /* Don't bother doing anything if the program has errors. */ + && !seen_error () + && flag_lto_partition == LTO_PARTITION_ONE + /* Only enable struct optimizations in C since other + languages' grammar forbid. */ + && lang_c_p () + /* Only enable struct optimizations in lto or whole_program. */ + && (in_lto_p || flag_whole_program)); } } // anon namespace @@ -4891,4 +6472,10 @@ simple_ipa_opt_pass * make_pass_ipa_struct_reorg (gcc::context *ctxt) { return new pass_ipa_struct_reorg (ctxt); -} \ No newline at end of file +} + +simple_ipa_opt_pass * +make_pass_ipa_reorder_fields (gcc::context *ctxt) +{ + return new pass_ipa_reorder_fields (ctxt); +} diff --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h index ef7f4c780..6f85adeb4 100644 --- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h +++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h @@ -68,12 +68,14 @@ struct srfunction auto_vec<srdecl *> args; auto_vec<srdecl *> globals; auto_vec_del<srdecl> decls; - srdecl *record_decl (srtype *, tree, int arg); + srdecl *record_decl (srtype *, tree, int arg, tree orig_type = NULL); srfunction *old; cgraph_node *newnode; srfunction *newf; + bool is_safe_func; + // Constructors srfunction (cgraph_node *n); @@ -184,6 +186,11 @@ struct srfield void create_new_fields (tree newtype[max_split], tree newfields[max_split], tree newlast[max_split]); + void reorder_fields (tree newfields[max_split], tree newlast[max_split], + tree &field); + void create_new_reorder_fields (tree newtype[max_split], + tree newfields[max_split], + tree newlast[max_split]); }; struct sraccess @@ -221,8 +228,11 @@ struct srdecl tree newdecl[max_split]; + /* Auxiliary record complete original type information of the void* type. */ + tree orig_type; + // Constructors - srdecl (srtype *type, tree decl, int argumentnum = -1); + srdecl (srtype *type, tree decl, int argumentnum = -1, tree orgtype = NULL); // Methods void dump (FILE *file); diff --git a/gcc/passes.def b/gcc/passes.def index 9692066e4..bdc835b87 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -178,6 +178,7 @@ along with GCC; see the file COPYING3. If not see compiled unit. */ INSERT_PASSES_AFTER (all_late_ipa_passes) NEXT_PASS (pass_ipa_pta); + NEXT_PASS (pass_ipa_reorder_fields); /* FIXME: this should be a normal IP pass. */ NEXT_PASS (pass_ipa_struct_reorg); NEXT_PASS (pass_omp_simd_clone); diff --git a/gcc/symbol-summary.h b/gcc/symbol-summary.h index 3fe64047c..6fa529eee 100644 --- a/gcc/symbol-summary.h +++ b/gcc/symbol-summary.h @@ -105,7 +105,7 @@ protected: { /* In structure optimizatons, we call new to ensure that the allocated memory is initialized to 0. */ - if (flag_ipa_struct_reorg) + if (flag_ipa_struct_reorg || flag_ipa_reorder_fields) return is_ggc () ? new (ggc_internal_alloc (sizeof (T))) T () : new T (); @@ -122,7 +122,7 @@ protected: ggc_delete (item); else { - if (flag_ipa_struct_reorg) + if (flag_ipa_struct_reorg || flag_ipa_reorder_fields) delete item; else m_allocator.remove (item); diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c new file mode 100644 index 000000000..b95be2dab --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_struct_instance_field.c @@ -0,0 +1,75 @@ +// escape_instance_field, "Type escapes via a field of instance". +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +typedef struct network +{ + arc_p arcs; + arc_p sorted_arcs; + int x; + node_p nodes; + node_p stop_nodes; + node_t node; +} network_t; + + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; + network_t* net_add; + node_t node; +}; + + +const int MAX = 100; + +/* let it escape_array, "Type is used in an array [not handled yet]". */ +network_t* net[2]; + +int +main () +{ + net[0] = (network_t*) calloc (1, sizeof(network_t)); + net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); + + /* Contains an escape type and has structure instance field. */ + net[0]->arcs->node = net[0]->node; + + return 0; +} + +/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c new file mode 100644 index 000000000..3d243313b --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_DTE_verify.c @@ -0,0 +1,94 @@ +// Verify in escape_dependent_type_escapes, +// the multi-layer dereference is rewriting correctly,and the memory access +// is correct. + +// release +// escape_dependent_type_escapes, +// "Type uses a type which escapes or is used by a type which escapes" +// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer" +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + arc_p arcs; + arc_p sorted_arcs; + int x; + node_p nodes; + node_p stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; + network_t* net_add; +}; + + +const int MAX = 100; + +/* let it escape_array, "Type is used in an array [not handled yet]". */ +network_t* net[2]; +arc_p stop_arcs = NULL; + +int +main () +{ + net[0] = (network_t*) calloc (1, sizeof(network_t)); + net[0]->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); + stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); + + net[0]->arcs->id = 100; + + for (unsigned i = 0; i < 3; i++) + { + net[0]->arcs->id = net[0]->arcs->id + 2; + stop_arcs->cost = net[0]->arcs->id / 2; + stop_arcs->net_add = net[0]; + printf("stop_arcs->cost = %ld\n", stop_arcs->cost); + net[0]->arcs++; + stop_arcs++; + } + + if( net[1] != 0 && stop_arcs != 0) + { + return -1; + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c new file mode 100644 index 000000000..faaf1e3a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_check_ptr_layers_bug.c @@ -0,0 +1,24 @@ +/* check_ptr_layers bugfix.*/ +/* { dg-do compile } */ +struct { + char a; +} **b = 0, *e = 0; +long c; +char d = 9; +int f; + +void g() +{ + for (; f;) + if (c) + (*e).a++; + if (!d) + for (;;) + b &&c; +} +int +main() +{ + g(); +} +/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c new file mode 100644 index 000000000..886706ae9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c @@ -0,0 +1,82 @@ +// bugfix: +// Common members do not need to reconstruct. +// Otherwise, eg:int* -> int** and void* -> void**. +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t* cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t** org_cost; +}; + +struct a +{ + int t; + int t1; +}; + +__attribute__((noinline)) int +f(int i, int j) +{ + struct a *t = NULL; + struct a t1 = {i, j}; + t = &t1; + auto int g(void) __attribute__((noinline)); + int g(void) + { + return t->t + t->t1; + } + return g(); +} + +arc_t **ap = NULL; +const int MAX = 100; + +int +main() +{ + if (f(1, 2) != 3) + { + abort (); + } + ap = (arc_t**) malloc(MAX * sizeof(arc_t*)); + (*ap)[0].id = 300; + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c new file mode 100644 index 000000000..f3785f392 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_create_new_func_bug.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +#define MallocOrDie(x) sre_malloc((x)) + +struct gki_elem { + char *key; + int idx; + struct gki_elem *nxt; +}; + +typedef struct { + struct gki_elem **table; + + int primelevel; + int nhash; + int nkeys; +} GKI; + +void +Die(char *format, ...) +{ + exit(1); +} + +void * +sre_malloc(size_t size) +{ + void *ptr; + + if ((ptr = malloc (size)) == NULL) + { + Die("malloc of %ld bytes failed", size); + } + return ptr; +} + + +__attribute__((noinline)) int +GKIStoreKey(GKI *hash, char *key) +{ + hash->table[0] = MallocOrDie(sizeof(struct gki_elem)); +} + +int +main () +{ + GKI *hash; + char *key; + GKIStoreKey(hash, key); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c new file mode 100644 index 000000000..1415d759a --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ele_minus_verify.c @@ -0,0 +1,60 @@ +// verify newarc[cmp-1].flow +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +arc_p ap = NULL; + +int +main () +{ + ap = (arc_p) calloc(MAX, sizeof(arc_t)); + printf("%d\n", ap[0].id); + for (int i = 1; i < MAX; i++) + { + ap[i-1].id = 500; + } + printf("%d\n", ap[0].id); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c new file mode 100644 index 000000000..003da0b57 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_escape_by_base.c @@ -0,0 +1,83 @@ +// release type is used by a type which escapes. +// avoid escape_cast_another_ptr, "Type escapes a cast to a different pointer" +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + arc_p arcs; + arc_p sorted_arcs; + int x; + node_p nodes; + node_p stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +network_t* net = NULL; +arc_p stop_arcs = NULL; +int cnt = 0; + +int +main () +{ + net = (network_t*) calloc (1, 20); + net->arcs = (arc_p) calloc (MAX, sizeof (arc_t)); + stop_arcs = (arc_p) calloc (MAX, sizeof (arc_t)); + if(!(net->arcs)) + { + return -1; + } + + for( int i = 0; i < MAX; i++, net->arcs = stop_arcs) + { + cnt++; + } + + net = (network_t*) calloc (1, 20); + if( !(net->arcs) ) + { + return -1; + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c new file mode 100644 index 000000000..84a34f241 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_external_func_types.c @@ -0,0 +1,69 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-shared" } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + int x; + arc_p arcs, sorted_arcs; + node_p nodes, stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +extern int bcf_sr_add_reader (network_t *); +extern int bcf_hdr_dup (arc_p); + +int +test () +{ + network_t *net = (network_t *) calloc (1, 20); + + if (!bcf_sr_add_reader(net)) + printf("error"); + arc_p arc = net->nodes->basic_arc; + if(!bcf_hdr_dup(arc)) + { + return -1; + } + return 0; +} + +/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c new file mode 100644 index 000000000..10dcf098c --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c @@ -0,0 +1,72 @@ +// release escape_cast_another_ptr, "Type escapes a cast to a different pointer" +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +typedef int cmp_t(const void *, const void *); + +__attribute__((noinline)) void +spec_qsort(void *a, cmp_t *cmp) +{ + char *pb = NULL; + while (cmp(pb, a)) + { + pb += 1; + } +} + +static int arc_compare( arc_t **a1, int a2 ) +{ + if( (*a1)->id < a2 ) + { + return -1; + } + return 1; +} + +int +main() +{ + spec_qsort(NULL, (int (*)(const void *, const void *))arc_compare); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c new file mode 100644 index 000000000..8d1a9a114 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_mem_ref_offset.c @@ -0,0 +1,58 @@ +/* Supports the MEM_REF offset. + _1 = MEM[(struct arc *)ap_4 + 72B].flow; + Old rewrite:_1 = ap.reorder.0_8->flow; + New rewrite:_1 = MEM[(struct arc.reorder.0 *)ap.reorder.0_8 + 64B].flow. */ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +int +main () +{ + const int MAX = 100; + /* A similar scenario can be reproduced only by using local variables. */ + arc_p ap = NULL; + ap = (arc_p) calloc(MAX, sizeof(arc_t)); + printf("%d\n", ap[1].flow); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c new file mode 100644 index 000000000..23765fc56 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_mul_layer_ptr_record_bug.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct T_HASH_ENTRY +{ + unsigned int hash; + unsigned int klen; + char *key; +} iHashEntry; + +typedef struct T_HASH +{ + unsigned int size; + unsigned int fill; + unsigned int keys; + + iHashEntry **array; +} uHash; + +uHash *retval; + +int +main() { + retval->array = (iHashEntry **)calloc(sizeof(iHashEntry *), retval->size); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c new file mode 100644 index 000000000..54e737ee8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c @@ -0,0 +1,109 @@ +// For testing: +/* +Compile options: gcc -O3 -g +-flto -flto-partition=one -fipa-reorder-fields -fipa-struct-reorg +-v -save-temps -fdump-ipa-all-details test.c -o test + +in COMPLETE_STRUCT_RELAYOUT pass: +N type: struct node.reorder.0 new = "Type escapes a cast to a different pointer" +copy$head_26 = test_arc.reorder.0_49->head; + +type : struct arc.reorder.0(1599) { +fields = { +field (5382) {type = cost_t} +field (5383) {type = struct node.reorder.0 *} // but node has escaped. +field (5384) {type = struct node.reorder.0 *} +field (5386) {type = struct arc.reorder.0 *} +field (5387) {type = struct arc.reorder.0 *} +field (5388) {type = flow_t} +field (5389) {type = cost_t} +field (5381) {type = int} +field (5385) {type = short int} +} + +// The types of the two types are inconsistent after the rewriting. +newarc_2(D)->tail = tail_1(D); +vs +struct_reorder.0_61(D)->tail = tail_1(D); +*/ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + arc_p arcs; + arc_p sorted_arcs; + int x; + node_p nodes; + node_p stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +__attribute__((noinline)) void +replace_weaker_arc( arc_t *newarc, node_t *tail, node_t *head) +{ + printf("test"); +} + +__attribute__((noinline)) int64_t +switch_arcs(arc_t** deleted_arcs, arc_t* arcnew) +{ + int64_t count = 0; + arc_t *test_arc, copy; + + if (!test_arc->ident) + { + copy = *test_arc; + count++; + *test_arc = arcnew[0]; + replace_weaker_arc(arcnew, NULL, NULL); + } + return count; +} + +int +main () +{ + switch_arcs(NULL, NULL); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c new file mode 100644 index 000000000..2ae46fb31 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr2void_lto.c @@ -0,0 +1,87 @@ +// escape_cast_void, "Type escapes a cast to/from void*" +// stop_393 = net.stop_nodes; void *stop; +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + arc_p arcs, sorted_arcs; + int x; + node_p nodes, stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +network_t* net = NULL; +int cnt = 0; + +__attribute__((noinline)) int +primal_feasible (network_t *net) +{ + void* stop; + node_t *node; + + node = net->nodes; + stop = (void *)net->stop_nodes; + for( node++; node < (node_t *)stop; node++ ) + { + printf( "PRIMAL NETWORK SIMPLEX: " ); + } + return 0; +} + +int +main () +{ + net = (network_t*) calloc (1, 20); + net->nodes = calloc (MAX, sizeof (node_t)); + net->stop_nodes = calloc (MAX, sizeof (node_t)); + cnt = primal_feasible( net ); + + net = (network_t*) calloc (1, 20); + if( !(net->arcs) ) + { + return -1; + } + return cnt; +} + +/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c new file mode 100644 index 000000000..3a3c10b70 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_diff.c @@ -0,0 +1,71 @@ +// support POINTER_DIFF_EXPR & NOP_EXPR to avoid +// escape_unhandled_rewrite, "Type escapes via a unhandled rewrite stmt" +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct network +{ + arc_p arcs; + arc_p sorted_arcs; + int x; + node_p nodes; + node_p stop_nodes; +} network_t; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +int +main () +{ + arc_t *old_arcs; + node_t *node; + node_t *stop; + size_t off; + network_t* net; + + for( ; node->number < stop->number; node++ ) + { + off = node->basic_arc - old_arcs; + node->basic_arc = (arc_t *)(net->arcs + off); + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c new file mode 100644 index 000000000..7b7d110df --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_negate_expr.c @@ -0,0 +1,55 @@ +// support NEGATE_EXPR rewriting +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +int +main () +{ + int64_t susp = 0; + const int MAX = 100; + arc_p ap = (arc_p) calloc(MAX, sizeof(arc_t)); + ap -= susp; + printf("%d\n", ap[1].flow); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c new file mode 100644 index 000000000..317aafa5f --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_offset.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +struct node +{ + struct node *left, *right; + double a, b, c, d, e, f; +} +*a; +int b, c; +void +CreateNode (struct node **p1) +{ + *p1 = calloc (10, sizeof (struct node)); +} + +int +main () +{ + a->left = 0; + struct node *t = a; + CreateNode (&t->right); + + struct node p = *a; + b = 1; + if (p.left) + b = 0; + if (b) + printf (" Tree.\n"); +} + +/* { dg-final { scan-ipa-dump "No structures to transform." "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c new file mode 100644 index 000000000..01a33f669 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c @@ -0,0 +1,55 @@ +// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]"; +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +arc_t **ap = NULL; + +int +main () +{ + ap = (arc_t**) malloc(MAX * sizeof(arc_t*)); + (*ap)[0].id = 300; + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c new file mode 100644 index 000000000..a38556533 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr_ptr.c @@ -0,0 +1,58 @@ +// release escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]" + +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +arc_p **ap; + + +int +main () +{ + ap = (arc_p**) calloc(MAX, sizeof(arc_p*)); + (**ap)[0].id = 500; + + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c new file mode 100644 index 000000000..5c17ee528 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_rescusive_type.c @@ -0,0 +1,57 @@ +// release escape_rescusive_type, "Recusive type" +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; +arc_p ap = NULL; + +int +main () +{ + ap = (arc_p) calloc (MAX, sizeof (arc_t)); + ap[0].id = 100; + ap[0].head = (node_p) calloc (MAX, sizeof (node_t)); + + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c new file mode 100644 index 000000000..710517ee9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_assign_more_cmp.c @@ -0,0 +1,65 @@ +// support more gimple assign rhs code +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +__attribute__((noinline)) int +compare(arc_p p1, arc_p p2) +{ + return p1 < p2; +} + +int n = 0; +int m = 0; + +int +main () +{ + scanf ("%d %d", &n, &m); + arc_p p = calloc (10, sizeof (struct arc)); + if (compare (&p[n], &p[m])) + { + printf ("ss!"); + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c new file mode 100644 index 000000000..6ed0a5d2d --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_bug.c @@ -0,0 +1,72 @@ +// rewrite_cond bugfix; +/* +if (iterator_600 != 0B) +old rewrite: _1369 = iterator.reorder.0_1249 != 0B; if (_1369 != 1) +new rewrite: if (iterator.reorder.0_1249 != 0B) +*/ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct list_elem +{ + arc_t* arc; + struct list_elem* next; +}list_elem; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +int i = 0; + +int +main () +{ + register list_elem *first_list_elem; + register list_elem* iterator; + iterator = first_list_elem->next; + while (iterator) + { + iterator = iterator->next; + i++; + } + + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c new file mode 100644 index 000000000..5a2dd964f --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_cond_more_cmp.c @@ -0,0 +1,58 @@ +// support if (_150 >= _154) +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +int +main() +{ + arc_p **ap = (arc_p**) malloc(1 * sizeof(arc_p*)); + arc_p **arcs_pointer_sorted = (arc_p**) malloc(1 * sizeof(arc_p*)); + arcs_pointer_sorted[0] = (arc_p*) calloc (1, sizeof(arc_p)); + + if (arcs_pointer_sorted >= ap) + { + return -1; + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c new file mode 100644 index 000000000..faa90b42d --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_rewrite_phi_bug.c @@ -0,0 +1,81 @@ +/* +Exclude the rewriting error caused by +first_list_elem = (list_elem *)NULL; +rewriting PHI:first_list_elem_700 = PHI <0B(144), 0B(146)> +into: +first_list_elem.reorder.0_55 = PHI <(144), (146)> +*/ +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +typedef struct list_elem +{ + arc_t* arc; + struct list_elem* next; +}list_elem; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout, firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail, head; + short ident; + arc_p nextout, nextin; + int64_t flow; + int64_t org_cost; +}; + +const int MAX = 100; + +list_elem* new_list_elem; +list_elem* first_list_elem; + +int +main () +{ + int i = 0; + list_elem *first_list_elem; + list_elem *new_list_elem; + arc_t *arcout; + for( ; i < MAX && arcout->ident == -1; i++); + + first_list_elem = (list_elem *)NULL; + for( ; i < MAX; i++) + { + new_list_elem = (list_elem*) calloc(1, sizeof(list_elem)); + new_list_elem->next = first_list_elem; + first_list_elem = new_list_elem; + } + if (first_list_elem != 0) + { + return -1; + } + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 3" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_shwi.c b/gcc/testsuite/gcc.dg/struct/rf_shwi.c new file mode 100644 index 000000000..2bb326ff2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_shwi.c @@ -0,0 +1,23 @@ +/* { dg-do compile } */ + +struct foo {int dx; long dy; int dz; }; +struct goo {long offset; struct foo* pfoo; }; + +void* func (long); + +__attribute__((used)) static void +test(struct goo* g) +{ + void* pvoid; + struct foo* f; + + for (f = g->pfoo; f->dx; f++) + { + if (f->dy) + break; + } + f--; + + pvoid = func(f->dz + g->offset); + return; +} diff --git a/gcc/testsuite/gcc.dg/struct/rf_visible_func.c b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c new file mode 100644 index 000000000..8f2da99cc --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_visible_func.c @@ -0,0 +1,92 @@ +// release escape_visible_function, "Type escapes via expternally visible function call" +// compile options: gcc -O3 -fno-inline -fwhole-program +// -flto-partition=one -fipa-struct-reorg arc_compare.c -fdump-ipa-all -S -v +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct node node_t; +typedef struct node *node_p; + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct node +{ + int64_t potential; + int orientation; + node_p child; + node_p pred; + node_p sibling; + node_p sibling_prev; + arc_p basic_arc; + arc_p firstout; + arc_p firstin; + arc_p arc_tmp; + int64_t flow; + int64_t depth; + int number; + int time; +}; + +struct arc +{ + int id; + int64_t cost; + node_p tail; + node_p head; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +__attribute__((noinline)) static int +arc_compare( arc_t **a1, arc_t **a2 ) +{ + if( (*a1)->flow > (*a2)->flow ) + { + return 1; + } + if( (*a1)->flow < (*a2)->flow ) + { + return -1; + } + if( (*a1)->id < (*a2)->id ) + { + return -1; + } + + return 1; +} + +__attribute__((noinline)) void +spec_qsort(void *array, int nitems, int size, + int (*cmp)(const void*,const void*)) +{ + for (int i = 0; i < nitems - 1; i++) + { + if (cmp (array , array)) + { + printf ("CMP 1\n"); + } + else + { + printf ("CMP 2\n"); + } + } +} + +typedef int cmp_t(const void *, const void *); + +int +main () +{ + void *p = calloc (100, sizeof (arc_t **)); + spec_qsort (p, 100, 0, (int (*)(const void *, const void *))arc_compare); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 2" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c new file mode 100644 index 000000000..723142c59 --- /dev/null +++ b/gcc/testsuite/gcc.dg/struct/rf_void_ptr_param_func.c @@ -0,0 +1,54 @@ +// Add a safe func mechanism. +// avoid escape_unkown_field, "Type escapes via an unkown field accessed" +// avoid escape_cast_void, "Type escapes a cast to/from void*" eg: GIMPLE_NOP +/* { dg-do compile } */ + +#include <stdio.h> +#include <stdlib.h> + +typedef struct arc arc_t; +typedef struct arc *arc_p; + +struct arc +{ + int id; + int64_t cost; + short ident; + arc_p nextout; + arc_p nextin; + int64_t flow; + int64_t org_cost; +}; + +void +__attribute__((noinline)) spec_qsort (void *a, size_t es) +{ + char *pa; + char *pb; + int cmp_result; + + while ((*(arc_t **)a)->id < *((int *)a)) + { + if (cmp_result == 0) + { + spec_qsort (a, es); + pa = (char *)a - es; + a += es; + *(long *)pb = *(long *)pa; + } + else + { + a -= pa - pb; + } + } +} + +int +main() +{ + arc_p **arcs_pointer_sorted; + spec_qsort (arcs_pointer_sorted[0], sizeof (arc_p)); + return 0; +} + +/* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "reorder_fields" } } */ \ No newline at end of file diff --git a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp index 43913104e..5a476e8f9 100644 --- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp +++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp @@ -27,8 +27,21 @@ set STRUCT_REORG_TORTURE_OPTIONS [list \ set-torture-options $STRUCT_REORG_TORTURE_OPTIONS {{}} -gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \ +# -fipa-struct-reorg +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/wo_*.c]] \ + "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_*.c]] \ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.cpp]] \ + "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/sr_*.c]] \ + "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/csr_*.c]] \ + "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program" + +# -fipa-reorder-fields +gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/rf_*.c]] \ + "" "-fipa-reorder-fields -fdump-ipa-all -flto-partition=one -fwhole-program" # All done. torture-finish diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c index 6565fe8dd..23444fe8b 100644 --- a/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c +++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-1.c @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } +// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" } struct a { @@ -21,4 +21,10 @@ int g(void) return b->t; } +int main() +{ + f (); + return g (); +} + /* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */ diff --git a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c index 5864ad46f..2d1f95c99 100644 --- a/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c +++ b/gcc/testsuite/gcc.dg/struct/struct_reorg-3.c @@ -1,5 +1,5 @@ // { dg-do compile } -// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all" } +// { dg-options "-O3 -flto-partition=one -fipa-struct-reorg -fdump-ipa-all -fwhole-program" } #include <stdlib.h> typedef struct { @@ -10,7 +10,7 @@ typedef struct { compile_stack_elt_t *stack; unsigned size; } compile_stack_type; -void f (const char *p, const char *pend, int c) +__attribute__((noinline)) void f (const char *p, const char *pend, int c) { compile_stack_type compile_stack; while (p != pend) @@ -20,4 +20,9 @@ void f (const char *p, const char *pend, int c) * sizeof (compile_stack_elt_t)); } +int main() +{ + f (NULL, NULL, 1); +} + /* { dg-final { scan-ipa-dump "Number of structures to transform is 1" "struct_reorg" } } */ diff --git a/gcc/timevar.def b/gcc/timevar.def index 98a5a490f..2b27c858a 100644 --- a/gcc/timevar.def +++ b/gcc/timevar.def @@ -80,6 +80,7 @@ DEFTIMEVAR (TV_IPA_CONSTANT_PROP , "ipa cp") DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics") DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting") DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats") +DEFTIMEVAR (TV_IPA_REORDER_FIELDS , "ipa struct reorder fields optimization") DEFTIMEVAR (TV_IPA_STRUCT_REORG , "ipa struct reorg optimization") DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations") DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression") diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 56898e019..a9ec8ed21 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -527,6 +527,7 @@ extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt); extern ipa_opt_pass_d *make_pass_ipa_odr (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 simple_ipa_opt_pass *make_pass_ipa_reorder_fields (gcc::context *ctxt); extern simple_ipa_opt_pass *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); -- 2.33.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2