1815 lines
44 KiB
Diff
1815 lines
44 KiB
Diff
|
|
diff -Nurp a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def
|
||
|
|
--- a/gcc/ipa-struct-reorg/escapes.def 2020-07-18 05:11:11.548000000 -0400
|
||
|
|
+++ b/gcc/ipa-struct-reorg/escapes.def 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -56,5 +56,7 @@ DEF_ESCAPE (escape_non_optimize, "Type u
|
||
|
|
DEF_ESCAPE (escape_array, "Type is used in an array [not handled yet]")
|
||
|
|
DEF_ESCAPE (escape_ptr_ptr, "Type is used in a pointer to a pointer [not handled yet]")
|
||
|
|
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")
|
||
|
|
|
||
|
|
#undef DEF_ESCAPE
|
||
|
|
diff -Nurp a/gcc/ipa-struct-reorg/ipa-struct-reorg.c b/gcc/ipa-struct-reorg/ipa-struct-reorg.c
|
||
|
|
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.c 2020-07-18 05:11:17.664000000 -0400
|
||
|
|
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.c 2020-07-20 09:08:08.912000000 -0400
|
||
|
|
@@ -95,6 +95,7 @@ along with GCC; see the file COPYING3.
|
||
|
|
#include "ipa-struct-reorg.h"
|
||
|
|
#include "tree-eh.h"
|
||
|
|
#include "bitmap.h"
|
||
|
|
+#include "cfgloop.h"
|
||
|
|
#include "ipa-param-manipulation.h"
|
||
|
|
#include "tree-ssa-live.h" /* For remove_unused_locals. */
|
||
|
|
|
||
|
|
@@ -103,6 +104,7 @@ along with GCC; see the file COPYING3.
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
using namespace struct_reorg;
|
||
|
|
+using namespace struct_relayout;
|
||
|
|
|
||
|
|
/* Return true iff TYPE is stdarg va_list type. */
|
||
|
|
|
||
|
|
@@ -152,6 +154,14 @@ handled_type (tree type)
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
+enum srmode
|
||
|
|
+{
|
||
|
|
+ NORMAL = 0,
|
||
|
|
+ COMPLETE_STRUCT_RELAYOUT
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static bool is_result_of_mult (tree arg, tree *num, tree struct_size);
|
||
|
|
+
|
||
|
|
} // anon namespace
|
||
|
|
|
||
|
|
namespace struct_reorg {
|
||
|
|
@@ -241,7 +251,8 @@ srtype::srtype (tree type)
|
||
|
|
: type (type),
|
||
|
|
chain_type (false),
|
||
|
|
escapes (does_not_escape),
|
||
|
|
- visited (false)
|
||
|
|
+ visited (false),
|
||
|
|
+ has_alloc_array (0)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < max_split; i++)
|
||
|
|
newtype[i] = NULL_TREE;
|
||
|
|
@@ -441,13 +452,6 @@ srtype::dump (FILE *f)
|
||
|
|
fn->simple_dump (f);
|
||
|
|
}
|
||
|
|
fprintf (f, "\n }\n");
|
||
|
|
- fprintf (f, "\n field_sites = {");
|
||
|
|
- FOR_EACH_VEC_ELT (field_sites, i, field)
|
||
|
|
- {
|
||
|
|
- fprintf (f, " \n");
|
||
|
|
- field->simple_dump (f);
|
||
|
|
- }
|
||
|
|
- fprintf (f, "\n }\n");
|
||
|
|
fprintf (f, "}\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -798,12 +802,6 @@ srfield::dump (FILE *f)
|
||
|
|
fprintf (f, ", offset = " HOST_WIDE_INT_PRINT_DEC, offset);
|
||
|
|
fprintf (f, ", type = ");
|
||
|
|
print_generic_expr (f, fieldtype);
|
||
|
|
- if (type)
|
||
|
|
- {
|
||
|
|
- fprintf (f, "( srtype = ");
|
||
|
|
- type->simple_dump (f);
|
||
|
|
- fprintf (f, ")");
|
||
|
|
- }
|
||
|
|
fprintf (f, "\n}\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -813,7 +811,10 @@ srfield::dump (FILE *f)
|
||
|
|
void
|
||
|
|
srfield::simple_dump (FILE *f)
|
||
|
|
{
|
||
|
|
- fprintf (f, "field (%d)", DECL_UID (fielddecl));
|
||
|
|
+ if (fielddecl)
|
||
|
|
+ {
|
||
|
|
+ fprintf (f, "field (%d)", DECL_UID (fielddecl));
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Dump out the access structure to FILE. */
|
||
|
|
@@ -857,21 +858,113 @@ srdecl::dump (FILE *file)
|
||
|
|
|
||
|
|
} // namespace struct_reorg
|
||
|
|
|
||
|
|
+namespace struct_relayout {
|
||
|
|
+
|
||
|
|
+/* Complete Structure Relayout Optimization.
|
||
|
|
+ It reorganizes all structure members, and puts same member together.
|
||
|
|
+ struct s {
|
||
|
|
+ long a;
|
||
|
|
+ int b;
|
||
|
|
+ struct s* c;
|
||
|
|
+ };
|
||
|
|
+ Array looks like
|
||
|
|
+ abcabcabcabc...
|
||
|
|
+ will be transformed to
|
||
|
|
+ aaaa...bbbb...cccc...
|
||
|
|
+*/
|
||
|
|
+
|
||
|
|
+#define GPTR_SIZE(i) \
|
||
|
|
+ TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (gptr[i])))
|
||
|
|
+
|
||
|
|
+unsigned transformed = 0;
|
||
|
|
+
|
||
|
|
+unsigned
|
||
|
|
+csrtype::calculate_field_num (tree field_offset)
|
||
|
|
+{
|
||
|
|
+ HOST_WIDE_INT off = int_byte_position (field_offset);
|
||
|
|
+ unsigned i = 1;
|
||
|
|
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
||
|
|
+ {
|
||
|
|
+ if (off == int_byte_position (field))
|
||
|
|
+ {
|
||
|
|
+ return i;
|
||
|
|
+ }
|
||
|
|
+ i++;
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+csrtype::init_type_info (void)
|
||
|
|
+{
|
||
|
|
+ if (!type)
|
||
|
|
+ {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ new_size = old_size = tree_to_uhwi (TYPE_SIZE_UNIT (type));
|
||
|
|
+
|
||
|
|
+ /* Close enough to pad to improve performance. */
|
||
|
|
+ if (old_size > 48 && old_size < 64)
|
||
|
|
+ {
|
||
|
|
+ new_size = 64;
|
||
|
|
+ }
|
||
|
|
+ if (old_size > 96 && old_size < 128)
|
||
|
|
+ {
|
||
|
|
+ new_size = 128;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* For performance reasons, only allow structure size
|
||
|
|
+ that is a power of 2 and not too big. */
|
||
|
|
+ if (new_size != 1 && new_size != 2
|
||
|
|
+ && new_size != 4 && new_size != 8
|
||
|
|
+ && new_size != 16 && new_size != 32
|
||
|
|
+ && new_size != 64 && new_size != 128)
|
||
|
|
+ {
|
||
|
|
+ new_size = 0;
|
||
|
|
+ field_count = 0;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ unsigned i = 0;
|
||
|
|
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
||
|
|
+ {
|
||
|
|
+ i++;
|
||
|
|
+ }
|
||
|
|
+ field_count = i;
|
||
|
|
+
|
||
|
|
+ struct_size = build_int_cstu (TREE_TYPE (TYPE_SIZE_UNIT (type)),
|
||
|
|
+ new_size);
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Type: ");
|
||
|
|
+ print_generic_expr (dump_file, type);
|
||
|
|
+ fprintf (dump_file, " has %d members.\n", field_count);
|
||
|
|
+ fprintf (dump_file, "Modify struct size from %ld to %ld.\n",
|
||
|
|
+ old_size, new_size);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+} // namespace struct_relayout
|
||
|
|
+
|
||
|
|
namespace {
|
||
|
|
|
||
|
|
+/* Structure definition for ipa_struct_reorg and ipa_struct_relayout. */
|
||
|
|
+
|
||
|
|
struct ipa_struct_reorg
|
||
|
|
{
|
||
|
|
+public:
|
||
|
|
// Constructors
|
||
|
|
ipa_struct_reorg(void)
|
||
|
|
: current_function (NULL),
|
||
|
|
- done_recording(false)
|
||
|
|
+ done_recording (false),
|
||
|
|
+ current_mode (NORMAL)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
- // public methods
|
||
|
|
- unsigned execute(void);
|
||
|
|
+ unsigned execute (enum srmode mode);
|
||
|
|
void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL);
|
||
|
|
-private:
|
||
|
|
+
|
||
|
|
// fields
|
||
|
|
auto_vec_del<srtype> types;
|
||
|
|
auto_vec_del<srfunction> functions;
|
||
|
|
@@ -879,8 +972,8 @@ private:
|
||
|
|
srfunction *current_function;
|
||
|
|
|
||
|
|
bool done_recording;
|
||
|
|
+ srmode current_mode;
|
||
|
|
|
||
|
|
- // private methods
|
||
|
|
void dump_types (FILE *f);
|
||
|
|
void dump_types_escaped (FILE *f);
|
||
|
|
void dump_functions (FILE *f);
|
||
|
|
@@ -910,6 +1003,7 @@ private:
|
||
|
|
void maybe_record_allocation_site (cgraph_node *, gimple *);
|
||
|
|
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);
|
||
|
|
|
||
|
|
void mark_decls_in_as_not_needed (tree fn);
|
||
|
|
@@ -925,6 +1019,7 @@ private:
|
||
|
|
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 wholeaccess (tree expr, tree base, tree accesstype, srtype *t);
|
||
|
|
|
||
|
|
+ void check_alloc_num (gimple *stmt, srtype *type);
|
||
|
|
void check_definition (srdecl *decl, vec<srdecl*>&);
|
||
|
|
void check_uses (srdecl *decl, vec<srdecl*>&);
|
||
|
|
void check_use (srdecl *decl, gimple *stmt, vec<srdecl*>&);
|
||
|
|
@@ -937,8 +1032,631 @@ private:
|
||
|
|
|
||
|
|
bool has_rewritten_type (srfunction*);
|
||
|
|
void maybe_mark_or_record_other_side (tree side, tree other, gimple *stmt);
|
||
|
|
+ unsigned execute_struct_relayout (void);
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+struct ipa_struct_relayout
|
||
|
|
+{
|
||
|
|
+public:
|
||
|
|
+ // fields
|
||
|
|
+ tree gptr[max_relayout_split + 1];
|
||
|
|
+ csrtype ctype;
|
||
|
|
+ ipa_struct_reorg* sr;
|
||
|
|
+ cgraph_node* current_node;
|
||
|
|
+
|
||
|
|
+ // Constructors
|
||
|
|
+ ipa_struct_relayout (tree type, ipa_struct_reorg* sr_)
|
||
|
|
+ {
|
||
|
|
+ ctype.type = type;
|
||
|
|
+ sr = sr_;
|
||
|
|
+ current_node = NULL;
|
||
|
|
+ for (int i = 0; i < max_relayout_split + 1; i++)
|
||
|
|
+ {
|
||
|
|
+ gptr[i] = NULL;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Methods
|
||
|
|
+ tree create_new_vars (tree type, const char *name);
|
||
|
|
+ void create_global_ptrs (void);
|
||
|
|
+ unsigned int rewrite (void);
|
||
|
|
+ void rewrite_stmt_in_function (void);
|
||
|
|
+ bool rewrite_debug (gimple *stmt, gimple_stmt_iterator *gsi);
|
||
|
|
+ bool rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi);
|
||
|
|
+ bool handled_allocation_stmt (gcall *stmt);
|
||
|
|
+ void init_global_ptrs (gcall *stmt, gimple_stmt_iterator *gsi);
|
||
|
|
+ bool check_call_uses (gcall *stmt);
|
||
|
|
+ bool rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi);
|
||
|
|
+ tree create_ssa (tree node, gimple_stmt_iterator *gsi);
|
||
|
|
+ bool is_candidate (tree xhs);
|
||
|
|
+ tree rewrite_address (tree xhs, gimple_stmt_iterator *gsi);
|
||
|
|
+ tree rewrite_offset (tree offset, HOST_WIDE_INT num);
|
||
|
|
+ bool rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi);
|
||
|
|
+ bool maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi,
|
||
|
|
+ HOST_WIDE_INT ×);
|
||
|
|
+ unsigned int execute (void);
|
||
|
|
};
|
||
|
|
|
||
|
|
+} // anon namespace
|
||
|
|
+
|
||
|
|
+namespace {
|
||
|
|
+
|
||
|
|
+/* Methods for ipa_struct_relayout. */
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+set_var_attributes (tree var)
|
||
|
|
+{
|
||
|
|
+ if (!var)
|
||
|
|
+ {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ gcc_assert (TREE_CODE (var) == VAR_DECL);
|
||
|
|
+
|
||
|
|
+ DECL_ARTIFICIAL (var) = 1;
|
||
|
|
+ DECL_EXTERNAL (var) = 0;
|
||
|
|
+ TREE_STATIC (var) = 1;
|
||
|
|
+ TREE_PUBLIC (var) = 0;
|
||
|
|
+ TREE_USED (var) = 1;
|
||
|
|
+ DECL_CONTEXT (var) = NULL;
|
||
|
|
+ TREE_THIS_VOLATILE (var) = 0;
|
||
|
|
+ TREE_ADDRESSABLE (var) = 0;
|
||
|
|
+ TREE_READONLY (var) = 0;
|
||
|
|
+ if (is_global_var (var))
|
||
|
|
+ {
|
||
|
|
+ set_decl_tls_model (var, TLS_MODEL_NONE);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+tree
|
||
|
|
+ipa_struct_relayout::create_new_vars (tree type, const char *name)
|
||
|
|
+{
|
||
|
|
+ gcc_assert (type);
|
||
|
|
+ tree new_type = build_pointer_type (type);
|
||
|
|
+
|
||
|
|
+ tree new_name = NULL;
|
||
|
|
+ if (name)
|
||
|
|
+ {
|
||
|
|
+ new_name = get_identifier (name);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ tree new_var = build_decl (UNKNOWN_LOCATION, VAR_DECL, new_name, new_type);
|
||
|
|
+
|
||
|
|
+ /* set new_var's attributes. */
|
||
|
|
+ set_var_attributes (new_var);
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Created new var: ");
|
||
|
|
+ print_generic_expr (dump_file, new_var);
|
||
|
|
+ fprintf (dump_file, "\n");
|
||
|
|
+ }
|
||
|
|
+ return new_var;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+ipa_struct_relayout::create_global_ptrs (void)
|
||
|
|
+{
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Create global gptrs: {\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ const char *type_name = get_type_name (ctype.type);
|
||
|
|
+ char *gptr0_name = concat (type_name, "_gptr0", NULL);
|
||
|
|
+ tree var_gptr0 = create_new_vars (ctype.type, gptr0_name);
|
||
|
|
+ gptr[0] = var_gptr0;
|
||
|
|
+ varpool_node::add (var_gptr0);
|
||
|
|
+
|
||
|
|
+ unsigned i = 1;
|
||
|
|
+ for (tree field = TYPE_FIELDS (ctype.type); field;
|
||
|
|
+ field = DECL_CHAIN (field))
|
||
|
|
+ {
|
||
|
|
+ if (TREE_CODE (field) == FIELD_DECL)
|
||
|
|
+ {
|
||
|
|
+ tree type = TREE_TYPE (field);
|
||
|
|
+
|
||
|
|
+ char *name = NULL;
|
||
|
|
+ char id[10] = {0};
|
||
|
|
+ sprintf (id, "%d", i);
|
||
|
|
+ const char *decl_name = IDENTIFIER_POINTER (DECL_NAME (field));
|
||
|
|
+
|
||
|
|
+ name = concat (type_name, "_", decl_name, "_gptr", id, NULL);
|
||
|
|
+
|
||
|
|
+ tree var = create_new_vars (type, name);
|
||
|
|
+
|
||
|
|
+ gptr[i] = var;
|
||
|
|
+ varpool_node::add (var);
|
||
|
|
+ i++;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "\nTotally create %d gptrs. }\n\n", i);
|
||
|
|
+ }
|
||
|
|
+ gcc_assert (ctype.field_count == i - 1);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+ipa_struct_relayout::rewrite_stmt_in_function (void)
|
||
|
|
+{
|
||
|
|
+ gcc_assert (cfun);
|
||
|
|
+
|
||
|
|
+ basic_block bb = NULL;
|
||
|
|
+ gimple_stmt_iterator si;
|
||
|
|
+ FOR_EACH_BB_FN (bb, cfun)
|
||
|
|
+ {
|
||
|
|
+ for (si = gsi_start_bb (bb); !gsi_end_p (si);)
|
||
|
|
+ {
|
||
|
|
+ gimple *stmt = gsi_stmt (si);
|
||
|
|
+ if (rewrite_stmt (stmt, &si))
|
||
|
|
+ {
|
||
|
|
+ gsi_remove (&si, true);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ gsi_next (&si);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Debug statements need to happen after all other statements
|
||
|
|
+ have changed. */
|
||
|
|
+ FOR_EACH_BB_FN (bb, cfun)
|
||
|
|
+ {
|
||
|
|
+ for (si = gsi_start_bb (bb); !gsi_end_p (si);)
|
||
|
|
+ {
|
||
|
|
+ gimple *stmt = gsi_stmt (si);
|
||
|
|
+ if (gimple_code (stmt) == GIMPLE_DEBUG
|
||
|
|
+ && rewrite_debug (stmt, &si))
|
||
|
|
+ {
|
||
|
|
+ gsi_remove (&si, true);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ gsi_next (&si);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+unsigned int
|
||
|
|
+ipa_struct_relayout::rewrite (void)
|
||
|
|
+{
|
||
|
|
+ cgraph_node *cnode = NULL;
|
||
|
|
+ function *fn = NULL;
|
||
|
|
+ FOR_EACH_FUNCTION (cnode)
|
||
|
|
+ {
|
||
|
|
+ if (!cnode->real_symbol_p () || !cnode->has_gimple_body_p ())
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (cnode->definition)
|
||
|
|
+ {
|
||
|
|
+ fn = DECL_STRUCT_FUNCTION (cnode->decl);
|
||
|
|
+ current_node = cnode;
|
||
|
|
+ push_cfun (fn);
|
||
|
|
+
|
||
|
|
+ rewrite_stmt_in_function ();
|
||
|
|
+
|
||
|
|
+ update_ssa (TODO_update_ssa_only_virtuals);
|
||
|
|
+
|
||
|
|
+ if (flag_tree_pta)
|
||
|
|
+ {
|
||
|
|
+ compute_may_aliases ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ remove_unused_locals ();
|
||
|
|
+
|
||
|
|
+ cgraph_edge::rebuild_edges ();
|
||
|
|
+
|
||
|
|
+ free_dominance_info (CDI_DOMINATORS);
|
||
|
|
+
|
||
|
|
+ pop_cfun ();
|
||
|
|
+ current_node = NULL;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return TODO_verify_all;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::rewrite_debug (gimple *stmt, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ /* TODO: For future implement. */
|
||
|
|
+ return true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::rewrite_stmt (gimple *stmt, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ switch (gimple_code (stmt))
|
||
|
|
+ {
|
||
|
|
+ case GIMPLE_ASSIGN:
|
||
|
|
+ return rewrite_assign (as_a <gassign *> (stmt), gsi);
|
||
|
|
+ case GIMPLE_CALL:
|
||
|
|
+ return rewrite_call (as_a <gcall *> (stmt), gsi);
|
||
|
|
+ default:
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::handled_allocation_stmt (gcall *stmt)
|
||
|
|
+{
|
||
|
|
+ if (gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
|
||
|
|
+ {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+ipa_struct_relayout::init_global_ptrs (gcall *stmt, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ gcc_assert (handled_allocation_stmt (stmt));
|
||
|
|
+
|
||
|
|
+ tree lhs = gimple_call_lhs (stmt);
|
||
|
|
+
|
||
|
|
+ /* Case that gimple is at the end of bb. */
|
||
|
|
+ if (gsi_one_before_end_p (*gsi))
|
||
|
|
+ {
|
||
|
|
+ gassign* gptr0 = gimple_build_assign (gptr[0], lhs);
|
||
|
|
+ gsi_insert_after (gsi, gptr0, GSI_SAME_STMT);
|
||
|
|
+ }
|
||
|
|
+ gsi_next (gsi);
|
||
|
|
+
|
||
|
|
+ /* Emit gimple gptr0 = _X and gptr1 = _X. */
|
||
|
|
+ gassign* gptr0 = gimple_build_assign (gptr[0], lhs);
|
||
|
|
+ gsi_insert_before (gsi, gptr0, GSI_SAME_STMT);
|
||
|
|
+ gassign* gptr1 = gimple_build_assign (gptr[1], lhs);
|
||
|
|
+ gsi_insert_before (gsi, gptr1, GSI_SAME_STMT);
|
||
|
|
+
|
||
|
|
+ /* Emit gimple gptr_[i] = gptr_[i-1] + _Y[gap]. */
|
||
|
|
+ for (unsigned i = 2; i <= ctype.field_count; i++)
|
||
|
|
+ {
|
||
|
|
+ gimple *new_stmt = NULL;
|
||
|
|
+ tree gptr_i_prev_ssa = create_ssa (gptr[i-1], gsi);
|
||
|
|
+ tree gptr_i_ssa = make_ssa_name (TREE_TYPE (gptr[i-1]));
|
||
|
|
+
|
||
|
|
+ /* Emit gimple _Y[gap] = N * sizeof (member). */
|
||
|
|
+ tree member_gap = gimplify_build2 (gsi, MULT_EXPR,
|
||
|
|
+ long_unsigned_type_node,
|
||
|
|
+ gimple_call_arg (stmt, 0),
|
||
|
|
+ GPTR_SIZE (i-1));
|
||
|
|
+
|
||
|
|
+ new_stmt = gimple_build_assign (gptr_i_ssa, POINTER_PLUS_EXPR,
|
||
|
|
+ gptr_i_prev_ssa, member_gap);
|
||
|
|
+ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
|
||
|
|
+
|
||
|
|
+ gassign *gptr_i = gimple_build_assign (gptr[i], gptr_i_ssa);
|
||
|
|
+ gsi_insert_before (gsi, gptr_i, GSI_SAME_STMT);
|
||
|
|
+ }
|
||
|
|
+ gsi_prev (gsi);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::check_call_uses (gcall *stmt)
|
||
|
|
+{
|
||
|
|
+ gcc_assert (current_node);
|
||
|
|
+ srfunction *fn = sr->find_function (current_node);
|
||
|
|
+ tree lhs = gimple_call_lhs (stmt);
|
||
|
|
+
|
||
|
|
+ if (fn == NULL)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ srdecl *d = fn->find_decl (lhs);
|
||
|
|
+ if (d == NULL)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ if (types_compatible_p (d->type->type, ctype.type))
|
||
|
|
+ {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::rewrite_call (gcall *stmt, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ if (handled_allocation_stmt (stmt))
|
||
|
|
+ {
|
||
|
|
+ /* Rewrite stmt _X = calloc (N, sizeof (struct)). */
|
||
|
|
+ tree size = gimple_call_arg (stmt, 1);
|
||
|
|
+ if (TREE_CODE (size) != INTEGER_CST)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ if (tree_to_uhwi (size) != ctype.old_size)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ if (!check_call_uses (stmt))
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Rewrite allocation call:\n");
|
||
|
|
+ print_gimple_stmt (dump_file, stmt, 0);
|
||
|
|
+ fprintf (dump_file, "to\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Modify sizeof (struct). */
|
||
|
|
+ gimple_call_set_arg (stmt, 1, ctype.struct_size);
|
||
|
|
+ update_stmt (stmt);
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ print_gimple_stmt (dump_file, stmt, 0);
|
||
|
|
+ fprintf (dump_file, "\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ init_global_ptrs (stmt, gsi);
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+tree
|
||
|
|
+ipa_struct_relayout::create_ssa (tree node, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ tree node_ssa = make_ssa_name (TREE_TYPE (node));
|
||
|
|
+ gassign *stmt = gimple_build_assign (node_ssa, node);
|
||
|
|
+ gsi_insert_before (gsi, stmt, GSI_SAME_STMT);
|
||
|
|
+ return node_ssa;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::is_candidate (tree xhs)
|
||
|
|
+{
|
||
|
|
+ if (TREE_CODE (xhs) != COMPONENT_REF)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ tree mem = TREE_OPERAND (xhs, 0);
|
||
|
|
+ if (TREE_CODE (mem) == MEM_REF)
|
||
|
|
+ {
|
||
|
|
+ tree type = TREE_TYPE (mem);
|
||
|
|
+ if (types_compatible_p (type, ctype.type))
|
||
|
|
+ {
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+tree
|
||
|
|
+ipa_struct_relayout::rewrite_address (tree xhs, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ tree mem_ref = TREE_OPERAND (xhs, 0);
|
||
|
|
+ tree pointer = TREE_OPERAND (mem_ref, 0);
|
||
|
|
+ tree pointer_offset = TREE_OPERAND (mem_ref, 1);
|
||
|
|
+ tree field = TREE_OPERAND (xhs, 1);
|
||
|
|
+
|
||
|
|
+ tree pointer_ssa = fold_convert (long_unsigned_type_node, pointer);
|
||
|
|
+ tree gptr0_ssa = fold_convert (long_unsigned_type_node, gptr[0]);
|
||
|
|
+
|
||
|
|
+ /* Emit gimple _X1 = ptr - gptr0. */
|
||
|
|
+ tree step1 = gimplify_build2 (gsi, MINUS_EXPR, long_unsigned_type_node,
|
||
|
|
+ pointer_ssa, gptr0_ssa);
|
||
|
|
+
|
||
|
|
+ /* Emit gimple _X2 = _X1 / sizeof (struct). */
|
||
|
|
+ tree step2 = gimplify_build2 (gsi, TRUNC_DIV_EXPR, long_unsigned_type_node,
|
||
|
|
+ step1, ctype.struct_size);
|
||
|
|
+
|
||
|
|
+ unsigned field_num = ctype.calculate_field_num (field);
|
||
|
|
+ gcc_assert (field_num > 0 && field_num <= ctype.field_count);
|
||
|
|
+
|
||
|
|
+ /* Emit gimple _X3 = _X2 * sizeof (member). */
|
||
|
|
+ tree step3 = gimplify_build2 (gsi, MULT_EXPR, long_unsigned_type_node,
|
||
|
|
+ step2, GPTR_SIZE (field_num));
|
||
|
|
+
|
||
|
|
+ /* Emit gimple _X4 = gptr[I]. */
|
||
|
|
+ tree gptr_field_ssa = create_ssa (gptr[field_num], gsi);
|
||
|
|
+ tree new_address = make_ssa_name (TREE_TYPE (gptr[field_num]));
|
||
|
|
+ gassign *new_stmt = gimple_build_assign (new_address, POINTER_PLUS_EXPR,
|
||
|
|
+ gptr_field_ssa, step3);
|
||
|
|
+ gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
|
||
|
|
+
|
||
|
|
+ /* MEM_REF with nonzero offset like
|
||
|
|
+ MEM[ptr + sizeof (struct)] = 0B
|
||
|
|
+ should be transformed to
|
||
|
|
+ MEM[gptr + sizeof (member)] = 0B
|
||
|
|
+ */
|
||
|
|
+ HOST_WIDE_INT size
|
||
|
|
+ = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (new_address))));
|
||
|
|
+ tree new_size = rewrite_offset (pointer_offset, size);
|
||
|
|
+ if (new_size)
|
||
|
|
+ {
|
||
|
|
+ TREE_OPERAND (mem_ref, 1) = new_size;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Update mem_ref pointer. */
|
||
|
|
+ TREE_OPERAND (mem_ref, 0) = new_address;
|
||
|
|
+
|
||
|
|
+ /* Update mem_ref TREE_TYPE. */
|
||
|
|
+ TREE_TYPE (mem_ref) = TREE_TYPE (TREE_TYPE (new_address));
|
||
|
|
+
|
||
|
|
+ return mem_ref;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+tree
|
||
|
|
+ipa_struct_relayout::rewrite_offset (tree offset, HOST_WIDE_INT num)
|
||
|
|
+{
|
||
|
|
+ if (TREE_CODE (offset) == INTEGER_CST)
|
||
|
|
+ {
|
||
|
|
+ bool sign = false;
|
||
|
|
+ HOST_WIDE_INT off = TREE_INT_CST_LOW (offset);
|
||
|
|
+ if (off == 0)
|
||
|
|
+ {
|
||
|
|
+ return NULL;
|
||
|
|
+ }
|
||
|
|
+ if (off < 0)
|
||
|
|
+ {
|
||
|
|
+ off = -off;
|
||
|
|
+ sign = true;
|
||
|
|
+ }
|
||
|
|
+ if (off % ctype.old_size == 0)
|
||
|
|
+ {
|
||
|
|
+ HOST_WIDE_INT times = off / ctype.old_size;
|
||
|
|
+ times = sign ? -times : times;
|
||
|
|
+ return build_int_cst (TREE_TYPE (offset), num * times);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return NULL;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+#define REWRITE_ASSIGN_TREE_IN_STMT(node) \
|
||
|
|
+do \
|
||
|
|
+{ \
|
||
|
|
+ tree node = gimple_assign_##node (stmt); \
|
||
|
|
+ if (node && is_candidate (node)) \
|
||
|
|
+ { \
|
||
|
|
+ tree mem_ref = rewrite_address (node, gsi); \
|
||
|
|
+ gimple_assign_set_##node (stmt, mem_ref); \
|
||
|
|
+ update_stmt (stmt); \
|
||
|
|
+ } \
|
||
|
|
+} while (0)
|
||
|
|
+
|
||
|
|
+/* COMPONENT_REF = exp => MEM_REF = exp
|
||
|
|
+ / \ / \
|
||
|
|
+ MEM_REF field gptr offset
|
||
|
|
+ / \
|
||
|
|
+ pointer offset
|
||
|
|
+*/
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::rewrite_assign (gassign *stmt, gimple_stmt_iterator *gsi)
|
||
|
|
+{
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Maybe rewrite assign:\n");
|
||
|
|
+ print_gimple_stmt (dump_file, stmt, 0);
|
||
|
|
+ fprintf (dump_file, "to\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ switch (gimple_num_ops (stmt))
|
||
|
|
+ {
|
||
|
|
+ case 4: REWRITE_ASSIGN_TREE_IN_STMT (rhs3); // FALLTHRU
|
||
|
|
+ case 3:
|
||
|
|
+ {
|
||
|
|
+ REWRITE_ASSIGN_TREE_IN_STMT (rhs2);
|
||
|
|
+ tree rhs2 = gimple_assign_rhs2 (stmt);
|
||
|
|
+ if (rhs2 && TREE_CODE (rhs2) == INTEGER_CST)
|
||
|
|
+ {
|
||
|
|
+ /* Handle pointer++ and pointer-- or
|
||
|
|
+ factor is euqal to struct size. */
|
||
|
|
+ HOST_WIDE_INT times = 1;
|
||
|
|
+ if (maybe_rewrite_cst (rhs2, gsi, times))
|
||
|
|
+ {
|
||
|
|
+ tree tmp = build_int_cst (
|
||
|
|
+ TREE_TYPE (TYPE_SIZE_UNIT (ctype.type)),
|
||
|
|
+ ctype.new_size * times);
|
||
|
|
+ gimple_assign_set_rhs2 (stmt, tmp);
|
||
|
|
+ update_stmt (stmt);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ } // FALLTHRU
|
||
|
|
+ case 2: REWRITE_ASSIGN_TREE_IN_STMT (rhs1); // FALLTHRU
|
||
|
|
+ case 1: REWRITE_ASSIGN_TREE_IN_STMT (lhs); // FALLTHRU
|
||
|
|
+ case 0: break;
|
||
|
|
+ default: gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ print_gimple_stmt (dump_file, stmt, 0);
|
||
|
|
+ fprintf (dump_file, "\n");
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+bool
|
||
|
|
+ipa_struct_relayout::maybe_rewrite_cst (tree cst, gimple_stmt_iterator *gsi,
|
||
|
|
+ HOST_WIDE_INT ×)
|
||
|
|
+{
|
||
|
|
+ bool ret = false;
|
||
|
|
+ gcc_assert (TREE_CODE (cst) == INTEGER_CST);
|
||
|
|
+
|
||
|
|
+ gimple *stmt = gsi_stmt (*gsi);
|
||
|
|
+ if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
|
||
|
|
+ {
|
||
|
|
+ tree lhs = gimple_assign_lhs (stmt);
|
||
|
|
+ tree rhs1 = gimple_assign_rhs1 (stmt);
|
||
|
|
+ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
|
||
|
|
+ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type))
|
||
|
|
+ {
|
||
|
|
+ tree num = NULL;
|
||
|
|
+ if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type)))
|
||
|
|
+ {
|
||
|
|
+ times = TREE_INT_CST_LOW (num);
|
||
|
|
+ return true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (gimple_assign_rhs_code (stmt) == MULT_EXPR)
|
||
|
|
+ {
|
||
|
|
+ if (gsi_one_before_end_p (*gsi))
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ gsi_next (gsi);
|
||
|
|
+ gimple *stmt2 = gsi_stmt (*gsi);
|
||
|
|
+
|
||
|
|
+ if (gimple_code (stmt2) == GIMPLE_ASSIGN
|
||
|
|
+ && gimple_assign_rhs_code (stmt2) == POINTER_PLUS_EXPR)
|
||
|
|
+ {
|
||
|
|
+ tree lhs = gimple_assign_lhs (stmt2);
|
||
|
|
+ tree rhs1 = gimple_assign_rhs1 (stmt2);
|
||
|
|
+ if (types_compatible_p (inner_type (TREE_TYPE (rhs1)), ctype.type)
|
||
|
|
+ || types_compatible_p (inner_type (TREE_TYPE (lhs)), ctype.type))
|
||
|
|
+ {
|
||
|
|
+ tree num = NULL;
|
||
|
|
+ if (is_result_of_mult (cst, &num, TYPE_SIZE_UNIT (ctype.type)))
|
||
|
|
+ {
|
||
|
|
+ times = TREE_INT_CST_LOW (num);
|
||
|
|
+ ret = true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ gsi_prev (gsi);
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
+ return false;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+unsigned int
|
||
|
|
+ipa_struct_relayout::execute (void)
|
||
|
|
+{
|
||
|
|
+ ctype.init_type_info ();
|
||
|
|
+ if (ctype.field_count < min_relayout_split
|
||
|
|
+ || ctype.field_count > max_relayout_split)
|
||
|
|
+ {
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "Complete Struct Relayout Type: ");
|
||
|
|
+ print_generic_expr (dump_file, ctype.type);
|
||
|
|
+ fprintf (dump_file, "\n");
|
||
|
|
+ }
|
||
|
|
+ transformed++;
|
||
|
|
+
|
||
|
|
+ create_global_ptrs ();
|
||
|
|
+ return rewrite ();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+} // anon namespace
|
||
|
|
+
|
||
|
|
+namespace {
|
||
|
|
+
|
||
|
|
+/* Methods for ipa_struct_reorg. */
|
||
|
|
+
|
||
|
|
/* Dump all of the recorded types to file F. */
|
||
|
|
|
||
|
|
void
|
||
|
|
@@ -1134,8 +1852,10 @@ ipa_struct_reorg::record_type (tree type
|
||
|
|
f->type = t1;
|
||
|
|
t1->add_field_site (f);
|
||
|
|
}
|
||
|
|
- if (t1 == type1)
|
||
|
|
- type1->mark_escape (escape_rescusive_type, NULL);
|
||
|
|
+ if (t1 == type1 && current_mode != COMPLETE_STRUCT_RELAYOUT)
|
||
|
|
+ {
|
||
|
|
+ type1->mark_escape (escape_rescusive_type, NULL);
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@@ -1272,6 +1992,14 @@ ipa_struct_reorg::record_var (tree decl,
|
||
|
|
else
|
||
|
|
e = escape_type_volatile_array_or_ptrptr (TREE_TYPE (decl));
|
||
|
|
|
||
|
|
+ /* Separate instance is hard to trace in complete struct
|
||
|
|
+ relayout optimization. */
|
||
|
|
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT
|
||
|
|
+ && TREE_CODE (TREE_TYPE (decl)) == RECORD_TYPE)
|
||
|
|
+ {
|
||
|
|
+ e = escape_separate_instance;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
if (e != does_not_escape)
|
||
|
|
type->mark_escape (e, NULL);
|
||
|
|
}
|
||
|
|
@@ -1347,7 +2075,8 @@ ipa_struct_reorg::find_vars (gimple *stm
|
||
|
|
{
|
||
|
|
case GIMPLE_ASSIGN:
|
||
|
|
if (gimple_assign_rhs_class (stmt) == GIMPLE_SINGLE_RHS
|
||
|
|
- || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
|
||
|
|
+ || gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR
|
||
|
|
+ || gimple_assign_rhs_code (stmt) == NOP_EXPR)
|
||
|
|
{
|
||
|
|
tree lhs = gimple_assign_lhs (stmt);
|
||
|
|
tree rhs = gimple_assign_rhs1 (stmt);
|
||
|
|
@@ -1372,6 +2101,32 @@ ipa_struct_reorg::find_vars (gimple *stm
|
||
|
|
current_function->record_decl (t, rhs, -1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ /* Because we won't handle these stmts in rewrite phase,
|
||
|
|
+ just mark these types as escaped. */
|
||
|
|
+ switch (gimple_num_ops (stmt))
|
||
|
|
+ {
|
||
|
|
+ case 4: mark_type_as_escape (
|
||
|
|
+ TREE_TYPE (gimple_assign_rhs3 (stmt)),
|
||
|
|
+ escape_unhandled_rewrite, stmt);
|
||
|
|
+ // FALLTHRU
|
||
|
|
+ case 3: mark_type_as_escape (
|
||
|
|
+ TREE_TYPE (gimple_assign_rhs2 (stmt)),
|
||
|
|
+ escape_unhandled_rewrite, stmt);
|
||
|
|
+ // FALLTHRU
|
||
|
|
+ case 2: mark_type_as_escape (
|
||
|
|
+ TREE_TYPE (gimple_assign_rhs1 (stmt)),
|
||
|
|
+ escape_unhandled_rewrite, stmt);
|
||
|
|
+ // FALLTHRU
|
||
|
|
+ case 1: mark_type_as_escape (
|
||
|
|
+ TREE_TYPE (gimple_assign_lhs (stmt)),
|
||
|
|
+ escape_unhandled_rewrite, stmt);
|
||
|
|
+ // FALLTHRU
|
||
|
|
+ case 0: break;
|
||
|
|
+ default: gcc_unreachable ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
break;
|
||
|
|
|
||
|
|
case GIMPLE_CALL:
|
||
|
|
@@ -1453,9 +2208,23 @@ is_result_of_mult (tree arg, tree *num,
|
||
|
|
/* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */
|
||
|
|
if (TREE_CODE (arg) == INTEGER_CST)
|
||
|
|
{
|
||
|
|
- if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg, struct_size)))
|
||
|
|
+ bool sign = false;
|
||
|
|
+ HOST_WIDE_INT size = TREE_INT_CST_LOW (arg);
|
||
|
|
+ if (size < 0)
|
||
|
|
{
|
||
|
|
- *num = size_binop (FLOOR_DIV_EXPR, arg, struct_size);
|
||
|
|
+ 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;
|
||
|
|
@@ -1525,15 +2294,19 @@ is_result_of_mult (tree arg, tree *num,
|
||
|
|
|
||
|
|
/* Return TRUE if STMT is an allocation statement that is handled. */
|
||
|
|
|
||
|
|
-static bool
|
||
|
|
-handled_allocation_stmt (gimple *stmt)
|
||
|
|
+bool
|
||
|
|
+ipa_struct_reorg::handled_allocation_stmt (gimple *stmt)
|
||
|
|
{
|
||
|
|
- if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
|
||
|
|
- || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
|
||
|
|
- || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)
|
||
|
|
- || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC)
|
||
|
|
- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)
|
||
|
|
- || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
|
||
|
|
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT
|
||
|
|
+ && gimple_call_builtin_p (stmt, BUILT_IN_CALLOC))
|
||
|
|
+ return true;
|
||
|
|
+ if (current_mode != COMPLETE_STRUCT_RELAYOUT
|
||
|
|
+ && (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
|
||
|
|
+ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
|
||
|
|
+ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)
|
||
|
|
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC)
|
||
|
|
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)
|
||
|
|
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)))
|
||
|
|
return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
@@ -1575,7 +2348,8 @@ ipa_struct_reorg::allocate_size (srtype
|
||
|
|
/* Check that second argument is a constant equal to the size of structure. */
|
||
|
|
if (operand_equal_p (arg1, struct_size, 0))
|
||
|
|
return size;
|
||
|
|
- /* Check that first argument is a constant equal to the size of structure. */
|
||
|
|
+ /* ??? Check that first argument is a constant
|
||
|
|
+ equal to the size of structure. */
|
||
|
|
if (operand_equal_p (size, struct_size, 0))
|
||
|
|
return arg1;
|
||
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
@@ -1692,6 +2466,29 @@ ipa_struct_reorg::maybe_record_assign (c
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+bool
|
||
|
|
+check_mem_ref_offset (tree expr)
|
||
|
|
+{
|
||
|
|
+ tree num = NULL;
|
||
|
|
+ bool ret = false;
|
||
|
|
+
|
||
|
|
+ if (TREE_CODE (expr) != MEM_REF)
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* Try to find the structure size. */
|
||
|
|
+ tree field_off = TREE_OPERAND (expr, 1);
|
||
|
|
+ tree tmp = TREE_OPERAND (expr, 0);
|
||
|
|
+ if (TREE_CODE (tmp) == ADDR_EXPR)
|
||
|
|
+ {
|
||
|
|
+ tmp = TREE_OPERAND (tmp, 0);
|
||
|
|
+ }
|
||
|
|
+ tree size = TYPE_SIZE_UNIT (inner_type (TREE_TYPE (tmp)));
|
||
|
|
+ ret = is_result_of_mult (field_off, &num, size);
|
||
|
|
+ return ret;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
tree
|
||
|
|
get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset, bool &realpart, bool &imagpart, tree &accesstype)
|
||
|
|
{
|
||
|
|
@@ -1731,7 +2528,10 @@ get_ref_base_and_offset (tree &e, HOST_W
|
||
|
|
gcc_assert (TREE_CODE (field_off) == INTEGER_CST);
|
||
|
|
/* So we can mark the types as escaping if different. */
|
||
|
|
accesstype = TREE_TYPE (field_off);
|
||
|
|
- offset += tree_to_uhwi (field_off);
|
||
|
|
+ if (!check_mem_ref_offset (expr))
|
||
|
|
+ {
|
||
|
|
+ offset += tree_to_uhwi (field_off);
|
||
|
|
+ }
|
||
|
|
return TREE_OPERAND (expr, 0);
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
@@ -2108,6 +2908,39 @@ ipa_struct_reorg::check_type_and_push (t
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
+void
|
||
|
|
+ipa_struct_reorg::check_alloc_num (gimple *stmt, srtype *type)
|
||
|
|
+{
|
||
|
|
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT
|
||
|
|
+ && handled_allocation_stmt (stmt))
|
||
|
|
+ {
|
||
|
|
+ tree arg0 = gimple_call_arg (stmt, 0);
|
||
|
|
+ basic_block bb = gimple_bb (stmt);
|
||
|
|
+ cgraph_node *node = current_function->node;
|
||
|
|
+ if (integer_onep (arg0))
|
||
|
|
+ {
|
||
|
|
+ /* Actually NOT an array, but may ruin other array. */
|
||
|
|
+ type->has_alloc_array = -1;
|
||
|
|
+ }
|
||
|
|
+ else if (bb->loop_father != NULL
|
||
|
|
+ && loop_outer (bb->loop_father) != NULL)
|
||
|
|
+ {
|
||
|
|
+ /* The allocation is in a loop. */
|
||
|
|
+ type->has_alloc_array = -2;
|
||
|
|
+ }
|
||
|
|
+ else if (node->callers != NULL)
|
||
|
|
+ {
|
||
|
|
+ type->has_alloc_array = -3;
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ type->has_alloc_array = type->has_alloc_array < 0
|
||
|
|
+ ? type->has_alloc_array
|
||
|
|
+ : type->has_alloc_array + 1;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/*
|
||
|
|
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
|
||
|
|
@@ -2151,6 +2984,7 @@ ipa_struct_reorg::check_definition (srde
|
||
|
|
if (!handled_allocation_stmt (stmt)
|
||
|
|
|| !allocate_size (type, stmt))
|
||
|
|
type->mark_escape (escape_return, stmt);
|
||
|
|
+ check_alloc_num (stmt, type);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
/* If the SSA_NAME is sourced from an inline-asm, just mark the type as escaping. */
|
||
|
|
@@ -2189,6 +3023,21 @@ ipa_struct_reorg::check_definition (srde
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
+ if (gimple_assign_rhs_code (stmt) == MAX_EXPR
|
||
|
|
+ || gimple_assign_rhs_code (stmt) == MIN_EXPR)
|
||
|
|
+ {
|
||
|
|
+ tree rhs2 = gimple_assign_rhs2 (stmt);
|
||
|
|
+ if (TREE_CODE (rhs) == SSA_NAME)
|
||
|
|
+ {
|
||
|
|
+ check_type_and_push (rhs, type, worklist, stmt);
|
||
|
|
+ }
|
||
|
|
+ if (TREE_CODE (rhs2) == SSA_NAME)
|
||
|
|
+ {
|
||
|
|
+ check_type_and_push (rhs2, type, worklist, stmt);
|
||
|
|
+ }
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
/* Casts between pointers and integer are escaping. */
|
||
|
|
if (gimple_assign_cast_p (stmt))
|
||
|
|
{
|
||
|
|
@@ -2251,6 +3100,13 @@ ipa_struct_reorg::check_other_side (srde
|
||
|
|
srtype *t1 = find_type (inner_type (t));
|
||
|
|
if (t1 == type)
|
||
|
|
{
|
||
|
|
+ /* In Complete Struct Relayout opti, if lhs type is the same
|
||
|
|
+ as rhs type, we could return without any harm. */
|
||
|
|
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT)
|
||
|
|
+ {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
tree base;
|
||
|
|
bool indirect;
|
||
|
|
srtype *type1;
|
||
|
|
@@ -2298,8 +3154,11 @@ ipa_struct_reorg::check_use (srdecl *dec
|
||
|
|
tree rhs1 = gimple_cond_lhs (stmt);
|
||
|
|
tree rhs2 = gimple_cond_rhs (stmt);
|
||
|
|
tree orhs = rhs1;
|
||
|
|
- if (gimple_cond_code (stmt) != EQ_EXPR
|
||
|
|
- && gimple_cond_code (stmt) != NE_EXPR)
|
||
|
|
+ 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)))
|
||
|
|
{
|
||
|
|
mark_expr_escape (rhs1, escape_non_eq, stmt);
|
||
|
|
mark_expr_escape (rhs2, escape_non_eq, stmt);
|
||
|
|
@@ -2329,8 +3188,11 @@ ipa_struct_reorg::check_use (srdecl *dec
|
||
|
|
tree rhs1 = gimple_assign_rhs1 (stmt);
|
||
|
|
tree rhs2 = gimple_assign_rhs2 (stmt);
|
||
|
|
tree orhs = rhs1;
|
||
|
|
- if (gimple_assign_rhs_code (stmt) != EQ_EXPR
|
||
|
|
- && gimple_assign_rhs_code (stmt) != NE_EXPR)
|
||
|
|
+ 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
|
||
|
|
+ && code != GT_EXPR && code != GE_EXPR)))
|
||
|
|
{
|
||
|
|
mark_expr_escape (rhs1, escape_non_eq, stmt);
|
||
|
|
mark_expr_escape (rhs2, escape_non_eq, stmt);
|
||
|
|
@@ -2727,8 +3589,11 @@ ipa_struct_reorg::propagate_escape (void
|
||
|
|
void
|
||
|
|
ipa_struct_reorg::prune_escaped_types (void)
|
||
|
|
{
|
||
|
|
- detect_cycles ();
|
||
|
|
- propagate_escape ();
|
||
|
|
+ if (current_mode != COMPLETE_STRUCT_RELAYOUT)
|
||
|
|
+ {
|
||
|
|
+ detect_cycles ();
|
||
|
|
+ propagate_escape ();
|
||
|
|
+ }
|
||
|
|
|
||
|
|
if (dump_file && (dump_flags & TDF_DETAILS))
|
||
|
|
{
|
||
|
|
@@ -3850,16 +4715,82 @@ ipa_struct_reorg::rewrite_functions (voi
|
||
|
|
}
|
||
|
|
|
||
|
|
unsigned int
|
||
|
|
-ipa_struct_reorg::execute (void)
|
||
|
|
+ipa_struct_reorg::execute_struct_relayout (void)
|
||
|
|
{
|
||
|
|
- /* FIXME: If there is a top-level inline-asm, the pass immediately returns. */
|
||
|
|
- if (symtab->first_asm_symbol ())
|
||
|
|
- return 0;
|
||
|
|
- record_accesses ();
|
||
|
|
- prune_escaped_types ();
|
||
|
|
- analyze_types ();
|
||
|
|
+ unsigned retval = 0;
|
||
|
|
+ for (unsigned i = 0; i < types.length (); i++)
|
||
|
|
+ {
|
||
|
|
+ tree type = types[i]->type;
|
||
|
|
+ if (TYPE_FIELDS (type) == NULL)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (types[i]->has_alloc_array != 1)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (types[i]->chain_type)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ retval |= ipa_struct_relayout (type, this).execute ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (dump_file)
|
||
|
|
+ {
|
||
|
|
+ if (transformed)
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "\nNumber of structures to transform in "
|
||
|
|
+ "Complete Structure Relayout is %d\n", transformed);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "\nNo structures to transform in "
|
||
|
|
+ "Complete Structure Relayout.\n");
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
|
||
|
|
- return rewrite_functions ();
|
||
|
|
+ return retval;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+unsigned int
|
||
|
|
+ipa_struct_reorg::execute (enum srmode mode)
|
||
|
|
+{
|
||
|
|
+ unsigned int ret = 0;
|
||
|
|
+
|
||
|
|
+ if (mode == NORMAL)
|
||
|
|
+ {
|
||
|
|
+ current_mode = NORMAL;
|
||
|
|
+ /* FIXME: If there is a top-level inline-asm,
|
||
|
|
+ the pass immediately returns. */
|
||
|
|
+ if (symtab->first_asm_symbol ())
|
||
|
|
+ {
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+ record_accesses ();
|
||
|
|
+ prune_escaped_types ();
|
||
|
|
+ analyze_types ();
|
||
|
|
+
|
||
|
|
+ ret = rewrite_functions ();
|
||
|
|
+ }
|
||
|
|
+ else if (mode == COMPLETE_STRUCT_RELAYOUT)
|
||
|
|
+ {
|
||
|
|
+ if (dump_file)
|
||
|
|
+ {
|
||
|
|
+ fprintf (dump_file, "\n\nTry Complete Struct Relayout:\n");
|
||
|
|
+ }
|
||
|
|
+ current_mode = COMPLETE_STRUCT_RELAYOUT;
|
||
|
|
+ if (symtab->first_asm_symbol ())
|
||
|
|
+ {
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+ record_accesses ();
|
||
|
|
+ prune_escaped_types ();
|
||
|
|
+
|
||
|
|
+ ret = execute_struct_relayout ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
const pass_data pass_data_ipa_struct_reorg =
|
||
|
|
@@ -3884,17 +4815,27 @@ public:
|
||
|
|
|
||
|
|
/* opt_pass methods: */
|
||
|
|
virtual bool gate (function *);
|
||
|
|
- virtual unsigned int execute (function *) { return ipa_struct_reorg ().execute(); }
|
||
|
|
+ virtual unsigned int execute (function *)
|
||
|
|
+ {
|
||
|
|
+ unsigned int ret = 0;
|
||
|
|
+ ret = ipa_struct_reorg ().execute (NORMAL);
|
||
|
|
+ if (!ret)
|
||
|
|
+ {
|
||
|
|
+ ret = ipa_struct_reorg ().execute (COMPLETE_STRUCT_RELAYOUT);
|
||
|
|
+ }
|
||
|
|
+ return ret;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
}; // class pass_ipa_struct_reorg
|
||
|
|
|
||
|
|
bool
|
||
|
|
pass_ipa_struct_reorg::gate (function *)
|
||
|
|
{
|
||
|
|
- return (optimize
|
||
|
|
+ return (optimize >= 3
|
||
|
|
&& flag_ipa_struct_reorg
|
||
|
|
/* Don't bother doing anything if the program has errors. */
|
||
|
|
- && !seen_error ());
|
||
|
|
+ && !seen_error ()
|
||
|
|
+ && flag_lto_partition == LTO_PARTITION_ONE);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // anon namespace
|
||
|
|
diff -Nurp a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
|
||
|
|
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h 2020-07-18 05:11:11.548000000 -0400
|
||
|
|
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -121,6 +121,7 @@ public:
|
||
|
|
|
||
|
|
tree newtype[max_split];
|
||
|
|
bool visited;
|
||
|
|
+ int has_alloc_array;
|
||
|
|
|
||
|
|
// Constructors
|
||
|
|
srtype(tree type);
|
||
|
|
@@ -232,4 +233,34 @@ struct srdecl
|
||
|
|
|
||
|
|
} // namespace struct_reorg
|
||
|
|
|
||
|
|
+
|
||
|
|
+namespace struct_relayout {
|
||
|
|
+
|
||
|
|
+const int min_relayout_split = 8;
|
||
|
|
+const int max_relayout_split = 16;
|
||
|
|
+
|
||
|
|
+struct csrtype
|
||
|
|
+{
|
||
|
|
+ tree type;
|
||
|
|
+ unsigned HOST_WIDE_INT old_size;
|
||
|
|
+ unsigned HOST_WIDE_INT new_size;
|
||
|
|
+ unsigned field_count;
|
||
|
|
+ tree struct_size;
|
||
|
|
+
|
||
|
|
+ // Constructors
|
||
|
|
+ csrtype ()
|
||
|
|
+ : type (NULL),
|
||
|
|
+ old_size (0),
|
||
|
|
+ new_size (0),
|
||
|
|
+ field_count (0),
|
||
|
|
+ struct_size (NULL)
|
||
|
|
+ {}
|
||
|
|
+
|
||
|
|
+ // Methods
|
||
|
|
+ unsigned calculate_field_num (tree field_offset);
|
||
|
|
+ void init_type_info (void);
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+} // namespace struct_relayout
|
||
|
|
+
|
||
|
|
#endif
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c b/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/complete_struct_relayout.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,60 @@
|
||
|
|
+// { dg-do run }
|
||
|
|
+
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 10000;
|
||
|
|
+node_p n;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ n = (node_p) calloc (MAX, sizeof (node_t));
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].a = 100;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].a != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].l = n[i].a;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].l != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "Number of structures to transform in Complete Structure Relayout is 1" "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,46 @@
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 1;
|
||
|
|
+node_p n;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ n = (node_p) calloc (MAX, sizeof (node_t));
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].a = 100;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].a != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,59 @@
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 10;
|
||
|
|
+node_p n;
|
||
|
|
+node_p m;
|
||
|
|
+
|
||
|
|
+int main()
|
||
|
|
+{
|
||
|
|
+ int i;
|
||
|
|
+ for (i = 0; i < MAX / 5; i++)
|
||
|
|
+ {
|
||
|
|
+ n = (node_p) calloc(MAX, sizeof(node_t));
|
||
|
|
+ if (i == 0)
|
||
|
|
+ {
|
||
|
|
+ m = n;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].a = 100;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ m[i].a = 50;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].a != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,77 @@
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 10;
|
||
|
|
+node_p n;
|
||
|
|
+node_p m;
|
||
|
|
+
|
||
|
|
+void test (int, int) __attribute__((noinline));
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+test (int num, int flag)
|
||
|
|
+{
|
||
|
|
+ if (num <= 0)
|
||
|
|
+ {
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ n = (node_p) calloc (num, sizeof (node_t));
|
||
|
|
+ if (flag)
|
||
|
|
+ {
|
||
|
|
+ m = n;
|
||
|
|
+ }
|
||
|
|
+ return;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ test (MAX, 1);
|
||
|
|
+ test (MAX, 0);
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].a = 100;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ m[i].a = 50;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].a != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (m[i].a != 50)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform in Complete Structure Relayout." "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/csr_cast_int.c b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/csr_cast_int.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,52 @@
|
||
|
|
+// { dg-do run }
|
||
|
|
+
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 100;
|
||
|
|
+node_p n;
|
||
|
|
+unsigned long y;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ n = (node_p) calloc (MAX, sizeof (node_t));
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].b = 50;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ node_p x = &n[5];
|
||
|
|
+ y = (unsigned long) x;
|
||
|
|
+ y += 8;
|
||
|
|
+
|
||
|
|
+ if (*((unsigned long*) y) != 50)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes a cast from/to intergral type\"" "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,48 @@
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+#include <stdio.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+ node_p c;
|
||
|
|
+ node_p d;
|
||
|
|
+ long e;
|
||
|
|
+ long f;
|
||
|
|
+ long g;
|
||
|
|
+ long h;
|
||
|
|
+ long i;
|
||
|
|
+ long j;
|
||
|
|
+ long k;
|
||
|
|
+ long l;
|
||
|
|
+ int m;
|
||
|
|
+ int n;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+const int MAX = 10000;
|
||
|
|
+node_p n;
|
||
|
|
+node_t t;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ n = (node_p) calloc (MAX, sizeof (node_t));
|
||
|
|
+ t.a = 100;
|
||
|
|
+
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ n[i].a = t.a;
|
||
|
|
+ }
|
||
|
|
+ for (int i = 0; i < MAX; i++)
|
||
|
|
+ {
|
||
|
|
+ if (n[i].a != 100)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes via a separate instance\"" "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,37 @@
|
||
|
|
+/* { dg-do run } */
|
||
|
|
+
|
||
|
|
+static struct S {
|
||
|
|
+ int *p1;
|
||
|
|
+ int *p2;
|
||
|
|
+} s;
|
||
|
|
+
|
||
|
|
+typedef __UINTPTR_TYPE__ uintptr_t;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+foo ()
|
||
|
|
+{
|
||
|
|
+ int i = 1;
|
||
|
|
+ int j = 2;
|
||
|
|
+ struct S s;
|
||
|
|
+ int **p;
|
||
|
|
+ s.p1 = &i;
|
||
|
|
+ s.p2 = &j;
|
||
|
|
+ p = &s.p1;
|
||
|
|
+ uintptr_t pi = (uintptr_t) p;
|
||
|
|
+ pi = pi + sizeof (int *);
|
||
|
|
+ p = (int **)pi;
|
||
|
|
+ **p = 3;
|
||
|
|
+ return j;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ if (foo () != 3)
|
||
|
|
+ {
|
||
|
|
+ __builtin_abort ();
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "struct S has escaped: \"Type escapes via taking the address of field\"" "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,25 @@
|
||
|
|
+// { dg-do compile }
|
||
|
|
+
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+
|
||
|
|
+struct S {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+struct S* s;
|
||
|
|
+struct S* t = (struct S*) 1000;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ s = (struct S*) calloc (1000, sizeof (struct S));
|
||
|
|
+ s = s > t ? s : t;
|
||
|
|
+ if (s == 0)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "No structures to transform." "struct_reorg" } } */
|
||
|
|
diff -Nurp a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c
|
||
|
|
--- a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c 1969-12-31 19:00:00.000000000 -0500
|
||
|
|
+++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c 2020-07-18 05:16:25.928000000 -0400
|
||
|
|
@@ -0,0 +1,33 @@
|
||
|
|
+// { dg-do compile }
|
||
|
|
+
|
||
|
|
+#include <stdlib.h>
|
||
|
|
+
|
||
|
|
+typedef struct node node_t;
|
||
|
|
+typedef struct node* node_p;
|
||
|
|
+
|
||
|
|
+struct node {
|
||
|
|
+ unsigned long a;
|
||
|
|
+ unsigned long b;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+int max;
|
||
|
|
+int x;
|
||
|
|
+
|
||
|
|
+node_p n;
|
||
|
|
+node_p z;
|
||
|
|
+
|
||
|
|
+int
|
||
|
|
+main ()
|
||
|
|
+{
|
||
|
|
+ n = (node_p) calloc (max, sizeof (node_t));
|
||
|
|
+
|
||
|
|
+ node_p xp = &n[x];
|
||
|
|
+
|
||
|
|
+ if (xp - z == 10)
|
||
|
|
+ {
|
||
|
|
+ abort ();
|
||
|
|
+ }
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/* { dg-final { scan-ipa-dump "struct node has escaped: \"Type escapes via a unhandled rewrite stmt\"" "struct_reorg" } } */
|