summaryrefslogtreecommitdiff
path: root/0021-StructReorderFields-Structure-reorder-fields.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
committerCoprDistGit <infra@openeuler.org>2025-02-28 10:03:49 +0000
commit73127104a245052cd5cf29cdaaca3e5c32c70348 (patch)
tree8e28b63e478c43c252f18b49836dff7313affe54 /0021-StructReorderFields-Structure-reorder-fields.patch
parent49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff)
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0021-StructReorderFields-Structure-reorder-fields.patch')
-rw-r--r--0021-StructReorderFields-Structure-reorder-fields.patch5739
1 files changed, 5739 insertions, 0 deletions
diff --git a/0021-StructReorderFields-Structure-reorder-fields.patch b/0021-StructReorderFields-Structure-reorder-fields.patch
new file mode 100644
index 0000000..8324617
--- /dev/null
+++ b/0021-StructReorderFields-Structure-reorder-fields.patch
@@ -0,0 +1,5739 @@
+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 &current_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 &current_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 &current_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 &current_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 &current_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
+