5371 lines
148 KiB
Diff
5371 lines
148 KiB
Diff
|
|
From bc86209da93f71d9fd48cb65ad3200b6c88cf75b Mon Sep 17 00:00:00 2001
|
|||
|
|
From: huangxiaoquan <huangxiaoquan1@huawei.com>
|
|||
|
|
Date: Tue, 20 Jul 2021 10:09:08 +0800
|
|||
|
|
Subject: [PATCH 18/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.
|
|||
|
|
|
|||
|
|
diff --git a/gcc/common.opt b/gcc/common.opt
|
|||
|
|
index d096ff9c314..73c24f28d22 100644
|
|||
|
|
--- a/gcc/common.opt
|
|||
|
|
+++ b/gcc/common.opt
|
|||
|
|
@@ -1865,6 +1865,10 @@ fipa-matrix-reorg
|
|||
|
|
Common Ignore
|
|||
|
|
Does nothing. Preserved for backward compatibility.
|
|||
|
|
|
|||
|
|
+fipa-reorder-fields
|
|||
|
|
+Common Report Var(flag_ipa_reorder_fields) Init(0) Optimization
|
|||
|
|
+Perform structure fields reorder optimizations.
|
|||
|
|
+
|
|||
|
|
fipa-struct-reorg
|
|||
|
|
Common Report 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 7b4578e3e44..4b0fd2ffb38 100644
|
|||
|
|
--- a/gcc/doc/invoke.texi
|
|||
|
|
+++ b/gcc/doc/invoke.texi
|
|||
|
|
@@ -478,6 +478,7 @@ Objective-C and Objective-C++ Dialects}.
|
|||
|
|
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
|
|||
|
|
-finline-small-functions -fipa-cp -fipa-cp-clone @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
|
|||
|
|
@@ -10224,6 +10225,14 @@ Enabled by default at @option{-O} and higher.
|
|||
|
|
Reduce stack alignment on call sites if possible.
|
|||
|
|
Enabled by default.
|
|||
|
|
|
|||
|
|
+@item -fipa-reorder-fields
|
|||
|
|
+@opindex fipa-reorder-fields
|
|||
|
|
+Introduce structure fields reordering optimization, that change fields
|
|||
|
|
+ordering of C-like structures in order to better utilize spatial locality.
|
|||
|
|
+This transformation is affective for programs containing arrays of structures.
|
|||
|
|
+It works only in whole program mode, so it requires @option{-fwhole-program}
|
|||
|
|
+to be enabled.
|
|||
|
|
+
|
|||
|
|
@item -fipa-struct-reorg
|
|||
|
|
@opindex fipa-struct-reorg
|
|||
|
|
Perform structure reorganization optimization, that change C-like structures
|
|||
|
|
diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def
|
|||
|
|
index 9020cc48952..03adc30811a 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.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
|||
|
|
index 1cb544ec3b0..384aa81583c 100644
|
|||
|
|
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
|||
|
|
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
|||
|
|
@@ -198,27 +198,66 @@ lang_c_p (void)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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 arg, tree *num, tree struct_size);
|
|||
|
|
+bool isptrptr (tree type);
|
|||
|
|
+
|
|||
|
|
+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)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -370,12 +409,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;
|
|||
|
|
@@ -399,17 +439,25 @@ 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.
|
|||
|
|
+ /* 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;
|
|||
|
|
}
|
|||
|
|
@@ -473,31 +521,29 @@ 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 = {");
|
|||
|
|
+ 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 = {");
|
|||
|
|
+ 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");
|
|||
|
|
+ fprintf (f, "}\n");
|
|||
|
|
fprintf (f, "}\n");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -507,6 +553,10 @@ 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. */
|
|||
|
|
@@ -544,6 +594,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++)
|
|||
|
|
@@ -592,6 +648,117 @@ 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
|
|||
|
|
@@ -627,7 +794,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;
|
|||
|
|
@@ -636,6 +804,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];
|
|||
|
|
|
|||
|
|
@@ -654,7 +823,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), newtype[i]);
|
|||
|
|
free (name);
|
|||
|
|
@@ -691,6 +861,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");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
@@ -749,7 +920,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);
|
|||
|
|
@@ -794,7 +970,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);
|
|||
|
|
}
|
|||
|
|
@@ -818,7 +995,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++)
|
|||
|
|
@@ -845,7 +1021,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");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@@ -880,7 +1056,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");
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -1010,8 +1186,7 @@ public:
|
|||
|
|
// Constructors
|
|||
|
|
ipa_struct_reorg(void)
|
|||
|
|
: current_function (NULL),
|
|||
|
|
- done_recording (false),
|
|||
|
|
- current_mode (NORMAL)
|
|||
|
|
+ done_recording (false)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -1023,11 +1198,12 @@ public:
|
|||
|
|
auto_vec_del<srfunction> functions;
|
|||
|
|
srglobal globals;
|
|||
|
|
srfunction *current_function;
|
|||
|
|
+ hash_set <cgraph_node *> safe_functions;
|
|||
|
|
|
|||
|
|
bool done_recording;
|
|||
|
|
- srmode current_mode;
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
@@ -1035,6 +1211,8 @@ 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 analyze_types (void);
|
|||
|
|
void clear_visited (void);
|
|||
|
|
bool create_new_types (void);
|
|||
|
|
@@ -1044,8 +1222,11 @@ public:
|
|||
|
|
void create_new_args (cgraph_node *new_node);
|
|||
|
|
unsigned rewrite_functions (void);
|
|||
|
|
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);
|
|||
|
|
@@ -1056,7 +1237,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);
|
|||
|
|
|
|||
|
|
@@ -1068,15 +1249,22 @@ public:
|
|||
|
|
bool rewrite_phi (gphi *);
|
|||
|
|
bool rewrite_expr (tree expr, tree newexpr[max_split], 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, vec<srdecl*> &worklist, gimple *stmt);
|
|||
|
|
+ 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);
|
|||
|
|
@@ -1731,9 +1919,45 @@ 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. */
|
|||
|
|
@@ -1763,7 +1987,6 @@ ipa_struct_reorg::dump_functions (FILE *f)
|
|||
|
|
unsigned i;
|
|||
|
|
srfunction *fn;
|
|||
|
|
|
|||
|
|
- fprintf (f, "\n\n");
|
|||
|
|
globals.dump (f);
|
|||
|
|
fprintf (f, "\n\n");
|
|||
|
|
FOR_EACH_VEC_ELT (functions, i, fn)
|
|||
|
|
@@ -1829,6 +2052,10 @@ bool isarraytype (tree type)
|
|||
|
|
|
|||
|
|
bool isptrptr (tree type)
|
|||
|
|
{
|
|||
|
|
+ if (type == NULL)
|
|||
|
|
+ {
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
bool firstptr = false;
|
|||
|
|
while (POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE)
|
|||
|
|
{
|
|||
|
|
@@ -1843,129 +2070,808 @@ bool 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. */
|
|||
|
|
|
|||
|
|
-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))
|
|||
|
|
{
|
|||
|
|
- if (TREE_CODE (field) == FIELD_DECL)
|
|||
|
|
- {
|
|||
|
|
- tree t = TREE_TYPE (field);
|
|||
|
|
- process_union (t);
|
|||
|
|
- if (TREE_CODE (inner_type (t)) == UNION_TYPE
|
|||
|
|
- || TREE_CODE (inner_type (t)) == QUAL_UNION_TYPE)
|
|||
|
|
+ fprintf (dump_file, "\n======== check node definition ========\n");
|
|||
|
|
+ }
|
|||
|
|
+ for (unsigned i = 1; i < num_ssa_names; ++i)
|
|||
|
|
+ {
|
|||
|
|
+ tree name = ssa_name (i);
|
|||
|
|
+ if (name && ptr_layers.get (name) != 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)
|
|||
|
|
{
|
|||
|
|
- type1->mark_escape (escape_union, NULL);
|
|||
|
|
+ res = check_def_phi (name, ptr_layers);
|
|||
|
|
}
|
|||
|
|
- 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))
|
|||
|
|
+ else if (gimple_code (def_stmt) == GIMPLE_ASSIGN)
|
|||
|
|
{
|
|||
|
|
- 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);
|
|||
|
|
- }
|
|||
|
|
+ res = check_def_assign (name, ptr_layers);
|
|||
|
|
}
|
|||
|
|
- }
|
|||
|
|
+ else if (gimple_code (def_stmt) == GIMPLE_NOP)
|
|||
|
|
+ {
|
|||
|
|
+ continue;
|
|||
|
|
+ }
|
|||
|
|
+ else
|
|||
|
|
+ {
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
+ }
|
|||
|
|
}
|
|||
|
|
-
|
|||
|
|
- return type1;
|
|||
|
|
+ return res;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
-/* Mark TYPE as escaping with ESCAPES as the reason. */
|
|||
|
|
+/* Check pointer usage. */
|
|||
|
|
|
|||
|
|
-void
|
|||
|
|
-ipa_struct_reorg::mark_type_as_escape (tree type, escape_type escapes, gimple *stmt)
|
|||
|
|
+bool
|
|||
|
|
+check_record_ptr_usage (gimple *use_stmt, tree ¤t_node,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers,
|
|||
|
|
+ auto_vec <tree> &ssa_name_stack)
|
|||
|
|
{
|
|||
|
|
- if (handled_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);
|
|||
|
|
+ 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))
|
|||
|
|
{
|
|||
|
|
- srtype *stype = record_type (inner_type (type));
|
|||
|
|
-
|
|||
|
|
- if (!stype)
|
|||
|
|
- return;
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
|
|||
|
|
- stype->mark_escape (escapes, stmt);
|
|||
|
|
+ bool res = true;
|
|||
|
|
+ /* MEM[(long int *)a_1] = _57; (record).
|
|||
|
|
+ If lhs is ssa_name, lhs cannot be the current node.
|
|||
|
|
+ _283 = _282->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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
-/* Maybe process the union of type TYPE, such that marking all of the fields'
|
|||
|
|
- types as being escaping. */
|
|||
|
|
+/* Check and record a single node. */
|
|||
|
|
|
|||
|
|
-void
|
|||
|
|
-ipa_struct_reorg::process_union (tree type)
|
|||
|
|
+bool
|
|||
|
|
+check_record_single_node (gimple *use_stmt, tree ¤t_node,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers,
|
|||
|
|
+ auto_vec <tree> &ssa_name_stack)
|
|||
|
|
{
|
|||
|
|
- static hash_set<tree> unions_recorded;
|
|||
|
|
-
|
|||
|
|
- 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;
|
|||
|
|
+ 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);
|
|||
|
|
|
|||
|
|
- for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
|||
|
|
+ if ((TREE_CODE (rhs1) != SSA_NAME && TREE_CODE (rhs1) != MEM_REF)
|
|||
|
|
+ || (TREE_CODE (lhs) != SSA_NAME && TREE_CODE (lhs) != MEM_REF))
|
|||
|
|
{
|
|||
|
|
- if (TREE_CODE (field) == FIELD_DECL)
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
+ bool res = true;
|
|||
|
|
+ if (TREE_CODE (lhs) == SSA_NAME && TREE_CODE (rhs1) == MEM_REF)
|
|||
|
|
+ {
|
|||
|
|
+ /* _257 = MEM[(struct arc_t * *)_17]. */
|
|||
|
|
+ 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)
|
|||
|
|
+ {
|
|||
|
|
+ /* MEM[(long int *)a_1] = _57. */
|
|||
|
|
+ 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;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+/* Check and record multiple nodes. */
|
|||
|
|
+
|
|||
|
|
+bool
|
|||
|
|
+check_record_mult_node (gimple *use_stmt, tree ¤t_node,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers,
|
|||
|
|
+ auto_vec <tree> &ssa_name_stack)
|
|||
|
|
+{
|
|||
|
|
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
|
|||
|
|
+ tree_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;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
+ 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;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+/* Check whether gimple assign is correctly used and record node. */
|
|||
|
|
+
|
|||
|
|
+bool
|
|||
|
|
+check_record_assign (tree ¤t_node, gimple *use_stmt,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers,
|
|||
|
|
+ auto_vec <tree> &ssa_name_stack)
|
|||
|
|
+{
|
|||
|
|
+ gimple_rhs_class rhs_class = gimple_assign_rhs_class (use_stmt);
|
|||
|
|
+ if (*ptr_layers.get (current_node) == 1)
|
|||
|
|
+ {
|
|||
|
|
+ return check_record_ptr_usage (use_stmt, current_node,
|
|||
|
|
+ ptr_layers, ssa_name_stack);
|
|||
|
|
+ }
|
|||
|
|
+ else if (*ptr_layers.get (current_node) > 1)
|
|||
|
|
+ {
|
|||
|
|
+ if (rhs_class != GIMPLE_BINARY_RHS
|
|||
|
|
+ && rhs_class != GIMPLE_UNARY_RHS
|
|||
|
|
+ && rhs_class != GIMPLE_SINGLE_RHS)
|
|||
|
|
+ {
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
+ if (rhs_class == GIMPLE_SINGLE_RHS || rhs_class == GIMPLE_UNARY_RHS)
|
|||
|
|
+ {
|
|||
|
|
+ return check_record_single_node (use_stmt, current_node,
|
|||
|
|
+ ptr_layers, ssa_name_stack);
|
|||
|
|
+ }
|
|||
|
|
+ else if (rhs_class == GIMPLE_BINARY_RHS)
|
|||
|
|
+ {
|
|||
|
|
+ return check_record_mult_node (use_stmt, current_node,
|
|||
|
|
+ ptr_layers, ssa_name_stack);
|
|||
|
|
+ }
|
|||
|
|
+ }
|
|||
|
|
+ else
|
|||
|
|
+ return false;
|
|||
|
|
+
|
|||
|
|
+ return true;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+/* Check whether gimple phi is correctly used and record node. */
|
|||
|
|
+
|
|||
|
|
+bool
|
|||
|
|
+check_record_phi (tree ¤t_node, gimple *use_stmt,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers,
|
|||
|
|
+ auto_vec <tree> &ssa_name_stack)
|
|||
|
|
+{
|
|||
|
|
+ bool res = true;
|
|||
|
|
+ res &= add_node (gimple_phi_result (use_stmt), *ptr_layers.get (current_node),
|
|||
|
|
+ ptr_layers, ssa_name_stack);
|
|||
|
|
+
|
|||
|
|
+ for (unsigned i = 0; i < gimple_phi_num_args (use_stmt); i++)
|
|||
|
|
+ {
|
|||
|
|
+ if (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;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+/* Check the use of callee. */
|
|||
|
|
+
|
|||
|
|
+bool
|
|||
|
|
+check_callee (cgraph_node *node, gimple *stmt,
|
|||
|
|
+ hash_map <tree, int> &ptr_layers, int input_layers)
|
|||
|
|
+{
|
|||
|
|
+ /* 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++)
|
|||
|
|
+ {
|
|||
|
|
+ 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;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
+/* 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. */
|
|||
|
|
+ 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)
|
|||
|
|
+ || !handled_type (TREE_TYPE (input)))
|
|||
|
|
+ {
|
|||
|
|
+ return false;
|
|||
|
|
+ }
|
|||
|
|
+ input_layers = get_ptr_layers (TREE_TYPE (input));
|
|||
|
|
+
|
|||
|
|
+ /* 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); } */
|
|||
|
|
+ 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. */
|
|||
|
|
+
|
|||
|
|
+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);
|
|||
|
|
+
|
|||
|
|
+ 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));
|
|||
|
|
@@ -2022,7 +2928,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)));
|
|||
|
|
@@ -2059,7 +2966,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;
|
|||
|
|
@@ -2138,8 +3046,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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
@@ -2157,10 +3067,26 @@ 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);
|
|||
|
|
@@ -2172,9 +3098,11 @@ ipa_struct_reorg::find_vars (gimple *stmt)
|
|||
|
|
current_function->record_decl (t, var, -1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
+ /* 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);
|
|||
|
|
@@ -2187,6 +3115,26 @@ ipa_struct_reorg::find_vars (gimple *stmt)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
+ 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);
|
|||
|
|
+ }
|
|||
|
|
+ /* _23 = _21 - old_arcs_12. */
|
|||
|
|
+ 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,
|
|||
|
|
@@ -2279,8 +3227,122 @@ ipa_struct_reorg::maybe_record_stmt (cgraph_node *node, gimple *stmt)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
+/* 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);
|
|||
|
|
+
|
|||
|
|
+ /* _480 = -_479; _479 = _478 * 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. */
|
|||
|
|
+
|
|||
|
|
+static bool
|
|||
|
|
+trace_calculate_diff (gimple *size_def_stmt, tree *num)
|
|||
|
|
+{
|
|||
|
|
+ gcc_assert (gimple_assign_rhs_code (size_def_stmt) == NOP_EXPR);
|
|||
|
|
+
|
|||
|
|
+ /* _25 = (long unsigned int) _23; _23 = _21 - old_arcs_12. */
|
|||
|
|
+ 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)
|
|||
|
|
+ {
|
|||
|
|
+ *num = NULL_TREE;
|
|||
|
|
+ return true;
|
|||
|
|
+ }
|
|||
|
|
+ *num = NULL_TREE;
|
|||
|
|
+ return false;
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
/* This function checks whether ARG is a result of multiplication
|
|||
|
|
- of some number by STRUCT_SIZE. If yes, the function returns true
|
|||
|
|
+ of some number by STRUCT_SIZE. If yes, the function returns true
|
|||
|
|
and this number is filled into NUM. */
|
|||
|
|
|
|||
|
|
static bool
|
|||
|
|
@@ -2291,30 +3353,12 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
|
|||
|
|
|| integer_zerop (struct_size))
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
- /* If we have a integer, just check if it is a multiply of 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
|
|||
|
|
@@ -2330,43 +3374,28 @@ 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;
|
|||
|
|
+ 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);
|
|||
|
|
}
|
|||
|
|
- if (gimple_assign_rhs_code (size_def_stmt) == MULT_EXPR)
|
|||
|
|
+ else if (rhs_code == 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;
|
|||
|
|
+ return trace_calculate_mult (size_def_stmt, num, struct_size);
|
|||
|
|
}
|
|||
|
|
- else if (gimple_assign_rhs_code (size_def_stmt) == SSA_NAME)
|
|||
|
|
+ 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;
|
|||
|
|
@@ -2383,10 +3412,17 @@ 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 ((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)
|
|||
|
|
@@ -2402,7 +3438,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
|
|||
|
|
@@ -2422,6 +3458,12 @@ 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)
|
|||
|
|
@@ -2435,7 +3477,9 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
|
|||
|
|
if (operand_equal_p (arg1, struct_size, 0))
|
|||
|
|
return size;
|
|||
|
|
/* ??? Check that first argument is a constant
|
|||
|
|
- equal to the size of structure. */
|
|||
|
|
+ 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))
|
|||
|
|
@@ -2479,17 +3523,38 @@ ipa_struct_reorg::maybe_mark_or_record_other_side (tree side, tree other, gimple
|
|||
|
|
|
|||
|
|
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,
|
|||
|
|
+ find_decl (other) ? find_decl (other)->orig_type : NULL);
|
|||
|
|
+ }
|
|||
|
|
else
|
|||
|
|
- type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+ {
|
|||
|
|
+ /* *_1 = &MEM[(void *)&x + 8B]. */
|
|||
|
|
+ type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+ }
|
|||
|
|
}
|
|||
|
|
else if (type != d->type)
|
|||
|
|
{
|
|||
|
|
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. */
|
|||
|
|
@@ -2515,7 +3580,11 @@ 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. */
|
|||
|
|
- if (is_result_of_mult (rhs2, &num, TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (lhs)))))
|
|||
|
|
+ /* The size adjustment and judgment of multi-layer pointers
|
|||
|
|
+ are added. */
|
|||
|
|
+ if (is_result_of_mult (rhs2, &num, 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);
|
|||
|
|
@@ -2553,9 +3622,8 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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)
|
|||
|
|
@@ -2570,13 +3638,18 @@ check_mem_ref_offset (tree 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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tree
|
|||
|
|
-get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, tree &accesstype)
|
|||
|
|
+get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
|
|||
|
|
+ bool &realpart, bool &imagpart,
|
|||
|
|
+ tree &accesstype, tree *num)
|
|||
|
|
{
|
|||
|
|
offset = 0;
|
|||
|
|
realpart = false;
|
|||
|
|
@@ -2599,22 +3672,29 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &i
|
|||
|
|
{
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
@@ -2655,8 +3735,13 @@ ipa_struct_reorg::wholeaccess (tree expr, tree base, tree accesstype, srtype *t)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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 can_escape)
|
|||
|
|
+ipa_struct_reorg::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,
|
|||
|
|
+ bool can_escape)
|
|||
|
|
{
|
|||
|
|
+ tree num = NULL_TREE;
|
|||
|
|
HOST_WIDE_INT offset;
|
|||
|
|
tree accesstype;
|
|||
|
|
address = false;
|
|||
|
|
@@ -2668,7 +3753,9 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
mark_as_bit_field = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
- base = get_ref_base_and_offset (expr, offset, realpart, imagpart, accesstype);
|
|||
|
|
+ /* ref is classified into two types: COMPONENT_REF or MER_REF. */
|
|||
|
|
+ base = get_ref_base_and_offset (expr, offset, realpart, imagpart,
|
|||
|
|
+ accesstype, &num);
|
|||
|
|
|
|||
|
|
/* Variable access, unkown type. */
|
|||
|
|
if (base == NULL)
|
|||
|
|
@@ -2706,6 +3793,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
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)
|
|||
|
|
@@ -2717,15 +3806,54 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
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.). */
|
|||
|
|
+ /* _607 = MEM[(struct arc_t * *)pl_100].
|
|||
|
|
+ then base pl_100:ssa_name - pointer_type - integer_type. */
|
|||
|
|
+ if (current_mode == STRUCT_REORDER_FIELDS)
|
|||
|
|
+ {
|
|||
|
|
+ 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
|
|||
|
|
{
|
|||
|
|
- gcc_assert (can_escape);
|
|||
|
|
- t->mark_escape (escape_cast_another_ptr, NULL);
|
|||
|
|
- return false;
|
|||
|
|
+ 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;
|
|||
|
|
@@ -2733,7 +3861,10 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
t = d->type;
|
|||
|
|
|
|||
|
|
if (t->has_escaped ())
|
|||
|
|
+ {
|
|||
|
|
+ escape_from_base = true;
|
|||
|
|
return false;
|
|||
|
|
+ }
|
|||
|
|
|
|||
|
|
if (mark_as_bit_field)
|
|||
|
|
{
|
|||
|
|
@@ -2759,7 +3890,6 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
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);
|
|||
|
|
@@ -2773,9 +3903,8 @@ ipa_struct_reorg::get_type_field (tree expr, tree &base, bool &indirect, srtype
|
|||
|
|
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);
|
|||
|
|
@@ -2797,7 +3926,9 @@ ipa_struct_reorg::mark_expr_escape (tree expr, escape_type escapes, gimple *stmt
|
|||
|
|
srtype *type;
|
|||
|
|
srfield *field;
|
|||
|
|
bool realpart, imagpart, address;
|
|||
|
|
- if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address))
|
|||
|
|
+ bool escape_from_base = false;
|
|||
|
|
+ if (!get_type_field (expr, base, indirect, type, field,
|
|||
|
|
+ realpart, imagpart, address, escape_from_base))
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
type->mark_escape (escapes, stmt);
|
|||
|
|
@@ -2875,6 +4006,7 @@ ipa_struct_reorg::maybe_record_call (cgraph_node *node, gcall *stmt)
|
|||
|
|
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++)
|
|||
|
|
{
|
|||
|
|
@@ -2882,9 +4014,16 @@ 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);
|
|||
|
|
}
|
|||
|
|
@@ -2905,11 +4044,26 @@ ipa_struct_reorg::record_stmt_expr (tree expr, cgraph_node *node, gimple *stmt)
|
|||
|
|
srtype *type;
|
|||
|
|
srfield *field;
|
|||
|
|
bool realpart, imagpart, address;
|
|||
|
|
- if (!get_type_field (expr, base, indirect, type, field, realpart, imagpart, address))
|
|||
|
|
+ bool escape_from_base = false;
|
|||
|
|
+ if (!get_type_field (expr, base, indirect, type, field,
|
|||
|
|
+ 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));
|
|||
|
|
@@ -2927,8 +4081,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;
|
|||
|
|
|
|||
|
|
@@ -2940,8 +4096,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*>
|
|||
|
|
type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
- if (d->type == type)
|
|||
|
|
- return;
|
|||
|
|
+ if (d->type == type
|
|||
|
|
+ && cmp_ptr_layers (TREE_TYPE (newdecl), TREE_TYPE (decl->decl)))
|
|||
|
|
+ return;
|
|||
|
|
|
|||
|
|
srtype *type1 = d->type;
|
|||
|
|
type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
@@ -2991,7 +4148,9 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type, vec<srdecl*>
|
|||
|
|
/* 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;
|
|||
|
|
@@ -3033,6 +4192,111 @@ 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
|
|||
|
|
@@ -3058,9 +4322,16 @@ 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);
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
@@ -3069,15 +4340,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist)
|
|||
|
|
*/
|
|||
|
|
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)
|
|||
|
|
@@ -3091,61 +4354,16 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl*> &worklist)
|
|||
|
|
if (gimple_code (stmt) == GIMPLE_PHI)
|
|||
|
|
{
|
|||
|
|
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);
|
|||
|
|
+ check_type_and_push (gimple_phi_arg_def (stmt, i),
|
|||
|
|
+ decl, worklist, stmt);
|
|||
|
|
}
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
-
|
|||
|
|
- /* Casts between pointers and integer are escaping. */
|
|||
|
|
- if (gimple_assign_cast_p (stmt))
|
|||
|
|
+ if (gimple_code (stmt) == GIMPLE_ASSIGN)
|
|||
|
|
{
|
|||
|
|
- type->mark_escape (escape_cast_int, stmt);
|
|||
|
|
- return;
|
|||
|
|
+ check_definition_assign (decl, worklist);
|
|||
|
|
}
|
|||
|
|
-
|
|||
|
|
- /*
|
|||
|
|
- 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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/* Mark the types used by the inline-asm as escaping. It is unkown what happens inside
|
|||
|
|
@@ -3177,11 +4395,10 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec<
|
|||
|
|
{
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3207,8 +4424,29 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec<
|
|||
|
|
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);
|
|||
|
|
+ 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;
|
|||
|
|
}
|
|||
|
|
@@ -3220,6 +4458,71 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt, vec<
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
+/* 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)
|
|||
|
|
+ {
|
|||
|
|
+ a->type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+ else if (b && a == NULL && TREE_CODE (a_expr) != INTEGER_CST)
|
|||
|
|
+ {
|
|||
|
|
+ b->type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+ else if (a == NULL && b == NULL)
|
|||
|
|
+ {
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
+ if (cmp_ptr_layers (TREE_TYPE (a_expr), TREE_TYPE (b_expr)))
|
|||
|
|
+ {
|
|||
|
|
+ return;
|
|||
|
|
+ }
|
|||
|
|
+ a->type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+ b->type->mark_escape (escape_cast_another_ptr, stmt);
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
void
|
|||
|
|
ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
{
|
|||
|
|
@@ -3234,7 +4537,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3250,10 +4553,15 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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);
|
|||
|
|
@@ -3264,7 +4572,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3284,9 +4592,14 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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);
|
|||
|
|
@@ -3298,7 +4611,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3312,6 +4625,7 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
check_other_side (decl, lhs, stmt, worklist);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
+ check_ptr_layers (lhs, rhs, stmt);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (is_gimple_assign (stmt)
|
|||
|
|
@@ -3321,10 +4635,26 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt, vec<srdecl*> &worklist)
|
|||
|
|
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;
|
|||
|
|
+ }
|
|||
|
|
+
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
@@ -3388,17 +4718,51 @@ 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)
|
|||
|
|
{
|
|||
|
|
@@ -3529,6 +4893,49 @@ ipa_struct_reorg::record_function (cgraph_node *node)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
+/* 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
|
|||
|
|
@@ -3560,6 +4967,12 @@ 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 ())
|
|||
|
|
@@ -3578,11 +4991,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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3606,6 +5022,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))
|
|||
|
|
{
|
|||
|
|
@@ -3685,22 +5102,99 @@ 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[i]->fields.length (); j++)
|
|||
|
|
+ {
|
|||
|
|
+ srfield *field = types[i]->fields[j];
|
|||
|
|
+ if (handled_type (field->fieldtype) && field->type)
|
|||
|
|
+ {
|
|||
|
|
+ for (unsigned k = 0; k < types.length (); k++)
|
|||
|
|
+ {
|
|||
|
|
+ const char *type1 = get_type_name (field->type->type);
|
|||
|
|
+ const char *type2 = get_type_name (types[k]->type);
|
|||
|
|
+ if (type1 == NULL || type2 == NULL)
|
|||
|
|
+ {
|
|||
|
|
+ continue;
|
|||
|
|
+ }
|
|||
|
|
+ if (type1 == type2 && types[k]->has_escaped ())
|
|||
|
|
+ {
|
|||
|
|
+ if (!field->type->has_escaped ())
|
|||
|
|
+ {
|
|||
|
|
+ field->type->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);
|
|||
|
|
+ }
|
|||
|
|
+ }
|
|||
|
|
+ }
|
|||
|
|
+ }
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
/* 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 ();
|
|||
|
|
+ }
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -3748,7 +5242,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);
|
|||
|
|
@@ -3773,24 +5268,33 @@ 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);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
@@ -3817,6 +5321,28 @@ 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)
|
|||
|
|
@@ -3919,7 +5445,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);
|
|||
|
|
}
|
|||
|
|
@@ -4005,9 +5532,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;
|
|||
|
|
@@ -4047,6 +5575,7 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_
|
|||
|
|
srfield *f;
|
|||
|
|
bool realpart, imagpart;
|
|||
|
|
bool address;
|
|||
|
|
+ bool escape_from_base = false;
|
|||
|
|
|
|||
|
|
tree newbase[max_split];
|
|||
|
|
memset (newexpr, 0, sizeof(tree[max_split]));
|
|||
|
|
@@ -4064,7 +5593,8 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_
|
|||
|
|
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. */
|
|||
|
|
@@ -4122,7 +5652,40 @@ ipa_struct_reorg::rewrite_expr (tree expr, tree newexpr[max_split], bool ignore_
|
|||
|
|
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_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;
|
|||
|
|
+ */
|
|||
|
|
+ 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)
|
|||
|
|
@@ -4162,8 +5725,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);
|
|||
|
|
@@ -4171,6 +5738,12 @@ 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;
|
|||
|
|
@@ -4208,19 +5781,88 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
|
|||
|
|
if (!is_result_of_mult (rhs2, &num, size))
|
|||
|
|
internal_error ("the rhs of pointer was not a multiplicate and it slipped 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);
|
|||
|
|
@@ -4228,21 +5870,20 @@ ipa_struct_reorg::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
|
|||
|
|
|
|||
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|||
|
|
{
|
|||
|
|
- fprintf (dump_file, "rewriting stamtenet:\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];
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|||
|
|
- fprintf (dump_file, "\nreplaced with:\n");
|
|||
|
|
+ fprintf (dump_file, "replaced with:\n");
|
|||
|
|
for (unsigned i = 0; i < max_split && (newlhs[i] || newrhs[i]); i++)
|
|||
|
|
{
|
|||
|
|
gimple *newstmt = gimple_build_assign (newlhs[i] ? newlhs[i] : lhs, newrhs[i] ? newrhs[i] : rhs);
|
|||
|
|
@@ -4276,7 +5917,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));
|
|||
|
|
|
|||
|
|
@@ -4296,7 +5937,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. */
|
|||
|
|
if (!gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
|
|||
|
|
@@ -4356,6 +6000,25 @@ 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)
|
|||
|
|
@@ -4440,7 +6103,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
|
|||
|
|
@@ -4453,8 +6116,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
|
|||
|
|
@@ -4466,48 +6128,58 @@ 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++)
|
|||
|
|
- {
|
|||
|
|
- 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)
|
|||
|
|
+ /* 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++)
|
|||
|
|
{
|
|||
|
|
- 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;
|
|||
|
|
}
|
|||
|
|
@@ -4518,6 +6190,11 @@ 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))
|
|||
|
|
{
|
|||
|
|
@@ -4570,7 +6247,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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@@ -4581,7 +6258,17 @@ 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]);
|
|||
|
|
@@ -4592,7 +6279,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);
|
|||
|
|
@@ -4666,12 +6353,58 @@ 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 ());
|
|||
|
|
+ dump_function_to_file (current_function_decl, dump_file,
|
|||
|
|
+ dump_flags | TDF_VOPS);
|
|||
|
|
+ }
|
|||
|
|
+ pop_cfun ();
|
|||
|
|
+ }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
create_new_decls ();
|
|||
|
|
@@ -4694,8 +6427,12 @@ ipa_struct_reorg::rewrite_functions (void)
|
|||
|
|
|
|||
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
|||
|
|
{
|
|||
|
|
- fprintf (dump_file, "\nBefore rewrite:\n");
|
|||
|
|
- dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS);
|
|||
|
|
+ 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)
|
|||
|
|
{
|
|||
|
|
@@ -4763,10 +6500,12 @@ 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");
|
|||
|
|
- dump_function_to_file (current_function_decl, dump_file, dump_flags | TDF_VOPS);
|
|||
|
|
+ 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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pop_cfun ();
|
|||
|
|
@@ -4820,9 +6559,9 @@ ipa_struct_reorg::execute (enum srmode mode)
|
|||
|
|
{
|
|||
|
|
unsigned int ret = 0;
|
|||
|
|
|
|||
|
|
- if (mode == NORMAL)
|
|||
|
|
+ if (mode == NORMAL || mode == STRUCT_REORDER_FIELDS)
|
|||
|
|
{
|
|||
|
|
- current_mode = NORMAL;
|
|||
|
|
+ current_mode = mode;
|
|||
|
|
/* If there is a top-level inline-asm,
|
|||
|
|
the pass immediately returns. */
|
|||
|
|
if (symtab->first_asm_symbol ())
|
|||
|
|
@@ -4831,7 +6570,10 @@ ipa_struct_reorg::execute (enum srmode mode)
|
|||
|
|
}
|
|||
|
|
record_accesses ();
|
|||
|
|
prune_escaped_types ();
|
|||
|
|
- analyze_types ();
|
|||
|
|
+ if (current_mode == NORMAL)
|
|||
|
|
+ {
|
|||
|
|
+ analyze_types ();
|
|||
|
|
+ }
|
|||
|
|
|
|||
|
|
ret = rewrite_functions ();
|
|||
|
|
}
|
|||
|
|
@@ -4903,6 +6645,47 @@ pass_ipa_struct_reorg::gate (function *)
|
|||
|
|
&& lang_c_p ());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
+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);
|
|||
|
|
+}
|
|||
|
|
+
|
|||
|
|
} // anon namespace
|
|||
|
|
|
|||
|
|
simple_ipa_opt_pass *
|
|||
|
|
@@ -4910,3 +6693,9 @@ make_pass_ipa_struct_reorg (gcc::context *ctxt)
|
|||
|
|
{
|
|||
|
|
return new pass_ipa_struct_reorg (ctxt);
|
|||
|
|
}
|
|||
|
|
+
|
|||
|
|
+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 d8fe399bdf8..8fb6ce9c448 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);
|
|||
|
|
|
|||
|
|
@@ -183,6 +185,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
|
|||
|
|
@@ -219,8 +226,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 fa744e25038..63303ab65bb 100644
|
|||
|
|
--- a/gcc/passes.def
|
|||
|
|
+++ b/gcc/passes.def
|
|||
|
|
@@ -173,6 +173,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
|
INSERT_PASSES_AFTER (all_late_ipa_passes)
|
|||
|
|
NEXT_PASS (pass_materialize_all_clones);
|
|||
|
|
NEXT_PASS (pass_ipa_pta);
|
|||
|
|
+ NEXT_PASS (pass_ipa_reorder_fields);
|
|||
|
|
/* FIXME: this should a normal IP pass */
|
|||
|
|
NEXT_PASS (pass_ipa_struct_reorg);
|
|||
|
|
NEXT_PASS (pass_omp_simd_clone);
|
|||
|
|
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 00000000000..b95be2dabc2
|
|||
|
|
--- /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 00000000000..3d243313ba9
|
|||
|
|
--- /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_create_fields_bug.c b/gcc/testsuite/gcc.dg/struct/rf_create_fields_bug.c
|
|||
|
|
new file mode 100644
|
|||
|
|
index 00000000000..886706ae913
|
|||
|
|
--- /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 00000000000..f3785f392e3
|
|||
|
|
--- /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 00000000000..1415d759ad6
|
|||
|
|
--- /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 00000000000..003da0b57bf
|
|||
|
|
--- /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_int_cast_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_int_cast_ptr.c
|
|||
|
|
new file mode 100644
|
|||
|
|
index 00000000000..10dcf098c3c
|
|||
|
|
--- /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 00000000000..8d1a9a114c1
|
|||
|
|
--- /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_pass_conflict.c b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c
|
|||
|
|
new file mode 100644
|
|||
|
|
index 00000000000..8d687c58b30
|
|||
|
|
--- /dev/null
|
|||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/rf_pass_conflict.c
|
|||
|
|
@@ -0,0 +1,110 @@
|
|||
|
|
+// 针对
|
|||
|
|
+/*
|
|||
|
|
+Compile options: /home/hxq/hcc_gcc9.3.0_org_debug/bin/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, copy.tail, copy.head);
|
|||
|
|
+ }
|
|||
|
|
+ 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 00000000000..190b9418275
|
|||
|
|
--- /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 "Number of structures to transform is 1" "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 00000000000..3a3c10b70ba
|
|||
|
|
--- /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 00000000000..7b7d110df4c
|
|||
|
|
--- /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_ptr.c b/gcc/testsuite/gcc.dg/struct/rf_ptr_ptr.c
|
|||
|
|
new file mode 100644
|
|||
|
|
index 00000000000..01a33f66962
|
|||
|
|
--- /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 00000000000..a38556533f1
|
|||
|
|
--- /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 00000000000..5c17ee528c8
|
|||
|
|
--- /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 00000000000..710517ee9e2
|
|||
|
|
--- /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 00000000000..6ed0a5d2d6b
|
|||
|
|
--- /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 00000000000..5a2dd964fc2
|
|||
|
|
--- /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 00000000000..faa90b42ddc
|
|||
|
|
--- /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 00000000000..2bb326ff200
|
|||
|
|
--- /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 00000000000..8f2da99ccdf
|
|||
|
|
--- /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 00000000000..723142c5975
|
|||
|
|
--- /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 1bd0e18ea2e..c8db4675f11 100644
|
|||
|
|
--- a/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
|
|||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/struct-reorg.exp
|
|||
|
|
@@ -27,8 +27,25 @@ 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_prof_*.c]] \
|
|||
|
|
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|||
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_ratio_*.c]] \
|
|||
|
|
"" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|||
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/w_prof_*.c]] \
|
|||
|
|
+ "" "-fipa-struct-reorg -fdump-ipa-all -flto-partition=one -fwhole-program"
|
|||
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/struct_reorg*.c]] \
|
|||
|
|
+ "" "-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"
|
|||
|
|
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/complete_struct_relayout.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/timevar.def b/gcc/timevar.def
|
|||
|
|
index d6a05562c2f..ee25eccbb67 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 d8355754ffa..eb32c5d441b 100644
|
|||
|
|
--- a/gcc/tree-pass.h
|
|||
|
|
+++ b/gcc/tree-pass.h
|
|||
|
|
@@ -509,6 +509,7 @@ 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_hsa (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.21.0.windows.1
|
|||
|
|
|