代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/gcc 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
From 699caeaa2d89966e4af1d36bc96b53eb4dac0a09 Mon Sep 17 00:00:00 2001
From: eastb233 <xiezhiheng@huawei.com>
Date: Fri, 25 Aug 2023 09:59:39 +0800
Subject: [PATCH 16/22] [CompleteStructRelayout] Complete Structure Relayout
Introduce complete structure reorganization based on original
structure reorganization optimization, which change array of
structure to structure of array in order to better utilize
spatial locality.
---
gcc/ipa-struct-reorg/escapes.def | 2 +
gcc/ipa-struct-reorg/ipa-struct-reorg.cc | 994 ++++++++++++++++--
gcc/ipa-struct-reorg/ipa-struct-reorg.h | 33 +
.../g++.dg/struct/no-body-function.cpp | 18 +
.../g++.dg/struct/struct-reorg-1.cpp | 13 +
.../g++.dg/struct/struct-reorg-2.cpp | 17 +
.../g++.dg/struct/struct-reorg-3.cpp | 24 +
gcc/testsuite/g++.dg/struct/struct-reorg.exp | 26 +
gcc/testsuite/gcc.dg/struct/csr_1.c | 60 ++
.../gcc.dg/struct/csr_allocation-1.c | 46 +
.../gcc.dg/struct/csr_allocation-2.c | 59 ++
.../gcc.dg/struct/csr_allocation-3.c | 77 ++
gcc/testsuite/gcc.dg/struct/csr_cast_int.c | 52 +
.../gcc.dg/struct/csr_separate_instance.c | 48 +
.../gcc.dg/struct/sr_address_of_field.c | 37 +
gcc/testsuite/gcc.dg/struct/sr_convert_mem.c | 23 +
gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c | 25 +
gcc/testsuite/gcc.dg/struct/sr_pointer_and.c | 17 +
.../gcc.dg/struct/sr_pointer_minus.c | 33 +
19 files changed, 1539 insertions(+), 65 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/struct/no-body-function.cpp
create mode 100644 gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp
create mode 100644 gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp
create mode 100644 gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp
create mode 100644 gcc/testsuite/g++.dg/struct/struct-reorg.exp
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_1.c
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_allocation-1.c
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_allocation-2.c
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_allocation-3.c
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_cast_int.c
create mode 100644 gcc/testsuite/gcc.dg/struct/csr_separate_instance.c
create mode 100644 gcc/testsuite/gcc.dg/struct/sr_address_of_field.c
create mode 100644 gcc/testsuite/gcc.dg/struct/sr_convert_mem.c
create mode 100644 gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c
create mode 100644 gcc/testsuite/gcc.dg/struct/sr_pointer_and.c
create mode 100644 gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c
diff --git a/gcc/ipa-struct-reorg/escapes.def b/gcc/ipa-struct-reorg/escapes.def
index c4c8e0739..d825eb3e6 100644
--- a/gcc/ipa-struct-reorg/escapes.def
+++ b/gcc/ipa-struct-reorg/escapes.def
@@ -56,5 +56,7 @@ DEF_ESCAPE (escape_non_optimize, "Type used by a function which turns off struct
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 --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
index 238530860..c8b975a92 100644
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.cc
@@ -104,10 +104,12 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-live.h" /* For remove_unused_locals. */
#include "ipa-param-manipulation.h"
#include "gimplify-me.h"
+#include "cfgloop.h"
namespace {
using namespace struct_reorg;
+using namespace struct_relayout;
#define VOID_POINTER_P(type) \
(POINTER_TYPE_P (type) && VOID_TYPE_P (TREE_TYPE (type)))
@@ -194,6 +196,14 @@ gimplify_build1 (gimple_stmt_iterator *gsi, enum tree_code code, tree type,
GSI_SAME_STMT);
}
+enum srmode
+{
+ NORMAL = 0,
+ COMPLETE_STRUCT_RELAYOUT
+};
+
+static bool is_result_of_mult (tree, tree *, tree);
+
} // anon namespace
@@ -283,7 +293,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;
@@ -483,13 +494,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");
}
@@ -631,15 +635,7 @@ srtype::create_new_type (void)
maxclusters++;
- const char *tname = NULL;
-
- if (TYPE_NAME (type) != NULL)
- {
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- tname = IDENTIFIER_POINTER (TYPE_NAME (type));
- else if (DECL_NAME (TYPE_NAME (type)) != NULL)
- tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- }
+ const char *tname = get_type_name (type);
for (unsigned i = 0; i < maxclusters; i++)
{
@@ -653,7 +649,10 @@ srtype::create_new_type (void)
if (tname)
{
name = concat (tname, ".reorg.", id, NULL);
- TYPE_NAME (newtype[i]) = get_identifier (name);
+ TYPE_NAME (newtype[i]) = build_decl (UNKNOWN_LOCATION,
+ TYPE_DECL,
+ get_identifier (name),
+ newtype[i]);
free (name);
}
}
@@ -673,6 +672,8 @@ srtype::create_new_type (void)
{
TYPE_FIELDS (newtype[i]) = newfields[i];
layout_type (newtype[i]);
+ if (TYPE_NAME (newtype[i]) != NULL)
+ layout_decl (TYPE_NAME (newtype[i]), 0);
}
warn_padded = save_warn_padded;
@@ -841,12 +842,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");
}
@@ -855,7 +850,8 @@ 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. */
@@ -899,6 +895,92 @@ 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)
+{
+ if (field_offset == NULL)
+ return 0;
+
+ 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.
+ 33~63 should pad to 64 but 33~48 (first half) are too far away, and
+ 65~127 should pad to 128 but 65~96 (first half) are too far away. */
+ 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))
+ if (TREE_CODE (field) == FIELD_DECL)
+ 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 {
struct ipa_struct_reorg
@@ -907,13 +989,10 @@ public:
// Constructors
ipa_struct_reorg (void)
: current_function (NULL),
- done_recording (false)
+ done_recording (false),
+ current_mode (NORMAL)
{}
- // Public methods
- unsigned execute (void);
- void mark_type_as_escape (tree type, escape_type, gimple *stmt = NULL);
-private:
// Fields
auto_vec_del<srtype> types;
auto_vec_del<srfunction> functions;
@@ -921,8 +1000,13 @@ private:
srfunction *current_function;
bool done_recording;
+ srmode current_mode;
+
+ // Methods
+ unsigned execute (enum srmode mode);
+ void mark_type_as_escape (tree type, escape_type escapes,
+ gimple *stmt = NULL);
- // Private methods
void dump_types (FILE *f);
void dump_types_escaped (FILE *f);
void dump_functions (FILE *f);
@@ -954,6 +1038,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);
@@ -976,6 +1061,7 @@ private:
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 *> &);
@@ -990,8 +1076,591 @@ 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");
+
+ char *gptr0_name = NULL;
+ const char *type_name = get_type_name (ctype.type);
+
+ if (type_name)
+ 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));
+
+ if (type_name && decl_name)
+ 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);
+ if (fn == NULL)
+ continue;
+
+ 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 ATTRIBUTE_UNUSED,
+ gimple_stmt_iterator *gsi ATTRIBUTE_UNUSED)
+{
+ /* Delete debug gimple now. */
+ 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)
+{
+ gcc_assert (TREE_CODE (node) == VAR_DECL);
+ 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
@@ -1189,7 +1858,7 @@ ipa_struct_reorg::record_type (tree type)
f->type = t1;
t1->add_field_site (f);
}
- if (t1 == type1)
+ if (t1 == type1 && current_mode != COMPLETE_STRUCT_RELAYOUT)
type1->mark_escape (escape_rescusive_type, NULL);
}
}
@@ -1331,6 +2000,12 @@ ipa_struct_reorg::record_var (tree decl, escape_type escapes, int arg)
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);
}
@@ -1369,6 +2044,7 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt)
|| TREE_CODE (expr) == VIEW_CONVERT_EXPR)
{
tree r = TREE_OPERAND (expr, 0);
+ tree orig_type = TREE_TYPE (expr);
if (handled_component_p (r)
|| TREE_CODE (r) == MEM_REF)
{
@@ -1382,8 +2058,18 @@ ipa_struct_reorg::find_var (tree expr, gimple *stmt)
escape_vce, stmt);
}
if (TREE_CODE (r) == MEM_REF)
- mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)),
- escape_addr, stmt);
+ {
+ mark_type_as_escape (TREE_TYPE (TREE_OPERAND (r, 1)),
+ escape_addr, stmt);
+ tree inner_type = TREE_TYPE (TREE_OPERAND (r, 0));
+ if (orig_type != inner_type)
+ {
+ mark_type_as_escape (orig_type,
+ escape_cast_another_ptr, stmt);
+ mark_type_as_escape (inner_type,
+ escape_cast_another_ptr, stmt);
+ }
+ }
r = TREE_OPERAND (r, 0);
}
mark_expr_escape (r, escape_addr, stmt);
@@ -1407,7 +2093,8 @@ ipa_struct_reorg::find_vars (gimple *stmt)
{
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);
@@ -1432,6 +2119,32 @@ ipa_struct_reorg::find_vars (gimple *stmt)
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:
@@ -1514,9 +2227,21 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
/* If we have a integer, just check if it is a multiply of STRUCT_SIZE. */
if (TREE_CODE (arg) == INTEGER_CST)
{
- 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)
+ {
+ size = -size;
+ sign = true;
+ }
+ tree arg2 = build_int_cst (TREE_TYPE (arg), size);
+ if (integer_zerop (size_binop (FLOOR_MOD_EXPR, arg2, struct_size)))
{
- *num = size_binop (FLOOR_DIV_EXPR, arg, 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;
@@ -1586,16 +2311,21 @@ is_result_of_mult (tree arg, tree *num, tree struct_size)
/* 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)
+ if (gimple_call_builtin_p (stmt, BUILT_IN_REALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALIGNED_ALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
+ return true;
return false;
}
@@ -1636,7 +2366,7 @@ ipa_struct_reorg::allocate_size (srtype *type, gimple *stmt)
the size of structure. */
if (operand_equal_p (arg1, struct_size, 0))
return size;
- /* Check that first argument is a constant equal to
+ /* ??? Check that first argument is a constant equal to
the size of structure. */
if (operand_equal_p (size, struct_size, 0))
return arg1;
@@ -1751,6 +2481,25 @@ ipa_struct_reorg::maybe_record_assign (cgraph_node *node, gassign *stmt)
}
}
+static 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;
+}
+
static tree
get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
bool &realpart, bool &imagpart,
@@ -1792,7 +2541,8 @@ get_ref_base_and_offset (tree &e, HOST_WIDE_INT &offset,
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:
@@ -2176,6 +2926,31 @@ ipa_struct_reorg::check_type_and_push (tree newdecl, srtype *type,
type1->mark_escape (escape_cast_another_ptr, stmt);
}
+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
@@ -2223,6 +2998,7 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
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,
@@ -2264,6 +3040,20 @@ ipa_struct_reorg::check_definition (srdecl *decl, vec<srdecl *> &worklist)
return;
}
+ if (gimple_assign_rhs_code (stmt) == MAX_EXPR
+ || gimple_assign_rhs_code (stmt) == MIN_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_IOR_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_XOR_EXPR
+ || gimple_assign_rhs_code (stmt) == BIT_AND_EXPR)
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ if (TREE_CODE (rhs) == SSA_NAME)
+ check_type_and_push (rhs, type, worklist, stmt);
+ if (TREE_CODE (rhs2) == SSA_NAME)
+ check_type_and_push (rhs2, type, worklist, stmt);
+ return;
+ }
+
/* Casts between pointers and integer are escaping. */
if (gimple_assign_cast_p (stmt))
{
@@ -2328,6 +3118,11 @@ ipa_struct_reorg::check_other_side (srdecl *decl, tree other, gimple *stmt,
srtype *t1 = find_type (inner_type (t));
if (t1 == type)
{
+ /* In Complete Struct Relayout, if lhs type is the same
+ as rhs type, we could return without any harm. */
+ if (current_mode == COMPLETE_STRUCT_RELAYOUT)
+ return;
+
tree base;
bool indirect;
srtype *type1;
@@ -2376,8 +3171,11 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
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);
@@ -2406,8 +3204,11 @@ ipa_struct_reorg::check_use (srdecl *decl, gimple *stmt,
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);
@@ -2692,6 +3493,12 @@ ipa_struct_reorg::record_accesses (void)
/* Record accesses inside a function. */
if (cnode->definition)
record_function (cnode);
+ else
+ {
+ tree return_type = TREE_TYPE (TREE_TYPE (cnode->decl));
+ mark_type_as_escape (return_type, escape_return, NULL);
+ }
+
}
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2807,8 +3614,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))
{
@@ -3954,17 +4764,66 @@ ipa_struct_reorg::rewrite_functions (void)
}
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 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 rewrite_functions ();
+ return ret;
}
const pass_data pass_data_ipa_struct_reorg =
@@ -3991,7 +4850,11 @@ public:
virtual bool gate (function *);
virtual unsigned int execute (function *)
{
- return ipa_struct_reorg ().execute ();
+ 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
@@ -3999,10 +4862,11 @@ public:
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 --git a/gcc/ipa-struct-reorg/ipa-struct-reorg.h b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
index a58794070..ef7f4c780 100644
--- a/gcc/ipa-struct-reorg/ipa-struct-reorg.h
+++ b/gcc/ipa-struct-reorg/ipa-struct-reorg.h
@@ -120,6 +120,9 @@ private:
public:
tree newtype[max_split];
bool visited;
+ /* Negative number means it has illegal allocated arrays
+ that we do not optimize. */
+ int has_alloc_array;
// Constructors
srtype (tree type);
@@ -232,4 +235,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 --git a/gcc/testsuite/g++.dg/struct/no-body-function.cpp b/gcc/testsuite/g++.dg/struct/no-body-function.cpp
new file mode 100644
index 000000000..4e56e73fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/struct/no-body-function.cpp
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-std=gnu++17 -Wno-builtin-declaration-mismatch -O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -S" } */
+
+struct S {
+ int x;
+ double y;
+};
+S f();
+
+const auto [x0, y0] = f();
+const auto [x1, y1] = f();
+
+static union {
+int a;
+double b;
+};
+
+const auto [x2, y2] = f();
diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp
new file mode 100644
index 000000000..6ab71abe1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/struct/struct-reorg-1.cpp
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details -S" } */
+
+struct Foo { int foo; int a; };
+Foo& ignoreSetMutex = *(new Foo);
+
+struct Goo { int goo; int a; };
+
+int main ()
+{
+ Goo* a;
+ return a->goo = 90;
+}
diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp
new file mode 100644
index 000000000..72b7db8a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/struct/struct-reorg-2.cpp
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details" } */
+
+#include <stdlib.h>
+
+struct testg {
+ int b;
+ float c;
+};
+
+testg *testgvar;
+int main ()
+{
+ testgvar = (testg*) calloc(10, sizeof(testg));
+ int b = testgvar->b;
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp b/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp
new file mode 100644
index 000000000..771164a96
--- /dev/null
+++ b/gcc/testsuite/g++.dg/struct/struct-reorg-3.cpp
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fwhole-program -flto-partition=one -fipa-struct-reorg -fdump-ipa-struct_reorg-details" } */
+
+#include <stdlib.h>
+
+struct testg {
+ int b;
+ float c;
+ double d;
+ double e;
+ double f;
+ double h;
+ double i;
+ double j;
+ int k;
+};
+
+testg *testgvar;
+int main ()
+{
+ testgvar = (testg*) calloc(10, sizeof(testg));
+ int b = testgvar->b;
+ return b;
+}
diff --git a/gcc/testsuite/g++.dg/struct/struct-reorg.exp b/gcc/testsuite/g++.dg/struct/struct-reorg.exp
new file mode 100644
index 000000000..e3ffe1388
--- /dev/null
+++ b/gcc/testsuite/g++.dg/struct/struct-reorg.exp
@@ -0,0 +1,26 @@
+# Copyright (C) 2021-2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib g++-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+g++-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.cpp]] \
+ "" ""
+
+# All done.
+dg-finish
\ No newline at end of file
diff --git a/gcc/testsuite/gcc.dg/struct/csr_1.c b/gcc/testsuite/gcc.dg/struct/csr_1.c
new file mode 100644
index 000000000..811030bf1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_1.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c
new file mode 100644
index 000000000..63bb695ae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-1.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c
new file mode 100644
index 000000000..0f75d5d12
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-2.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c
new file mode 100644
index 000000000..3dcb674c6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_allocation-3.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/csr_cast_int.c b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c
new file mode 100644
index 000000000..6907158c9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_cast_int.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c
new file mode 100644
index 000000000..9e5e05838
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/csr_separate_instance.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c
new file mode 100644
index 000000000..9d58edab8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/sr_address_of_field.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c b/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c
new file mode 100644
index 000000000..a99ee0de4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/sr_convert_mem.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+
+struct T1 {
+ long var1;
+ int var2;
+};
+
+struct T2 {
+ long var1;
+ int var2;
+};
+
+void test (void*);
+
+__attribute__((used)) void
+foo (struct T2 *t2)
+{
+ struct T1* t1 = (void *)(&t2[1]);
+ void* data = (void *)(&t1[1]);
+
+ test(data);
+ return;
+}
diff --git a/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c
new file mode 100644
index 000000000..fb135ef0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/sr_maxmin_expr.c
@@ -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 --git a/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c
new file mode 100644
index 000000000..9a4b10d9a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_and.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+
+struct test {long val; struct test* next; };
+
+unsigned long P_DATA;
+
+void func (struct test*);
+
+__attribute__((used)) static void
+foo (struct test* pt)
+{
+ struct test t;
+
+ t.next = (void *)((unsigned long)pt->next & P_DATA);
+ func(&t);
+ return;
+}
diff --git a/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c
new file mode 100644
index 000000000..9a82da0d6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/struct/sr_pointer_minus.c
@@ -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" } } */
--
2.33.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。