gcc/0021-StructReorderFields-Structure-reorder-fields.patch
h00564365 adacc909ea [Sync] Sync patch from openeuler/gcc
Sync patch from openeuler/gcc - 20230829

(cherry picked from commit 5e9724992d967ef598d70c92c5c936ebbf828946)
2023-08-29 20:59:41 +08:00

5740 lines
164 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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