summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild.sh1
-rw-r--r--gary/error-summary31
-rw-r--r--gary/how_to_organize_reorg40
-rw-r--r--gcc/Makefile.in7
-rw-r--r--gcc/common.opt32
-rw-r--r--gcc/doc/invoke.texi25
-rw-r--r--gcc/ipa-hello-world.c569
-rw-r--r--gcc/ipa-hello-world.h19
-rw-r--r--gcc/ipa-str-reorg-dead-field-eliminate.c2763
-rw-r--r--gcc/ipa-str-reorg-field-reorder.c47
-rw-r--r--gcc/ipa-str-reorg-instance-interleave.c48
-rw-r--r--gcc/ipa-str-reorg-utils.c300
-rw-r--r--gcc/ipa-str-reorg-utils.h58
-rw-r--r--gcc/ipa-structure-reorg.c879
-rw-r--r--gcc/ipa-structure-reorg.h154
-rw-r--r--gcc/ipa-type-escape-analysis.c1029
-rw-r--r--gcc/ipa-type-escape-analysis.h21
-rw-r--r--gcc/lto-streamer.h2
-rw-r--r--gcc/passes.def3
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c13
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c20
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c20
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c27
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-09-parameter-type-escapes-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c26
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c27
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c11
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c25
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c17
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-21-rewrites-clobber-type-0.c17
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c28
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-24-array-cast-0.c31
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c31
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c31
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c20
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-28-array-cast-0.c31
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-3-new-offsets-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c26
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c28
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-32-pointer-indirection-level-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c42
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-35-array-cast-0.c38
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c37
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c37
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c38
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-4-layout-compile-0.c22
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c18
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c29
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c30
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c14
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c14
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c24
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c38
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c48
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-field-reads-0.c18
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-rewrite-local-decl-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c15
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c6
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c11
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c5
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c10
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c19
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c6
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c12
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c10
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-6-field-writes-0.c16
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c20
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-7-delete-first-field-0.c23
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-8-modify-double-struct-0.c33
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-9-modify-int-struct-0.c18
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-pass.h4
102 files changed, 7796 insertions, 2 deletions
diff --git a/build.sh b/build.sh
index f1ebba3e23c..620573c7b68 100755
--- a/build.sh
+++ b/build.sh
@@ -12,4 +12,3 @@ make -j `nproc`
make install -j `nproc`
make check-gcc RUNTESTFLAGS="ipa.exp"
popd
-
diff --git a/gary/error-summary b/gary/error-summary
new file mode 100644
index 00000000000..f51eae94ad9
--- /dev/null
+++ b/gary/error-summary
@@ -0,0 +1,31 @@
+There are two errors know to date and one porblem.
+
+Errors:
+
+1) Using typedef to create differents names for the same type will
+confuse the optimization into thinking that they are different
+types.
+
+This is a know big issue and not a surprise.
+
+2) Some local declarations go missing for not apparient reason.
+To verify this is the case in a suspicious situation uncoment
+the DEBUG statemest annotated with "test_1_8" and you'll see in the
+stderr output that there are no declarations associate with the
+function of interest.
+
+This was a surprise and will require a lot of debugging to track
+dowm the root case of the problem. If you wish to see my test case
+I will send it to you.
+
+Problem:
+
+If you invoke any of the structure reorg optimizations
+(e.g. -fipa-structure-reorg), you'll need to include the options
+"-flto -flto-partition=one". The problem is that struction reorg
+will unfortunenately run if only "-flto" is included with a
+struct reorg option but it will be insane and not function correctly.
+
+I've not found a way to address this yet but I'm hopeful that this
+is someing we can cope with.
+
diff --git a/gary/how_to_organize_reorg b/gary/how_to_organize_reorg
new file mode 100644
index 00000000000..c8116eac15b
--- /dev/null
+++ b/gary/how_to_organize_reorg
@@ -0,0 +1,40 @@
+I'll put shared types and externs in ipa-structure-reorg.h.
+The externs in file ipa-structure-reorg.h will be for the API
+calls.
+
+There will three flags associated with
+
+-fipa-structure-reorg
+-fipa-dead-field-eliminate
+-fipa-field-reorder
+-fipa-instance-interleave
+
+Specifying any of them will run the shared qualification analysis.
+
+Specifying -fipa-structure-reorg will be equivalent
+to invoking all the other flags.
+
+The other flags just run the specific structure reorg algorithm.
+
+The driver and shared qualification code will be in ipa-structure-reorg.c.
+I'm assuming for now that each algorithm will be in it's own file
+and can be invoked via from the driver like this
+
+ if ( control code )
+ {
+ int return_val = algorithm( info);
+ // typical actions dependent on the return value;
+ }
+
+Note, the info parameter (of type Info *) is how I'd like to give the
+API calls access to the persistent information. Frankly, this is my
+own strange idiom but it's served me well in the past and I think it
+beats globals which are something I want to avoid.
+
+Would it be OK for our first integration of code that I create one or
+two empty files. You'd supply a name that you are using now of course
+so you can just subsitute your work for the stubs on itegration.
+
+Also, reagarding the API itself wouldn't a reasonable start just
+be some of the functions in the utility section of my design?
+Check them out see if that makes any sense. \ No newline at end of file
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 523e3045fe8..419f64ec70e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1403,6 +1403,8 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+ ipa-type-escape-analysis.o \
+ ipa-hello-world.o \
ipa-escape-analysis.o \
compare-types.o \
collect-types.o \
@@ -1428,6 +1430,11 @@ OBJS = \
ipa-reference.o \
ipa-hsa.o \
ipa-ref.o \
+ ipa-structure-reorg.o \
+ ipa-str-reorg-dead-field-eliminate.o \
+ ipa-str-reorg-field-reorder.o \
+ ipa-str-reorg-instance-interleave.o \
+ ipa-str-reorg-utils.o \
ipa-utils.o \
ipa.o \
ira.o \
diff --git a/gcc/common.opt b/gcc/common.opt
index 5c626286a16..86aeb0d39e7 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1838,6 +1838,22 @@ fipa-struct-reorg
Common Ignore
Does nothing. Preserved for backward compatibility.
+fipa-structure-reorg
+Common Report Var(flag_ipa_structure_reorg) Init(0) Optimization
+Structure reorganization optimization.
+
+fipa-dead-field-eliminate
+Common Report Var(flag_ipa_dead_field_eliminate) Init(0) Optimization
+Structure reorganization optimization, dead field elimination.
+
+fipa-field-reorder
+Common Report Var(flag_ipa_field_reorder) Init(0) Optimization
+Structure reorganization optimization, field reordering.
+
+fipa-instance-interleave
+Common Report Var(flag_ipa_instance_interleave) Init(0) Optimization
+Structure reorganization optimization, instance interleaving.
+
fipa-vrp
Common Report Var(flag_ipa_vrp) Optimization
Perform IPA Value Range Propagation.
@@ -3413,6 +3429,22 @@ fipa-ra
Common Report Var(flag_ipa_ra) Optimization
Use caller save register across calls if possible.
+fipa-typelist-struct=
+Common Joined Report Var(flag_ipa_typelist_struct) Init(0)
+-fipa-typelist-struct=<string> Name of struct of interest
+
+fipa-typelist-field=
+Common Joined Report Var(flag_ipa_typelist_field) Init(0)
+-fipa-typelist-field=<string> Name of struct of interest
+
+fipa-type-escape-analysis
+Common Report Var(flag_ipa_type_escape_analysis) Optimization
+Type escape analysis
+
+fipa-hello-world
+Common Report Var(flag_ipa_hello_world) Optimization
+Hello world
+
fipa-escape-analysis
Common Report Var(flag_ipa_escape_analysis) Optimization
TBD
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 850aeac033d..29d1fd2fff5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -469,6 +469,8 @@ Objective-C and Objective-C++ Dialects}.
-fdelete-null-pointer-checks -fdevirtualize -fdevirtualize-speculatively @gol
-fdevirtualize-at-ltrans -fdse @gol
-fearly-inlining -fipa-sra -fexpensive-optimizations -ffat-lto-objects @gol
+-fipa-structure-reorg -fipa-dead-field-eliminate @gol
+-fipa-field-reorder -fipa-instance-interleave @gol
-ffast-math -ffinite-math-only -ffloat-store -fexcess-precision=@var{style} @gol
-ffinite-loops @gol
-fforward-propagate -ffp-contract=@var{style} -ffunction-sections @gol
@@ -9438,6 +9440,29 @@ by parameters passed by value.
Enabled at levels @option{-O2}, @option{-O3} and @option{-Os}.
+@item -fipa-structure-reorg
+@opindex fipa-structure-reorg
+Transforms arrays of structures with the dead field, field reordering
+and instance interleaving optimizations (which can be invoked seperately
+with their own flags.)
+
+@item -fipa-dead-field-eliminate
+@opindex fipa-dead-field-eliminate
+Theobroma plaese add comment here.
+
+@item -fipa-field-reorder
+@opindex fipa-field-reorder
+Theobroma plaese add comment here.
+
+@item -fipa-instance-interleave
+@opindex fipa-instance-interleave
+Transforms arrays of structures into structures of arrays. This
+improves cache locality if there are loops that use only a small
+number of fields from a transformed array. The performance
+qualification of this optimization relies on execution counts of loops
+so running with branch profiling data available will improve the
+outcome.
+
@item -finline-limit=@var{n}
@opindex finline-limit
By default, GCC limits the size of functions that can be inlined. This flag
diff --git a/gcc/ipa-hello-world.c b/gcc/ipa-hello-world.c
new file mode 100644
index 00000000000..e75de90bee5
--- /dev/null
+++ b/gcc/ipa-hello-world.c
@@ -0,0 +1,569 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "predict.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "ipa-prop.h"
+#include "tree-pretty-print.h"
+#include "tree-inline.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "tree-cfg.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+
+#include <map>
+#include <set>
+
+#include "ipa-type-escape-analysis.h"
+#include "ipa-str-reorg-utils.h"
+#include "ipa-hello-world.h"
+
+
+//TODO: place in header file
+inline static void
+print_function (cgraph_node *cnode)
+{
+ if (!dump_file)
+ return;
+ gcc_assert (cnode);
+ cnode->get_untransformed_body ();
+ dump_function_to_file (cnode->decl, dump_file, TDF_NONE);
+}
+
+//TODO: do not use pair.
+//This names are unintelligible
+typedef std::pair<unsigned /* reads */, unsigned /* writes */> accesses;
+struct field_comparator
+{
+ bool operator()(const fields &left, const fields &right) const
+ {
+ const_tree left_record = left.first;
+ gcc_assert(left_record);
+ const_tree right_record = right.first;
+ gcc_assert(right_record);
+ // Make sure that we are only comparing valid types...
+ const enum tree_code tree_code_left_record = TREE_CODE(left_record);
+ const enum tree_code tree_code_right_record = TREE_CODE(right_record);
+ const bool is_left_record_type = RECORD_TYPE == tree_code_left_record;
+ const bool is_right_record_type = RECORD_TYPE == tree_code_right_record;
+ gcc_assert(is_left_record_type);
+ gcc_assert(is_right_record_type);
+ const bool are_left_and_right_valid = is_left_record_type && is_right_record_type;
+ gcc_assert(are_left_and_right_valid);
+
+ // Handle typedefs:
+ // Get the main variants of the main types
+ const_tree main_variant_left = TYPE_MAIN_VARIANT(left_record);
+ gcc_assert(main_variant_left);
+ const_tree main_variant_right = TYPE_MAIN_VARIANT(right_record);
+ gcc_assert(main_variant_right);
+ // If they are not equal, we can do a comparison of the types here...
+ const bool are_main_variants_equal = main_variant_left == main_variant_right;
+ const bool left_type_less_than_right_type = main_variant_left < main_variant_right;
+ if (!are_main_variants_equal) return left_type_less_than_right_type;
+
+ // If they are equal, that means that we are comparing fields defined in the same record
+ const_tree left_field = left.second;
+ gcc_assert(left_field);
+ const_tree right_field = right.second;
+ gcc_assert(right_field);
+ // Make sure that they are valid
+ const enum tree_code tree_code_left_field = TREE_CODE(left_field);
+ const enum tree_code tree_code_right_field = TREE_CODE(right_field);
+ const bool is_left_field_field_decl = FIELD_DECL == tree_code_left_field;
+ const bool is_right_field_field_decl = FIELD_DECL == tree_code_right_field;
+ const bool are_left_and_right_field_decls = is_left_field_field_decl && is_right_field_field_decl;
+ gcc_assert(are_left_and_right_field_decls);
+
+ // Compare on the field offset.
+ const_tree left_constant = byte_position(left_field);
+ gcc_assert(left_constant);
+ const_tree right_constant = byte_position(right_field);
+ gcc_assert(right_constant);
+ unsigned left_offset = tree_to_uhwi(left_constant);
+ unsigned right_offset = tree_to_uhwi(right_constant);
+ const bool left_offset_less_than_right_offset = left_offset < right_offset;
+ return left_offset_less_than_right_offset;
+ }
+};
+
+typedef std::map<fields, accesses, field_comparator> field_access_counter;
+typedef std::set<const_tree> record_set;
+
+enum access_code { READ_ACCESS, WRITE_ACCESS };
+
+void count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access);
+
+void
+count_access_for_type_in_component_ref(const_tree component_ref, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
+{
+ log("types in component_ref\n");
+ gcc_assert(component_ref);
+ enum tree_code tree_code_component_ref = TREE_CODE(component_ref);
+ const bool is_component_ref = COMPONENT_REF == tree_code_component_ref;
+ gcc_assert(is_component_ref);
+
+ const_tree _struct = TREE_OPERAND(component_ref, 0);
+ gcc_assert(_struct);
+
+ log ("going in recursion\n");
+ count_access_for_types_in_expr(_struct, non_escaping_records, counter, READ_ACCESS);
+ const_tree tree_type_struct = TREE_TYPE(_struct);
+ gcc_assert(tree_type_struct);
+ enum tree_code tree_type_struct_code = TREE_CODE(tree_type_struct);
+ const bool is_record_type = RECORD_TYPE == tree_type_struct_code;
+ //TODO: Also write something for UNION_TYPE
+ switch (tree_type_struct_code)
+ {
+ case UNION_TYPE: return; break;
+ case RECORD_TYPE: break;
+ default: gcc_unreachable(); break;
+ }
+ gcc_assert(is_record_type);
+
+ //FIXME: Future proofing or making things more difficult to read?
+ bool in_set =
+#if __cplusplus > 201703L
+ non_escaping_records.contains(tree_type_struct)
+#else
+ non_escaping_records.find(tree_type_struct) != non_escaping_records.end()
+#endif
+ ;
+
+ in_set |=
+#if __cplusplus > 201703L
+ non_escaping_records.contains(TYPE_MAIN_VARIANT(tree_type_struct))
+#else
+ non_escaping_records.find(TYPE_MAIN_VARIANT(tree_type_struct)) != non_escaping_records.end()
+#endif
+ ;
+
+
+ log("%s is in non_escaping_records ? %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false");
+ log("access is %s\n", access == READ_ACCESS ? "read_access" : "write_access");
+ log("%s is in non_escaping set %s\n", get_type_name(tree_type_struct), in_set ? "true" : "false");
+ if (!in_set) return;
+
+ const_tree field = TREE_OPERAND(component_ref, 1);
+ gcc_assert(field);
+ enum tree_code tree_code_field = TREE_CODE(field);
+ const bool is_field_decl = FIELD_DECL == tree_code_field;
+ gcc_assert(is_field_decl);
+
+ const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(tree_type_struct, field);
+ accesses &access_counter = counter[struct_field_pair];
+
+ switch (access)
+ {
+ case READ_ACCESS:
+ //TODO: do not use pair.
+ //This names are unintelligible
+ access_counter.first++;
+ log("%s.%s read %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.first);
+ break;
+ case WRITE_ACCESS:
+ //TODO: do not use pair.
+ //This names are unintelligible
+ access_counter.second++;
+ log("%s.%s write %d\n", get_type_name(tree_type_struct), get_field_name(field), access_counter.second);
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+static inline void
+is_addr_expr_p(const_tree expr)
+{
+ gcc_assert(expr);
+ const enum tree_code code = TREE_CODE(expr);
+ const bool is_addr_expr = ADDR_EXPR == code;
+ gcc_assert(is_addr_expr);
+}
+
+
+void
+count_access_for_type_in_addr_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
+{
+ is_addr_expr_p(expr);
+ const_tree op0 = TREE_OPERAND(expr, 0);
+ count_access_for_types_in_expr(op0, non_escaping_records, counter, access);
+}
+
+static inline void
+is_array_expr_p(const_tree expr)
+{
+ gcc_assert(expr);
+ const enum tree_code code = TREE_CODE(expr);
+ const bool is_addr_expr = ARRAY_REF == code;
+ gcc_assert(is_addr_expr);
+}
+
+void
+count_access_for_type_in_array_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
+{
+ is_array_expr_p(expr);
+ const_tree op0 = TREE_OPERAND(expr, 0);
+ const_tree op1 = TREE_OPERAND(expr, 1);
+ count_access_for_types_in_expr(op0, non_escaping_records, counter, READ_ACCESS);
+ count_access_for_types_in_expr(op1, non_escaping_records, counter, READ_ACCESS);
+}
+
+void
+count_access_for_types_in_expr(const_tree expr, const record_set &non_escaping_records, field_access_counter &counter, const enum access_code access)
+{
+ log("types in expr\n");
+ gcc_assert(expr);
+ enum tree_code tree_code_expr = TREE_CODE(expr);
+ switch (tree_code_expr)
+ {
+ case COMPONENT_REF: count_access_for_type_in_component_ref(expr, non_escaping_records, counter, access); break;
+ case ADDR_EXPR: count_access_for_type_in_addr_expr(expr, non_escaping_records, counter, access); break;
+ case ARRAY_REF : count_access_for_type_in_array_expr(expr, non_escaping_records, counter, access); break;
+ default: break;
+ }
+}
+
+void
+count_access_for_types_in_lhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ gcc_assert(stmt);
+ const enum gimple_code gimple_code_stmt = gimple_code(stmt);
+ const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt;
+ const bool is_call = GIMPLE_CALL == gimple_code_stmt;
+ const bool is_valid = is_assign || is_call;
+ gcc_assert(is_valid);
+
+
+ const_tree lhs = is_assign ? gimple_assign_lhs (stmt) : gimple_call_lhs (stmt);
+ /* GIMPLE_CALL might have a lhs null.
+ * E.g.
+ * foo()
+ */
+ if (!lhs) return;
+
+ count_access_for_types_in_expr(lhs, non_escaping_records, counter, WRITE_ACCESS);
+}
+
+void
+count_access_for_types_in_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ gcc_assert(stmt);
+ const enum gimple_code gimple_code_stmt = gimple_code(stmt);
+ const bool is_assign = GIMPLE_ASSIGN == gimple_code_stmt;
+ gcc_assert(is_assign);
+
+ log("types in rhs\n");
+ const enum gimple_rhs_class gimple_rhs_class_stmt = gimple_assign_rhs_class(stmt);
+ switch (gimple_rhs_class_stmt)
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ log("gimple_ternary_rhs\n");
+ }
+ /* fall through */
+ case GIMPLE_BINARY_RHS:
+ {
+ log("gimple_binary_rhs\n");
+ }
+ /* fall through */
+ case GIMPLE_SINGLE_RHS:
+ case GIMPLE_UNARY_RHS:
+ {
+ const_tree rhs1 = gimple_assign_rhs1(stmt);
+ gcc_assert(rhs1);
+ count_access_for_types_in_expr(rhs1, non_escaping_records, counter, READ_ACCESS);
+ log("gimple_single_rhs\n");
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+inline static void
+is_gimple_assign_p(gimple *stmt)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code(stmt);
+ const bool is_assign = GIMPLE_ASSIGN == code;
+ gcc_assert(is_assign);
+}
+
+inline static void
+is_gimple_call_p(gimple *stmt)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code(stmt);
+ const bool is_call = GIMPLE_CALL == code;
+ gcc_assert(is_call);
+
+}
+
+void
+count_access_for_types_in_assign(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ is_gimple_assign_p(stmt);
+
+ count_access_for_types_in_rhs(stmt, non_escaping_records, counter);
+ count_access_for_types_in_lhs(stmt, non_escaping_records, counter);
+}
+
+static void
+count_access_for_types_in_call_rhs(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ is_gimple_call_p(stmt);
+ unsigned args = gimple_call_num_args (stmt);
+
+
+
+ for (unsigned i = 0; i < args; i++)
+ {
+ const_tree arg = gimple_call_arg (stmt, i);
+ count_access_for_types_in_expr(arg, non_escaping_records, counter, READ_ACCESS);
+ }
+
+}
+
+void
+count_access_for_types_in_call(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ is_gimple_call_p(stmt);
+ count_access_for_types_in_lhs(stmt, non_escaping_records, counter);
+
+ /* TODO: We need to iterate over each argument and find out if it is a read */
+ count_access_for_types_in_call_rhs(stmt, non_escaping_records, counter);
+}
+
+void
+count_access_for_types_in_stmt(gimple *stmt, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ gcc_assert(stmt);
+ const enum gimple_code gimple_code_stmt = gimple_code(stmt);
+ switch(gimple_code_stmt)
+ {
+ case GIMPLE_ASSIGN:
+ count_access_for_types_in_assign(stmt, non_escaping_records, counter);
+ break;
+ case GIMPLE_CALL:
+ count_access_for_types_in_call(stmt, non_escaping_records, counter);
+ break;
+ default:
+ break;
+ }
+}
+
+void
+count_access_for_types_in_bb(basic_block bb, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ gcc_assert(bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt(gsi);
+ count_access_for_types_in_stmt(stmt, non_escaping_records, counter);
+ }
+}
+
+void
+count_access_for_types_in_function(cgraph_node *cnode, const record_set &non_escaping_records, field_access_counter &counter)
+{
+ gcc_assert(cnode);
+ tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ push_cfun(func);
+ basic_block bb = NULL;
+ FOR_EACH_BB_FN (bb, func)
+ {
+ gcc_assert(bb);
+ count_access_for_types_in_bb(bb, non_escaping_records, counter);
+ }
+ pop_cfun();
+}
+
+void
+init_field_access_counter(field_access_counter &counter, const record_set &non_escaping_records)
+{
+ for (auto it = non_escaping_records.cbegin(); it != non_escaping_records.cend(); ++it)
+ {
+ const_tree record = *it;
+ gcc_assert(record);
+ enum tree_code tree_code_record_type = TREE_CODE(record);
+ const bool is_record_type = RECORD_TYPE == tree_code_record_type;
+ gcc_assert(is_record_type);
+
+ for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
+ {
+ gcc_assert(field);
+ const std::pair<const_tree, const_tree> struct_field_pair = std::make_pair(record, field);
+ counter[struct_field_pair] = { 0, 0 };
+ }
+ }
+}
+
+/* INFO:
+ * Yes, I know we are returning a std::map.
+ * Bad pattern? Maybe, but this will only be called once
+ * and I rather pass by value because that allows
+ * me to have a pure function and not worry about
+ * garbage collection
+ *
+ * TODO: I'd like to change type_map for a std::map
+ * TODO: I'd like to make this a template that can work
+ * for std::map and std::set
+ */
+field_access_counter
+count_access_for_types_in_linking_unit(const record_set &non_escaping_records)
+{
+ field_access_counter counter;
+ init_field_access_counter(counter, non_escaping_records);
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION(cnode)
+ {
+ gcc_assert(cnode);
+ log("printing a defined function\n");
+ print_function(cnode);
+ count_access_for_types_in_function(cnode, non_escaping_records, counter);
+ }
+ return counter;
+}
+
+bool
+_calculate_non_escaping_records(const_tree const &type, escaping_info *info, record_set *non_escaping_records)
+{
+
+ gcc_assert(info);
+ log("NOW: %s is escaping %s\n", get_type_name(type), info->is_escaping ? "true" : "false");
+ if (info->is_escaping) return true;
+ gcc_assert(non_escaping_records);
+
+ enum tree_code tree_code_type = TREE_CODE(type);
+ const bool is_record_type = RECORD_TYPE == tree_code_type;
+ log("NOW: %s is record %s\n", get_type_name(type), is_record_type ? "true" : "false");
+ if (!is_record_type) return true;
+
+ non_escaping_records->insert(type);
+ return true;
+}
+
+/*
+ * Yes, again, we are passing a std::set
+ * as a value. I don\t care too much since
+ * this is only called once...
+ */
+static record_set
+calculate_non_escaping_records(type_map &escaping_type_info)
+{
+ // We are going to have to traverse the type_map...
+ // This is why I don't really like hash_set...
+ record_set non_escaping_records;
+ escaping_type_info.traverse<record_set*, _calculate_non_escaping_records>(&non_escaping_records);
+ return non_escaping_records;
+}
+
+static field_access_counter
+count_field_accesses()
+{
+
+ type_map escaping_types;
+ calculate_escaping_types(escaping_types);
+ const record_set non_escaping_records = calculate_non_escaping_records(escaping_types);
+ field_access_counter counter = count_access_for_types_in_linking_unit(non_escaping_records);
+ return counter;
+}
+
+record_field_set
+get_fields_to_reorg()
+{
+ const field_access_counter counter = count_field_accesses();
+ record_field_set records_and_fields_to_reorg;
+ for (auto it = counter.cbegin(); it != counter.cend(); ++it)
+ {
+ fields record_field_pair = it->first;
+ accesses counter = it->second;
+ const_tree record = record_field_pair.first;
+ const_tree field = record_field_pair.second;
+ // We are interested in reads == 0;
+ unsigned reads = counter.first;
+ log("final count for %s.%s = %d\n", get_type_name(record), get_field_name(field), reads);
+ if (0 != reads) continue;
+
+ records_and_fields_to_reorg.insert(record_field_pair);
+ }
+
+ return records_and_fields_to_reorg;
+}
+
+void
+print_record_field_set(const record_field_set &to_reorg)
+{
+ log_2("I am about to print\n");
+ for (auto it = to_reorg.cbegin(); it != to_reorg.cend(); ++it)
+ {
+ fields record_field_pair = *it;
+ const_tree record = record_field_pair.first;
+ const_tree field = record_field_pair.second;
+ // TODO: Some fields / records might be anonymous
+ log_2("will eliminate %s.%s\n", get_type_name(record), get_field_name(field));
+ }
+}
+
+
+static unsigned int
+iphw_execute()
+{
+ const record_field_set to_reorg = get_fields_to_reorg();
+ log("I am about to enter print function\n");
+ print_record_field_set(to_reorg);
+ return 0;
+}
+
+namespace {
+const pass_data pass_data_ipa_hello_world =
+{
+ SIMPLE_IPA_PASS,
+ "hello-world",
+ OPTGROUP_NONE,
+ TV_NONE,
+ (PROP_cfg | PROP_ssa),
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+class pass_ipa_hello_world : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_hello_world (gcc::context *ctx)
+ : simple_ipa_opt_pass(pass_data_ipa_hello_world, ctx)
+ {}
+
+ virtual bool gate(function*) { return flag_ipa_hello_world; }
+ virtual unsigned execute (function*) { return iphw_execute(); }
+};
+} // anon namespace
+
+simple_ipa_opt_pass*
+make_pass_ipa_hello_world (gcc::context *ctx)
+{
+ return new pass_ipa_hello_world (ctx);
+}
diff --git a/gcc/ipa-hello-world.h b/gcc/ipa-hello-world.h
new file mode 100644
index 00000000000..aec99da3260
--- /dev/null
+++ b/gcc/ipa-hello-world.h
@@ -0,0 +1,19 @@
+#ifndef GCC_IPA_HELLO_WORLD_H
+#define GCC_IPA_HELLO_WORLD_H
+#pragma once
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+
+#include <set>
+
+//TODO: do not use pair.
+//This names are unintelligible
+typedef std::pair<const_tree /* record */, const_tree /* field */> fields;
+typedef std::set<fields> record_field_set;
+record_field_set get_fields_to_reorg();
+void print_record_field_set(const record_field_set &to_reorg);
+
+#endif
diff --git a/gcc/ipa-str-reorg-dead-field-eliminate.c b/gcc/ipa-str-reorg-dead-field-eliminate.c
new file mode 100644
index 00000000000..f86ed1f866a
--- /dev/null
+++ b/gcc/ipa-str-reorg-dead-field-eliminate.c
@@ -0,0 +1,2763 @@
+/* Interprocedural scalar replacement of aggregates
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Erick Ochoa <erick.ochoa@theobroma-systems.com>
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "options.h"
+#include "cgraph.h"
+#include "tree-pass.h"
+#include "tree-cfg.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "stringpool.h" //get_identifier
+#include "basic-block.h" //needed for gimple.h
+#include "function.h" //needed for gimple.h
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "stor-layout.h" // layout_type
+#include "fold-const.h" //build_fold_addr_expr
+#include "gimple-ssa.h" // update_stmt
+#include "attribs.h" // decl_attributes
+#include "gimplify.h" //unshare_expr
+#include "value-range.h" // make_ssa_name dependency
+#include "tree-ssanames.h" // make_ssa_name
+#include "ssa.h"
+#include "tree-into-ssa.h"
+#include <vector> // needed for ipa-structure-reorg
+#include <map>
+#include <set>
+#include "ipa-structure-reorg.h"
+#include "ipa-utils.h"
+#include "ipa-str-reorg-utils.h"
+#include "ipa-hello-world.h"
+
+#define test_write(M, ...) \
+ if (dump_file) \
+ { \
+ fprintf (dump_file, M, ##__VA_ARGS__); \
+ }
+
+#define test_log(M, indent, ...) \
+ if (dump_file) \
+ { \
+ fprintf (dump_file, "%*c" M "\n", indent, ' ', ##__VA_ARGS__); \
+ }
+
+
+static void
+log_expr_prologue (const int indent, const char *debug_str, tree expr)
+{
+ const char *expr_str = print_generic_expr_to_str (expr);
+ test_log ("<%s \"%s\">", indent, debug_str, expr_str);
+ const_tree type = TREE_TYPE (expr);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ const_tree domain = TYPE_DOMAIN (type);
+ const_tree min = TYPE_MIN_VALUE (domain);
+ const_tree max = TYPE_MAX_VALUE (domain);
+ int _min = tree_to_uhwi (min);
+ int _max = tree_to_uhwi (max);
+ test_log ("< domain = (%d,%d)>", indent, _min, _max);
+ }
+ test_log ("< type = %s>", indent, get_type_name (type));
+}
+
+static tree
+const_to_tree (const_tree ctree)
+{
+ return (tree) ctree;
+}
+
+static void
+substitute_type (tree expr, const_tree new_type)
+{
+ gcc_assert(expr);
+ gcc_assert(new_type);
+ const_tree old_type = TREE_TYPE(expr);
+ TREE_TYPE(expr) = const_to_tree(new_type);
+}
+
+static void
+substitute_type (tree expr, const_tree* new_type_ptr)
+{
+ gcc_assert(new_type_ptr);
+ substitute_type(expr, *new_type_ptr);
+}
+
+// This function should be hidden
+static const_tree
+get_base_type_from_ptr_or_arr_var (const_tree var,
+ unsigned int &indirection_level)
+{
+ tree ptr_or_array = TREE_TYPE (var);
+ const bool is_array = TREE_CODE (ptr_or_array) == ARRAY_TYPE;
+ const bool is_ptr = TREE_CODE (ptr_or_array) == POINTER_TYPE;
+ const bool is_array_or_ptr = is_array || is_ptr;
+ gcc_assert (is_array_or_ptr);
+ const_tree retval
+ = get_base_type_from_ptr_or_arr_type (ptr_or_array, indirection_level);
+ return retval;
+}
+
+static const_tree __attribute__((unused))
+get_base_type_from_array_var (const_tree var, unsigned int &indirection_level)
+{
+ gcc_assert (TREE_CODE (var) != ARRAY_TYPE);
+ tree array_type = TREE_TYPE (var);
+ gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
+ const_tree retval
+ = get_base_type_from_ptr_or_arr_var (array_type, indirection_level);
+ return retval;
+}
+
+static const_tree
+get_base_type_from_pointer_var (const_tree var, unsigned int &indirection_level)
+{
+ gcc_assert (TREE_CODE (var) != POINTER_TYPE);
+ tree pointer_type = TREE_TYPE (var);
+ gcc_assert (TREE_CODE (pointer_type) == POINTER_TYPE);
+ const_tree retval
+ = get_base_type_from_ptr_or_arr_type (pointer_type, indirection_level);
+ return retval;
+}
+
+static const_tree __attribute__((unused))
+get_base_type_from_pointer_var (const_tree var)
+{
+ gcc_assert (TREE_CODE (var) != POINTER_TYPE);
+ unsigned int indirection_level;
+ return get_base_type_from_pointer_var (var, indirection_level);
+}
+
+// INFO: cannot change
+// tree expr to const_tree expr
+static void
+log_expr_epilogue (const int indent, const char *debug_str, tree expr)
+{
+ const char *expr_str = print_generic_expr_to_str (expr);
+ const_tree type = TREE_TYPE (expr);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ const_tree domain = TYPE_DOMAIN (type);
+ const_tree min = TYPE_MIN_VALUE (domain);
+ const_tree max = TYPE_MAX_VALUE (domain);
+ int _min = tree_to_uhwi (min);
+ int _max = tree_to_uhwi (max);
+ test_log ("< domain = (%d,%d)>", indent, _min, _max);
+ }
+ test_log ("< type = %s>", indent, get_type_name (type));
+ test_log ("</%s \"%s\">", indent, debug_str, expr_str);
+}
+
+
+
+static const char *
+make_base_name_based_on_old (const char *old_name)
+{
+ gcc_assert (old_name);
+ char *ptr;
+ static const char *suffix = ".reorg";
+ int new_size = strlen (old_name) + strlen (suffix);
+ int retval = asprintf (&ptr, "%s%s", old_name, suffix);
+ gcc_assert (retval == new_size);
+ return ptr;
+}
+
+static const char *
+make_base_name_based_on_old (const_tree base_type)
+{
+ enum tree_code base_code = TREE_CODE (base_type);
+ const bool is_pointer = POINTER_TYPE == base_code;
+ const bool is_array = ARRAY_TYPE == base_code;
+ const bool prohibited = is_pointer || is_array;
+ // This means that this is only for base types
+ // and structs.
+ // I.e. we don't want to generate names which have
+ //[][][] at the end or ****
+ gcc_assert (!prohibited);
+ const char *base_type_name = get_type_name (base_type);
+ return make_base_name_based_on_old (base_type_name);
+}
+
+static const char *
+make_record_name_based_on_old (const char *old_record_name)
+{
+ return make_base_name_based_on_old (old_record_name);
+}
+
+static const char *
+make_array_name_based_on_old (const_tree array)
+{
+ enum tree_code code = TREE_CODE (array);
+ gcc_assert (ARRAY_TYPE == code);
+ unsigned int indirection_level;
+ const_tree base_type
+ = get_base_type_from_array_type (array, indirection_level);
+ const char *reorged_base_type_name = make_base_name_based_on_old (base_type);
+ const char *suffix = make_array_postfix (indirection_level);
+ return make_pointer_or_array_name (reorged_base_type_name, suffix);
+}
+
+static const char *
+make_pointer_name_based_on_old (const_tree pointer)
+{
+ enum tree_code code = TREE_CODE (pointer);
+ gcc_assert (POINTER_TYPE == code);
+ unsigned int indirection_level;
+ const_tree base_type
+ = get_base_type_from_pointer_type (pointer, indirection_level);
+ const char *reorged_base_type_name = make_base_name_based_on_old (base_type);
+ const char *suffix = make_pointer_postfix (indirection_level);
+ return make_pointer_or_array_name (reorged_base_type_name, suffix);
+}
+
+static const char *
+make_record_name_based_on_old (const_tree record)
+{
+ enum tree_code code = TREE_CODE (record);
+ gcc_assert (RECORD_TYPE == code);
+ const char *old_name = get_type_name (record);
+ return make_record_name_based_on_old (old_name);
+}
+
+
+typedef hash_set<const_tree> field_set;
+typedef hash_set<const_tree> tree_set;
+struct delete_info { const_tree old_record; const_tree new_record; field_set* deleted_fields;};
+typedef struct delete_info delete_info_t;
+typedef hash_map<const_tree, delete_info_t> t_map;
+
+static bool
+rewrite_addr_expr_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_addr_expr (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_addr_expr", expr);
+ bool retval = rewrite_addr_expr_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_addr_expr", expr);
+ return retval;
+}
+
+static bool
+rewrite_array_ref_def (tree expr, t_map &type_map,
+ const int indent);
+
+static bool
+rewrite_array_ref (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_array_ref", expr);
+ bool retval = rewrite_array_ref_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_array_ref", expr);
+ return retval;
+}
+
+static bool
+rewrite_bin_expr_default_def (tree expr,
+ t_map &type_map,
+ const int indent);
+static bool
+rewrite_bin_expr_default (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_bin_expr", expr);
+ bool retval = rewrite_bin_expr_default_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_bin_expr", expr);
+ return retval;
+}
+
+static bool
+rewrite_constructor_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_constructor (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_constructor", expr);
+ bool retval = rewrite_constructor_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_constructor", expr);
+ return retval;
+}
+
+static bool
+rewrite_field_decl_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_field_decl (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_field_decl", expr);
+ bool retval = rewrite_field_decl_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_field_decl", expr);
+ return retval;
+}
+
+static bool
+rewrite_integer_cst_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_integer_cst (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_integer_cst", expr);
+ bool retval = rewrite_integer_cst_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_integer_cst", expr);
+ return retval;
+}
+
+static bool
+rewrite_function_decl_def (tree expr,
+ t_map &type_map,
+ const int indent);
+static bool
+rewrite_function_decl (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_function_decl", expr);
+ bool retval = rewrite_function_decl_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_function_decl", expr);
+ return retval;
+}
+
+static bool
+rewrite_component_ref (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_component_ref_def (tree expr,
+ t_map &type_map,
+ const int indent);
+static bool
+rewrite_component_ref (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_component_ref", expr);
+ bool retval = rewrite_component_ref_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_component_ref", expr);
+ return retval;
+}
+
+static bool
+rewrite_expr (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_expr_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_expr (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_expr", expr);
+ bool retval = rewrite_expr_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_expr", expr);
+ return retval;
+}
+
+static bool
+rewrite_mem_ref_def (tree expr, t_map &type_map,
+ const int indent);
+
+static bool
+rewrite_mem_ref (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_mem_ref", expr);
+ bool retval = rewrite_mem_ref_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_mem_ref", expr);
+ return retval;
+}
+
+
+static bool
+rewrite_ssa_name_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_ssa_name (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_ssa_name", expr);
+ bool retval = rewrite_ssa_name_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_ssa_name", expr);
+ return retval;
+}
+
+static bool
+rewrite_var_decl_def (tree expr, t_map &type_map,
+ const int indent);
+static bool
+rewrite_var_decl (tree expr, t_map &type_map,
+ const int indent)
+{
+ log_expr_prologue (indent, "rewrite_var_decl", expr);
+ bool retval = rewrite_var_decl_def (expr, type_map, indent + 4);
+ log_expr_epilogue (indent, "rewrite_var_decl", expr);
+ return retval;
+}
+
+static bool
+rewrite_expr_def (tree expr, t_map &type_map,
+ const int indent)
+{
+ bool retval = false;
+ switch (TREE_CODE (expr))
+ {
+ case ADDR_EXPR:
+ retval = rewrite_addr_expr (expr, type_map, indent);
+ break;
+ case ARRAY_REF:
+ retval = rewrite_array_ref (expr, type_map, indent);
+ break;
+ case COMPONENT_REF:
+ retval = rewrite_component_ref (expr, type_map, indent);
+ break;
+ case CONSTRUCTOR:
+ retval = rewrite_constructor (expr, type_map, indent);
+ break;
+ case FIELD_DECL:
+ retval = rewrite_field_decl (expr, type_map, indent);
+ break;
+ case FUNCTION_DECL:
+ retval = rewrite_function_decl (expr, type_map, indent);
+ break;
+ case INTEGER_CST:
+ retval = rewrite_integer_cst (expr, type_map, indent);
+ break;
+ case MEM_REF:
+ retval = rewrite_mem_ref (expr, type_map, indent);
+ break;
+ case MINUS_EXPR:
+ retval = rewrite_bin_expr_default (expr, type_map, indent);
+ break;
+ case MULT_EXPR:
+ retval = rewrite_bin_expr_default (expr, type_map, indent);
+ break;
+ case POINTER_DIFF_EXPR:
+ // not needed
+ break;
+ case POINTER_PLUS_EXPR:
+ // not needed
+ break;
+ case PLUS_EXPR:
+ // not needed
+ break;
+ case SSA_NAME:
+ retval = rewrite_ssa_name (expr, type_map, indent);
+ break;
+ case VAR_DECL:
+ retval = rewrite_var_decl (expr, type_map, indent);
+ break;
+ default:
+ {
+ //TODO: can we put an unreachable here?
+ enum tree_code code = TREE_CODE (expr);
+ test_log ("code = %s", indent, get_tree_code_name (code));
+ delete_info_t *delete_info = type_map.get (TREE_TYPE(expr));
+ const_tree *new_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (!new_type_ptr)
+ return false;
+ retval = true;
+ substitute_type(expr, new_type_ptr);
+ }
+ break;
+ }
+
+ return retval;
+}
+
+inline static void
+test_print_generic_decl (tree decl)
+{
+ if (!dump_file)
+ return;
+ print_generic_decl (dump_file, decl, TDF_DETAILS);
+}
+
+inline static void
+test_print_gimple_stmt (gimple *stmt)
+{
+ if (!dump_file)
+ return;
+ print_gimple_stmt (dump_file, stmt, 0, TDF_NONE);
+}
+
+inline static void
+print_function (cgraph_node *cnode)
+{
+ if (!dump_file)
+ return;
+ gcc_assert (cnode);
+ cnode->get_untransformed_body ();
+ dump_function_to_file (cnode->decl, dump_file, TDF_NONE);
+}
+
+static unsigned
+get_field_offset (const_tree field)
+{
+ gcc_assert (TREE_CODE (field) == FIELD_DECL);
+ tree cst = byte_position (field);
+ unsigned offset = tree_to_uhwi (cst);
+ return offset;
+}
+
+
+static const_tree
+get_field_with_offset_unsafe (const_tree record, const unsigned offset)
+{
+ gcc_assert (record);
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+ for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
+ {
+ unsigned field_offset = get_field_offset (field);
+ if (field_offset == offset)
+ return field;
+ }
+
+ return NULL;
+}
+
+static const_tree __attribute__((unused))
+get_field_with_offset (const_tree record, const unsigned offset)
+{
+ const_tree retval = get_field_with_offset_unsafe (record, offset);
+ gcc_assert (retval != NULL);
+ return retval;
+}
+
+static const_tree
+get_field_with_name_unsafe (const_tree record, const char *identifier)
+{
+ gcc_assert (record);
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+ for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
+ {
+ const char *field_identifier = get_field_name (field);
+ const bool is_same_name = strcmp (field_identifier, identifier) == 0;
+ if (!is_same_name)
+ continue;
+
+ gcc_assert (TREE_CODE (field) == FIELD_DECL);
+ return field;
+ }
+ return NULL;
+}
+
+static const_tree
+get_field_with_name (const_tree record, const char *identifier)
+{
+ const_tree retval = get_field_with_name_unsafe (record, identifier);
+ gcc_assert (retval != NULL);
+ return retval;
+}
+
+static bool
+filter_out_boring_type (const_tree type, hash_set<const_tree> &map);
+
+inline static void
+is_record_p(const_tree record)
+{
+ gcc_assert(record);
+ const enum tree_code code = TREE_CODE(record);
+ const bool is_record = RECORD_TYPE == code;
+ gcc_assert(is_record);
+}
+
+struct cstrless {
+ bool operator()(const char* a, const char* b) { return strcmp(a, b) < 0; }
+};
+std::set<const char*, cstrless> interesting_records;
+std::set<const char*, cstrless> interesting_fields;
+std::set<const char*, cstrless> record_field_pair_name;
+std::set<const char*, cstrless> updated_functions;
+
+static bool
+is_interesting_struct_escape_analysis(const_tree record)
+{
+ is_record_p(record);
+ const_tree main_variant = TYPE_MAIN_VARIANT(record);
+ is_record_p(main_variant);
+ const char* const ob_type_name = get_type_name(main_variant);
+ const char* blacklist [5] = { "__gcov_fn_info", "__gcov_ctr_info", "__gcov_fn_info", "__gcov_info", "indirect_call_tuple" };
+ //const char* whitelist [4] = { "arc", "arc_t", "node", "node_t" };
+
+ for (int i = 0; i < 5; i++)
+ {
+ const bool is_blacklisted = strcmp(blacklist[i], ob_type_name) == 0;
+ if (is_blacklisted) return false;
+ }
+
+ /*
+ bool is_whitelisted = false;
+ for (int i = 0; i < 4; i++)
+ {
+ is_whitelisted |= strcmp(whitelist[i], ob_type_name) == 0;
+ }
+ if (!is_whitelisted) return false;
+ */
+
+
+ bool in_set =
+#if __cplusplus > 201703L
+ interesting_records.contains(get_type_name(main_variant))
+#else
+ interesting_records.find(get_type_name(main_variant)) != interesting_records.end()
+#endif
+ ;
+
+ in_set |=
+#if __cplusplus > 201703L
+ interesting_records.contains(get_type_name(record))
+#else
+ interesting_records.find(get_type_name(record)) != interesting_records.end()
+#endif
+ ;
+
+
+ log("is interesting struct ? %s\n", in_set ? "true" : "false");
+
+ return in_set;
+
+}
+
+static bool is_interesting_struct_manual(const_tree);
+
+static bool
+is_interesting_struct (const_tree record_1)
+{
+ const bool use_escape_analysis_info = !flag_ipa_typelist_struct && !flag_ipa_typelist_field;
+ return use_escape_analysis_info ? is_interesting_struct_escape_analysis(record_1) : is_interesting_struct_manual(record_1);
+}
+
+static bool
+is_interesting_pair (const char* pair_name)
+{
+ const bool use_escape_analysis_info = !flag_ipa_typelist_struct && !flag_ipa_typelist_field;
+ //TODO: If we are not in escape analysis we shouldn't be calling this function.
+ //We need to define a better interface for specifying record type and name to avoid
+ //having this problem.
+ if (!use_escape_analysis_info) return true;
+ const bool in_set =
+#if __cplusplus > 201703L
+ record_field_pair_name.contains(pair_name);
+#else
+ record_field_pair_name.find(pair_name) != record_field_pair_name.end()
+#endif
+ ;
+
+ log("is interesting pair? %s\n", in_set ? "true" : "false");
+
+ return in_set;
+}
+
+static bool
+is_interesting_struct_manual(const_tree record_1)
+{
+ is_record_p(record_1);
+
+ const_tree record = TYPE_MAIN_VARIANT(record_1);
+ is_record_p(record);
+
+ const char *record_name = get_type_name (record);
+ const int buffer_size = 1024;
+ char interesting_structs[buffer_size];
+ static const int cli_length = strlen (flag_ipa_typelist_struct);
+ gcc_assert (cli_length < buffer_size);
+ strcpy (interesting_structs, flag_ipa_typelist_struct);
+ bool retval = false;
+ char *save_ptr;
+ char *token = strtok_r (interesting_structs, ",", &save_ptr);
+ while (token)
+ {
+ retval |= strcmp (record_name, token) == 0;
+ token = strtok_r (NULL, ",", &save_ptr);
+ if (retval) break;
+ }
+
+
+ return retval;
+}
+
+
+inline static void
+is_field_decl_p(const_tree field)
+{
+ gcc_assert(field);
+ const enum tree_code code = TREE_CODE(field);
+ const bool is_field = FIELD_DECL == code;
+ gcc_assert(is_field);
+}
+
+static bool
+is_interesting_field_manual (const_tree field)
+{
+ log ("HERE HERE %s\n", get_type_name(field));
+ is_field_decl_p(field);
+
+ const char *field_name = get_field_name (field);
+ const int buffer_size = 1024;
+ char interesting_fields[buffer_size];
+ static const int cli_length = strlen (flag_ipa_typelist_field);
+ gcc_assert (cli_length < buffer_size);
+ strcpy (interesting_fields, flag_ipa_typelist_field);
+ bool retval = false;
+ char *save_ptr;
+ char *token = strtok_r (interesting_fields, ",", &save_ptr);
+ while (token)
+ {
+ retval |= strcmp (field_name, token) == 0;
+ token = strtok_r (NULL, ",", &save_ptr);
+ }
+ return retval;
+}
+
+static bool
+is_interesting_field_escape_analysis(const_tree field)
+{
+ is_field_decl_p(field);
+
+ const char* field_name = get_field_name(field);
+ /*
+ const char* whitelist [2] = { "nextin", "nextout" };
+
+ bool is_whitelisted = false;
+ for (int i = 0; i < 2; i++)
+ {
+ is_whitelisted |= strcmp(whitelist[i], field_name) == 0;
+ }
+ if (!is_whitelisted) return false;
+ */
+
+ const bool in_set =
+#if __cplusplus > 201703L
+ interesting_fields.contains(field_name);
+#else
+ interesting_fields.find(field_name) != interesting_fields.end()
+#endif
+ ;
+
+ log("is interesting field? %s\n", in_set ? "true" : "false");
+
+ return in_set;
+}
+
+static bool
+is_interesting_field (const_tree field)
+{
+ const bool use_escape_analysis_info = !flag_ipa_typelist_struct && !flag_ipa_typelist_field;
+ return use_escape_analysis_info ? is_interesting_field_escape_analysis(field) : is_interesting_field_manual(field);
+}
+
+static bool
+filter_out_boring_record (const_tree record, hash_set<const_tree> &map)
+{
+ test_log ("filter_out_boring_record", 0);
+ enum tree_code code = TREE_CODE (record);
+ gcc_assert (code == RECORD_TYPE);
+
+ for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
+ {
+ tree field_type = TREE_TYPE (field);
+ enum tree_code field_code = TREE_CODE (field);
+ test_log ("filter_out_boring_field %s %s", 0, get_type_name (field_type),
+ get_tree_code_name (field_code));
+ bool is_boring = filter_out_boring_type (field_type, map);
+ if (!is_boring)
+ return false;
+ }
+
+ return !is_interesting_struct (record);
+}
+
+static bool
+filter_out_boring_pointer (const_tree pointer, hash_set<const_tree> &map)
+{
+ test_log ("filter_out_boring_pointer", 0);
+ enum tree_code code = TREE_CODE (pointer);
+ gcc_assert (code == POINTER_TYPE);
+ const_tree base_type = get_base_type_from_pointer_type (pointer);
+ return filter_out_boring_type (base_type, map);
+}
+
+static bool
+filter_out_boring_array (const_tree array, hash_set<const_tree> &map)
+{
+ enum tree_code code = TREE_CODE (array);
+ gcc_assert (code == ARRAY_TYPE);
+ const_tree base_type = get_base_type_from_array_type (array);
+ return filter_out_boring_type (base_type, map);
+}
+
+static bool
+filter_out_boring_reference (const_tree ref, hash_set<const_tree> &map)
+{
+ gcc_unreachable();
+ enum tree_code code = TREE_CODE (ref);
+ gcc_assert (code == REFERENCE_TYPE);
+ test_log ("in filter out boring reference", 0);
+ bool retval = filter_out_boring_type (TREE_TYPE (ref), map);
+ if (retval)
+ {
+ test_log ("we are getting a reference", 0);
+ }
+ return retval;
+}
+
+static bool
+filter_out_boring_type (const_tree type, hash_set<const_tree> &map)
+{
+ if (!type)
+ {
+ test_log ("filter_out_boring_type (NULL)", 0);
+ return true;
+ }
+
+ // maybe something like, if the type is
+ // equivalent to one of the already
+ // interesting types, then it should
+ // also be interesting..?
+ // But then, imagine this happens out of order...
+ // We get type A which is non-interesting
+ // type A is equivalent to B
+ // then we receive type B which is interesting
+ // this approach would fail...
+
+ enum tree_code code = TREE_CODE (type);
+ bool retval = true;
+ switch (code)
+ {
+ case ARRAY_TYPE:
+ retval = filter_out_boring_array (type, map);
+ break;
+ case POINTER_TYPE:
+ retval = filter_out_boring_pointer (type, map);
+ break;
+ case RECORD_TYPE:
+ retval = filter_out_boring_record (type, map);
+ break;
+ case REFERENCE_TYPE:
+ retval = filter_out_boring_reference (type, map);
+ break;
+ default:
+ {
+ test_log ("default in tree code %s", 0, get_tree_code_name (code));
+ retval = true;
+ }
+ break;
+ }
+
+ if (!retval)
+ {
+ test_log ("putting %s", 0, get_type_name (type));
+ map.add (type);
+ }
+ return retval;
+}
+
+static bool
+filter_var_decls (tree var_decl, hash_set<const_tree> &type_map)
+{
+ gcc_assert (var_decl);
+ gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
+ tree type = TREE_TYPE (var_decl);
+ return filter_out_boring_type (type, type_map);
+}
+
+static bool
+filter_parm_decls (tree parm_decl, hash_set<const_tree> &type_map)
+{
+ gcc_assert (parm_decl);
+ gcc_assert (TREE_CODE (parm_decl) == PARM_DECL);
+ tree type = TREE_TYPE (parm_decl);
+ return filter_out_boring_type (type, type_map);
+}
+
+static void
+collect_parm_declarations (cgraph_node *cnode,
+ bool (*filter) (tree, hash_set<const_tree> &),
+ hash_set<const_tree> &decl_map)
+{
+ gcc_assert (cnode);
+ // TODO: Do we need to get_untransformed_body_here?
+ for (tree parm = DECL_ARGUMENTS (cnode->decl); parm; parm = DECL_CHAIN (parm))
+ {
+ bool filter_out = (*filter) (parm, decl_map);
+ if (filter_out)
+ continue;
+
+ tree type = TREE_TYPE (parm);
+ bool is_inside = decl_map.contains (type);
+ // We already have this type.
+ if (is_inside)
+ continue;
+
+ //const char *type_identifier = get_type_name (type);
+ //test_log ("collecting,%s", 0, type_identifier);
+ decl_map.add (type);
+ }
+}
+
+static void
+collect_pointer_plus (tree lhs, tree rhs1, tree rhs2,
+ hash_set<const_tree> &decl_map)
+{
+ tree lhs_type = lhs ? TREE_TYPE (lhs) : NULL;
+ bool is_lhs_boring
+ = lhs_type ? filter_out_boring_type (lhs_type, decl_map) : true;
+ tree rhs1_type = rhs1 ? TREE_TYPE (rhs1) : NULL;
+ bool is_rhs1_boring
+ = rhs1_type ? filter_out_boring_type (rhs1_type, decl_map) : true;
+ tree rhs2_type = rhs2 ? TREE_TYPE (rhs2) : NULL;
+ bool is_rhs2_boring
+ = rhs2_type ? filter_out_boring_type (rhs2_type, decl_map) : true;
+
+ if (!is_lhs_boring)
+ {
+ test_log ("putting lhs %s", 0, get_type_name (lhs_type));
+ decl_map.add (lhs_type);
+ }
+ if (!is_rhs1_boring)
+ {
+ test_log ("putting rhs1 %s", 0, get_type_name (rhs1_type));
+ decl_map.add (rhs1_type);
+ }
+ if (!is_rhs2_boring)
+ {
+ test_log ("putting rhs2 %s", 0, get_type_name (rhs2_type));
+ decl_map.add (rhs2_type);
+ }
+}
+
+static void
+collect_assign_rhs (gimple *stmt, hash_set<const_tree> &decl_map)
+{
+ enum tree_code code = gimple_expr_code (stmt);
+ switch (code)
+ {
+ case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
+ case COMPONENT_REF:
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ collect_pointer_plus (lhs, rhs1, rhs2, decl_map);
+ }
+ break;
+ default:
+ {
+ //print_gimple_stmt (dump_file, stmt, 0);
+ test_log ("DEFAULT HERE: %s", 0, get_tree_code_name (code));
+ }
+ break;
+ }
+}
+
+static void
+collect_assign (gimple *stmt, hash_set<const_tree> &decl_map)
+{
+ gcc_assert (stmt);
+ collect_assign_rhs (stmt, decl_map);
+}
+
+static void
+collect_stmt (gimple *stmt, hash_set<const_tree> &decl_map)
+{
+ gcc_assert (stmt);
+ const enum gimple_code code = gimple_code (stmt);
+ switch (code)
+ {
+ case GIMPLE_ASSIGN:
+ collect_assign (stmt, decl_map);
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+static void
+collect_basic_block (basic_block bb, hash_set<const_tree> &decl_map)
+{
+ gcc_assert (bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ collect_stmt (stmt, decl_map);
+ }
+}
+
+static void
+collect_function_body (cgraph_node *cnode, hash_set<const_tree> &decl_map)
+{
+ gcc_assert (cnode);
+ cnode->get_untransformed_body ();
+ basic_block bb = NULL;
+ function *func = DECL_STRUCT_FUNCTION (cnode->decl);
+ push_cfun (func);
+ FOR_EACH_BB_FN (bb, func)
+ {
+ collect_basic_block (bb, decl_map);
+ }
+ pop_cfun ();
+ print_function (cnode);
+}
+
+static void
+collect_local_declarations (cgraph_node *cnode,
+ bool (*filter) (tree, hash_set<const_tree> &),
+ hash_set<const_tree> &decl_map)
+{
+ gcc_assert (cnode);
+ int i = 0;
+ function *func = DECL_STRUCT_FUNCTION (cnode->decl);
+ cnode->get_untransformed_body ();
+ tree var_decl = NULL;
+ FOR_EACH_LOCAL_DECL (func, i, var_decl)
+ {
+ bool filter_out = (*filter) (var_decl, decl_map);
+ if (filter_out)
+ continue;
+
+ tree type = TREE_TYPE (var_decl);
+ //const char *type_identifier = get_type_name (type);
+ //test_log ("collecting,%s", 0, type_identifier);
+ decl_map.add (type);
+ }
+}
+
+static void
+collect_global_declaration (varpool_node *vnode,
+ bool (*filter) (tree, hash_set<const_tree> &),
+ hash_set<const_tree> &decl_map)
+{
+ test_log ("collect global declarations", 0);
+ int i;
+ struct ipa_ref *ref;
+
+ /* Only IPA_REF_STORE and IPA_REF_LOAD left. */
+ for (i = 0; vnode->iterate_referring (i, ref); i++)
+ {
+ bool filter_out = (*filter) (vnode->decl, decl_map);
+ if (filter_out)
+ {
+ test_log ("filter out", 0);
+ continue;
+ }
+
+ tree type = TREE_TYPE (vnode->decl);
+ //const char *type_identifier = get_type_name (type);
+ //test_log ("collecting,%s", 0, type_identifier);
+ decl_map.add (type);
+ }
+}
+
+static void
+collect_global_declarations (bool (*filter) (tree,
+ hash_set<const_tree> &),
+ hash_set<const_tree> &decl_map)
+{
+ varpool_node *vnode;
+ FOR_EACH_VARIABLE (vnode)
+ {
+ collect_global_declaration (vnode, filter, decl_map);
+ }
+}
+
+static void
+collect_orig_structs (hash_set<const_tree> &type_map)
+{
+ collect_global_declarations (&filter_var_decls, type_map);
+
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION (cnode)
+ {
+ print_function (cnode);
+ collect_parm_declarations (cnode, &filter_parm_decls, type_map);
+ collect_function_body (cnode, type_map);
+ collect_local_declarations (cnode, &filter_var_decls, type_map);
+ }
+}
+
+static const_tree
+make_new_type_based_on_old (const_tree old,
+ t_map *mod_type_map);
+
+static const_tree
+get_new_type_main_variant (const_tree old, t_map *mod_type_map)
+{
+ const_tree old_type_main_variant = TYPE_MAIN_VARIANT(old);
+ gcc_assert(old != old_type_main_variant);
+ delete_info_t *ptr = mod_type_map->get (TYPE_MAIN_VARIANT(old_type_main_variant));
+ if (ptr) {
+ const_tree retval = TYPE_MAIN_VARIANT(ptr->new_record);
+ return ptr->new_record;
+ }
+
+ const_tree new_main_variant_record = make_new_type_based_on_old(old_type_main_variant, mod_type_map);
+ return new_main_variant_record;
+}
+
+static const_tree
+make_new_record_based_on_typedef (const_tree _typedef, t_map *mod_type_map)
+{
+ log("make_new_record_based_on_typedef\n");
+ bool is_typedef = _typedef != TYPE_MAIN_VARIANT(_typedef);
+ gcc_assert(is_typedef);
+ tree new_main_variant = (tree) get_new_type_main_variant(_typedef, mod_type_map);
+ tree new_type = build_type_variant(new_main_variant, TYPE_READONLY(_typedef), TYPE_VOLATILE(_typedef));
+ const char *new_name = make_record_name_based_on_old (_typedef);
+ tree new_record_name = get_identifier (new_name);
+ TYPE_NAME (new_type) = new_record_name;
+ layout_type(new_type);
+
+ delete_info_t* info = mod_type_map->get(TYPE_MAIN_VARIANT(_typedef));
+ gcc_assert(info);
+ delete_info_t new_info;
+ new_info.old_record = _typedef;
+ new_info.new_record = new_type;
+ new_info.deleted_fields = info->deleted_fields;
+ mod_type_map->put (_typedef, new_info);
+ return new_type;
+}
+
+/*
+ * This method will copy the parameter
+ * and delete the field named "delete_me"
+ * int the copy. The offsets will be adjusted
+ * to account for the deleted parameter
+ */
+static const_tree
+make_new_record_based_on_old (const_tree old,
+ t_map *mod_type_map)
+{
+ log("make_new_record_based_on_old\n %s", get_type_name(old));
+ delete_info_t* info = mod_type_map->get(old);
+ const_tree *new_record_ptr = info ? &(info->new_record) : NULL;
+
+ gcc_assert (!new_record_ptr);
+
+ bool is_typedef = old != TYPE_MAIN_VARIANT(old);
+ if (is_typedef) { return make_new_record_based_on_typedef(old, mod_type_map); }
+
+ bool will_definitely_change = is_interesting_struct (old);
+
+ tree new_record = make_node (RECORD_TYPE);
+ const char *new_name = make_record_name_based_on_old (old);
+ tree new_record_name = get_identifier (new_name);
+ TYPE_NAME (new_record) = new_record_name;
+ hash_set<const_tree> *deleted_fields = new hash_set<const_tree> ();
+
+ tree prev_new_field = NULL;
+ for (tree old_field = TYPE_FIELDS (old); old_field;
+ old_field = DECL_CHAIN (old_field))
+ {
+
+ const bool are_field_names_equal = is_interesting_field (old_field);
+ log("am i deleting field %s ? %s\n", get_field_name(old_field), will_definitely_change && are_field_names_equal ? "true" : "false");
+ if (will_definitely_change && are_field_names_equal)
+ {
+ char *buffer;
+ char *buffer2;
+ asprintf(&buffer, "%s.%s", get_type_name(old), get_field_name(old_field));
+ asprintf(&buffer2, "%s.%s", get_type_name(TYPE_MAIN_VARIANT(old)), get_field_name(old_field));
+ log("buffer %s\n", buffer);
+ log("buffer2 %s\n", buffer2);
+ if (is_interesting_pair(buffer) || is_interesting_pair(buffer2))
+ {
+ deleted_fields->add(old_field);
+ continue;
+ }
+ }
+
+ tree new_field = make_node (FIELD_DECL);
+ DECL_NAME (new_field) = DECL_NAME (old_field);
+ tree old_field_type = TREE_TYPE (old_field);
+ const_tree new_field_type
+ = make_new_type_based_on_old (TREE_TYPE (old_field), mod_type_map);
+ test_log ("inside making new field, %s %s", 0,
+ get_type_name (old_field_type), get_type_name (new_field_type));
+ const_tree maybe_new_field
+ = new_field_type == old_field ? old_field : new_field_type;
+ substitute_type(new_field, maybe_new_field);
+ DECL_SOURCE_LOCATION (new_field) = DECL_SOURCE_LOCATION (old_field);
+ SET_DECL_ALIGN (new_field, DECL_ALIGN (old_field));
+ DECL_USER_ALIGN (new_field) = DECL_ALIGN (old_field);
+ TREE_ADDRESSABLE (new_field) = TREE_ADDRESSABLE (old_field);
+ DECL_NONADDRESSABLE_P (new_field) = !TREE_ADDRESSABLE (old_field);
+ TREE_THIS_VOLATILE (new_field) = TREE_THIS_VOLATILE (old_field);
+ // DECL_FIELD_OFFSET and DECL_FIELD_BIT_OFFSET
+ // are actually set by layout_type.
+ const bool first_new_field = !prev_new_field;
+ if (first_new_field)
+ {
+ TYPE_FIELDS (new_record) = new_field;
+ }
+ else
+ {
+ DECL_CHAIN (prev_new_field) = new_field;
+ }
+
+ prev_new_field = new_field;
+ }
+
+ layout_type (new_record);
+ tree new_type = build_type_variant(new_record, TYPE_READONLY(old), TYPE_VOLATILE(old));
+ layout_type (new_type);
+
+
+ for (tree new_field = TYPE_FIELDS (new_record); new_field;
+ new_field = DECL_CHAIN (new_field))
+ {
+ const char *new_field_name = get_field_name (new_field);
+ int new_offset = get_field_offset (new_field);
+ test_log ("offset,%s,%s,%d", 0, new_name, new_field_name, new_offset);
+ }
+
+ delete_info_t new_info;
+ new_info.old_record = old;
+ new_info.new_record = new_record;
+ new_info.deleted_fields = deleted_fields;
+ mod_type_map->put (old, new_info);
+ return new_record;
+}
+
+const_tree
+make_new_array_based_on_old (const_tree old_type,
+ t_map *mod_type_map)
+{
+ gcc_assert (TREE_CODE (old_type) == ARRAY_TYPE);
+ delete_info_t *delete_info_1 = mod_type_map->get(old_type);
+ const_tree *new_type_ptr = delete_info_1 ? &(delete_info_1->new_record) : NULL;
+ gcc_assert (!new_type_ptr);
+
+ const char *ptr = make_array_name_based_on_old (old_type);
+ tree new_array = make_node (ARRAY_TYPE);
+ TYPE_NAME (new_array) = get_identifier (ptr);
+ TYPE_DOMAIN (new_array) = TYPE_DOMAIN (old_type);
+ tree old_array_type = TREE_TYPE (old_type);
+ const_tree possibly_new
+ = make_new_type_based_on_old (old_array_type, mod_type_map);
+ if (possibly_new == old_array_type)
+ return old_type;
+ substitute_type(new_array, possibly_new);
+ layout_type (new_array);
+
+ delete_info *ptr_2 = mod_type_map->get (old_type);
+ if (ptr_2)
+ return ptr_2->new_record;
+
+ //HERE HERE
+ // struct delete_info { const_tree old_record; const_tree new_record; field_set* deleted_fields;};
+ delete_info_t delete_info;
+ delete_info.old_record = old_type;
+ delete_info.new_record = new_array;
+ delete_info.deleted_fields = NULL;
+ mod_type_map->put (old_type, delete_info);
+
+ return new_array;
+}
+
+static const_tree
+make_new_pointer_based_on_old (const_tree old,
+ t_map *mod_type_map)
+{
+ test_log ("make_new_pointer_based_on_old %s", 0, get_type_name (old));
+ delete_info_t *delete_info_1 = mod_type_map->get(old);
+ const_tree *already_computed = delete_info_1 ? &(delete_info_1->new_record) : NULL;
+ gcc_assert (!already_computed);
+
+ gcc_assert (TREE_CODE (old) == POINTER_TYPE);
+
+ tree new_pointer = make_node (POINTER_TYPE);
+ const char *ptr = make_pointer_name_based_on_old (old);
+
+ TYPE_NAME (new_pointer) = get_identifier (ptr);
+ SET_TYPE_MODE (new_pointer, TYPE_MODE (old));
+ tree old_type = TREE_TYPE (old);
+ gcc_assert (old_type);
+ const_tree new_type = make_new_type_based_on_old (old_type, mod_type_map);
+ // We do not need it...
+ if (new_type == old_type)
+ return old;
+
+ substitute_type(new_pointer, new_type);
+ layout_type (new_pointer);
+
+ delete_info_t *ptr_2 = mod_type_map->get (old);
+ if (ptr_2)
+ return ptr_2->new_record;
+
+ //HERE HERE
+ // struct delete_info { const_tree old_record; const_tree new_record; field_set* deleted_fields;};
+ delete_info_t delete_info;
+ delete_info.old_record = old;
+ delete_info.new_record = new_pointer;
+ delete_info.deleted_fields = NULL;
+ mod_type_map->put (old, delete_info);
+ test_log ("putting %s %s", 0, get_type_name (old),
+ get_type_name (new_pointer));
+ return new_pointer;
+}
+
+static const_tree
+make_new_type_based_on_old (const_tree old,
+ t_map *mod_type_map)
+{
+ if (!old)
+ return old;
+
+ gcc_assert (old);
+ delete_info_t *delete_info = mod_type_map->get (old);
+ const_tree *new_base_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (new_base_ptr)
+ return *new_base_ptr;
+
+ switch (TREE_CODE (old))
+ {
+ case ARRAY_TYPE:
+ return make_new_array_based_on_old (old, mod_type_map);
+ break;
+ case POINTER_TYPE:
+ return make_new_pointer_based_on_old (old, mod_type_map);
+ break;
+ case RECORD_TYPE:
+ return make_new_record_based_on_old (old, mod_type_map);
+ break;
+ default:
+ return old;
+ break;
+ }
+ gcc_unreachable ();
+ return NULL;
+}
+
+// Non-null values for type_map
+// will be the modified tree.
+bool
+compute_modified_structs_internal (
+ const_tree const &old_type,
+ t_map *mod_type_map)
+{
+ delete_info_t *ptr = mod_type_map->get (old_type);
+ // already in map
+ if (ptr)
+ return true;
+
+ const char *identifier = get_type_name (old_type);
+ test_log ("modifying,%s", 0, identifier);
+
+ const_tree new_record = make_new_type_based_on_old (old_type, mod_type_map);
+ // We might have modified the mod_type_map inside make_new_type_based_on_old
+ // and therefore we no longer have the need to store this there again...
+ delete_info_t *ptr_2 = mod_type_map->get (old_type);
+ if (ptr_2)
+ return true;
+
+ test_log ("new_name,%s", 0, get_type_name (new_record));
+ //HERE HERE
+ // struct delete_info { const_tree old_record; const_tree new_record; field_set* deleted_fields;};
+ delete_info_t delete_info;
+ delete_info.new_record = new_record;
+ delete_info.old_record = old_type;
+ delete_info.deleted_fields = NULL;
+ mod_type_map->put (old_type, delete_info);
+ return true;
+}
+
+static void
+compute_modified_structs (hash_set<const_tree> &type_map,
+ t_map &mod_type_map)
+{
+ type_map.traverse< t_map *,
+ compute_modified_structs_internal> (&mod_type_map);
+}
+
+static bool
+rewrite_constructor_def (tree expr, t_map &type_map,
+ const int indent)
+{
+ // These nodes represent the brace initializers
+ // for a structure or an array. They contain
+ // a sequence of component values made out of a vector
+ // of constructor_elt, which is a (INDEX, VALUE) pair.
+ tree old_rhs_type = TREE_TYPE (expr);
+ delete_info_t *delete_info = type_map.get (old_rhs_type);
+ const_tree *new_rhs_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (!new_rhs_type_ptr)
+ return false;
+
+ substitute_type(expr, new_rhs_type_ptr);
+
+ tree new_type = TREE_TYPE (expr);
+ // If the TREE_TYPE of the CONSTRUCTOR is a RECORD_TYPE
+ // UNION_TYPE or QUAL_UNION_TYPE, then the INDEX of each node
+ // in the sequence will be a FIELD_DECL and the VALUE will be the
+ // expression used to initialize that field.
+ // If TREE_TYPE of the CONSTRUCTOR is an ARRAY_TYPE, then
+ // the INDEX of each node in the sequence will be an INTEGER_CST
+ // or a RANGE_EXPR of two INTEGER_CSTs.
+ if (TREE_CLOBBER_P (expr))
+ return true;
+
+ enum tree_code code = TREE_CODE (new_type);
+ bool is_record = code == RECORD_TYPE;
+ bool is_union = code == UNION_TYPE;
+ bool is_qual = code == QUAL_UNION_TYPE;
+ bool is_array = code == ARRAY_TYPE;
+ bool is_interesting = is_record || is_union || is_qual || is_array;
+ if (!is_interesting)
+ return true;
+
+ // We have not tested this with other types...
+ gcc_assert (is_record);
+ // FIXME, we would need some time to rewrite the
+ // API to allow gimple_stmt_iterator be passed
+ // around all rewrite expressions...
+ // or something like that.
+ // Since not a lot of code uses this syntax,
+ // let's avoid it for now. But make a note
+ // we still need to fix this.
+ gcc_unreachable ();
+
+ unsigned i;
+ tree val;
+ FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (expr), i, val)
+ {
+ rewrite_expr (val, type_map, indent + 4);
+ }
+
+ return true;
+}
+
+static bool
+rewrite_field_decl_def (tree expr, t_map &type_map,
+ __attribute__((unused)) const int indent)
+{
+ tree old_rhs_type = TREE_TYPE (expr);
+ delete_info_t *delete_info = type_map.get(old_rhs_type);
+ const_tree *new_rhs_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (!new_rhs_type_ptr)
+ return false;
+
+ substitute_type(expr, new_rhs_type_ptr);
+ gcc_assert (TREE_OPERAND (expr, 0) == NULL);
+ return true;
+}
+
+static bool
+rewrite_integer_cst_def (tree expr, t_map &type_map,
+ __attribute__((unused)) const int indent)
+{
+ tree old_rhs_type = TREE_TYPE (expr);
+ delete_info_t *delete_info = type_map.get (old_rhs_type);
+ const_tree *new_rhs_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (!new_rhs_type_ptr)
+ return false;
+
+ substitute_type(expr, new_rhs_type_ptr);
+ return true;
+}
+
+static void
+rewrite_function_parms (tree expr, t_map &type_map,
+ const int indent);
+static void
+rewrite_function_return_type (tree expr,
+ t_map &type_map,
+ const int indent);
+
+static bool
+rewrite_function_decl_def (tree expr,
+ t_map &type_map,
+ const int indent)
+{
+ rewrite_function_parms (expr, type_map, indent + 4);
+ rewrite_function_return_type (expr, type_map, indent + 4);
+ return false;
+}
+
+static bool
+rewrite_component_ref_def_lhs (gimple_stmt_iterator &gsi, tree expr, t_map &type_map, const int indent)
+{
+ gcc_assert (expr);
+ tree expr_type = TREE_TYPE (expr);
+ gcc_assert (expr_type);
+ delete_info_t *delete_info1 = type_map.get (expr_type);
+ delete_info1 = delete_info1 ? delete_info1 : type_map.get (TYPE_MAIN_VARIANT(expr_type));
+ const_tree *new_expr_type_ptr = delete_info1 ? &(delete_info1->new_record) : NULL;
+
+ tree _struct = TREE_OPERAND (expr, 0);
+ gcc_assert (_struct);
+ tree _struct_type = TREE_TYPE (_struct);
+
+
+ gcc_assert (_struct_type);
+ const enum tree_code code = TREE_CODE(_struct_type);
+ const bool is_record = RECORD_TYPE == code;
+ //TODO: Handle unions better
+ switch (code)
+ {
+ case UNION_TYPE: return false; break;
+ case RECORD_TYPE: break;
+ default: gcc_unreachable(); break;
+ }
+ gcc_assert(is_record);
+
+ delete_info_t *delete_info = type_map.get (_struct_type);
+ delete_info = delete_info ? delete_info : type_map.get (TYPE_MAIN_VARIANT(_struct_type));
+ const_tree *new_struct_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+
+ if (new_expr_type_ptr)
+ substitute_type(expr, new_expr_type_ptr);
+
+ bool retval = rewrite_expr (_struct, type_map, indent);
+
+ tree new_type
+ = new_struct_type_ptr ? const_to_tree(*new_struct_type_ptr) : _struct_type;
+ tree field_decl = TREE_OPERAND (expr, 1);
+ bool has_been_deleted = delete_info ? delete_info->deleted_fields->contains(field_decl) : false;
+ if (has_been_deleted)
+ {
+ const char *field_name = get_field_name (field_decl);
+ test_log("we are removing field %s from struct %s", 0, field_name, get_type_name(delete_info->old_record));
+ return true;
+ }
+
+
+ const char *field_name = get_field_name (field_decl);
+ if (strcmp (field_name, "anonymous") == 0)
+ return false;
+
+
+ const_tree new_field = get_field_with_name (new_type, field_name);
+ // INFO: We need to rewrite the whole operand
+ // not just its type.
+ // INFO: When rewriting an operand we **must**
+ // be in -flto-partition=none
+ // INFO: setting the type and calling relayout_decl
+ // doesn't work.
+ // TODO: FIXME: In order to remove this assertion
+ // you need to use clones.
+ gcc_assert (in_lto_p && !flag_ltrans && !flag_wpa);
+ TREE_OPERAND (expr, 1) = const_to_tree(new_field);
+ int offset = get_field_offset (new_field);
+ test_log ("rewrite,field_offset,%s,%d", indent, field_name, offset);
+ gcc_assert (TREE_OPERAND (expr, 2) == NULL);
+
+ return false;
+}
+
+static bool
+rewrite_component_ref_def (tree expr,
+ t_map &type_map,
+ const int indent)
+{
+ gcc_assert (expr);
+ tree expr_type = TREE_TYPE (expr);
+ gcc_assert (expr_type);
+
+ delete_info_t *delete_info1 = type_map.get (expr_type);
+ const_tree *new_expr_type_ptr = delete_info1 ? &(delete_info1->new_record) : NULL;
+ if (new_expr_type_ptr)
+ substitute_type(expr, new_expr_type_ptr);
+
+ tree _struct = TREE_OPERAND (expr, 0);
+ gcc_assert (_struct);
+ tree _struct_type = TREE_TYPE (_struct);
+ gcc_assert (_struct_type);
+ const enum tree_code code = TREE_CODE(_struct_type);
+ const bool is_record = RECORD_TYPE == code;
+ //TODO: Handle unions better
+ switch (code)
+ {
+ case UNION_TYPE: return false; break;
+ case RECORD_TYPE: break;
+ default: gcc_unreachable(); break;
+ }
+ gcc_assert(is_record);
+ delete_info_t *delete_info = type_map.get (_struct_type);
+ const_tree *new_struct_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+
+ bool retval = rewrite_expr (_struct, type_map, indent);
+
+ tree new_type
+ = new_struct_type_ptr ? const_to_tree(*new_struct_type_ptr) : _struct_type;
+ tree field_decl = TREE_OPERAND (expr, 1);
+ bool has_been_deleted = delete_info ? delete_info->deleted_fields->contains(field_decl) : false;
+ if (has_been_deleted)
+ {
+ gcc_unreachable();
+ return false;
+ }
+
+ const char *field_name = get_field_name (field_decl);
+ if (strcmp (field_name, "anonymous") == 0)
+ return retval;
+
+ const_tree new_field = get_field_with_name (new_type, field_name);
+ // INFO: We need to rewrite the whole operand
+ // not just its type.
+ // INFO: When rewriting an operand we **must**
+ // be in -flto-partition=none
+ // INFO: setting the type and calling relayout_decl
+ // doesn't work.
+ // TODO: FIXME: In order to remove this assertion
+ // you need to use clones.
+ gcc_assert (in_lto_p && !flag_ltrans && !flag_wpa);
+ TREE_OPERAND (expr, 1) = const_to_tree(new_field);
+ int offset = get_field_offset (new_field);
+ test_log ("rewrite,field_offset,%s,%d", indent, field_name, offset);
+ gcc_assert (TREE_OPERAND (expr, 2) == NULL);
+
+ return true;
+}
+
+static bool
+rewrite_addr_expr_def (tree expr, t_map &type_map,
+ const int indent)
+{
+ tree type = TREE_TYPE (expr);
+ gcc_assert (TREE_CODE (expr) == ADDR_EXPR);
+ delete_info_t *delete_info = type_map.get (type);
+ const_tree *new_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (new_type_ptr)
+ substitute_type(expr, new_type_ptr);
+ tree op0 = TREE_OPERAND (expr, 0);
+ bool retval = rewrite_expr (op0, type_map, indent);
+ // There isn't an operand here, but we also can't
+ // TREE_OPERAND(expr, 1)
+ // Accessing this won't fail.
+ return retval;
+}
+
+static bool
+rewrite_var_decl_def (tree expr, __attribute__((unused)) t_map &type_map,
+ __attribute__((unused)) const int indent)
+{
+ gcc_assert (TREE_CODE (expr) == VAR_DECL);
+ return false;
+}
+
+static bool
+rewrite_mem_ref_def (tree expr, t_map &type_map,
+ const int indent)
+{
+ // Do we need to modify this value so that we op1 and calculate a constant
+ // value?
+ gcc_assert (expr);
+ gcc_assert (TREE_CODE (expr) == MEM_REF);
+ tree type = TREE_TYPE (expr);
+
+ delete_info_t *delete_info = type_map.get (type);
+ delete_info = delete_info ? delete_info : type_map.get (TYPE_MAIN_VARIANT(type));
+ const_tree *new_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (new_type_ptr)
+ substitute_type(expr, new_type_ptr);
+
+ tree op0 = TREE_OPERAND (expr, 0);
+ // The first operand is the pointer being dereferenced
+ bool retval = rewrite_expr (op0, type_map, indent);
+ // The second operand is a pointer constant. Its type specifying the type
+ // to be used for type-based alias analysis.
+ tree op1 = TREE_OPERAND (expr, 1);
+ rewrite_expr (op1, type_map, indent);
+ gcc_assert (TREE_CODE (op1) == INTEGER_CST);
+ int old_offset = tree_to_uhwi (op1);
+ if (old_offset == 0 || !new_type_ptr)
+ return retval;
+
+ tree old_struct_size = TYPE_SIZE_UNIT (type);
+ int old_type_size_int = tree_to_shwi (old_struct_size);
+ test_log ("old_type = %s", 0, get_type_name (type));
+ test_log ("old_type_size = %ld", 0, tree_to_shwi (old_struct_size));
+ tree new_struct_size = TYPE_SIZE_UNIT (const_to_tree(*new_type_ptr));
+ int new_type_size_int = tree_to_shwi (new_struct_size);
+ int multiple = old_offset / old_type_size_int;
+ int offset = multiple * new_type_size_int;
+ int remainder = old_offset % old_type_size_int;
+ // FIXME: Do I need a way of mapping old_offsets to new_offsets...
+ // This seems insufficient.
+ // I need to know at which offset the discontinuity happens so that
+ // I can account for that.
+ // for now, we can only guarantee this transformation if
+ // old_offset is multiple of old_type_size_int;
+ int new_offset = offset + remainder;
+ if (new_offset == old_offset)
+ return retval;
+
+ tree new_offset_tree = build_int_cst (TREE_TYPE (op1), new_offset);
+ TREE_OPERAND (expr, 1) = new_offset_tree;
+ gcc_assert (old_offset % old_type_size_int == 0);
+
+ // TREE_OPERAND(expr, 2) cannot be accessed.
+ return retval;
+}
+
+static bool
+rewrite_ssa_name_def (tree expr, t_map &type_map,
+ __attribute__((unused)) const int indent)
+{
+ tree type = TREE_TYPE (expr);
+ tree ssa_name_var = SSA_NAME_VAR (expr);
+ delete_info_t *delete_info = type_map.get (type);
+ const_tree *new_type_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ tree new_type_2 = NULL;
+ if (new_type_ptr)
+ {
+ new_type_2 = build_type_variant(const_to_tree(*new_type_ptr), TYPE_READONLY(type), TYPE_VOLATILE(type));
+ substitute_type(expr, new_type_2);
+ // TODO: I had some cases where ssa_name_var was not set.
+ // Not sure why...
+ // I need to investigate
+ // Could this be the variables that I create?
+ // If so, then the temporary variables should have SSA_NAMES
+ // and there is something else that I need to change
+ if (ssa_name_var)
+ {
+ substitute_type(ssa_name_var, new_type_2);
+ relayout_decl (ssa_name_var);
+ }
+ }
+
+ return new_type_2;
+}
+
+static bool
+rewrite_bin_expr_default_def (tree expr,
+ t_map &type_map,
+ const int indent)
+{
+ gcc_assert (expr);
+ tree op0 = TREE_OPERAND (expr, 0);
+ tree op1 = TREE_OPERAND (expr, 1);
+ gcc_assert (op0 && op1);
+
+ bool retval = false;
+ retval |= rewrite_expr (op0, type_map, indent);
+ retval |= rewrite_expr (op1, type_map, indent);
+ // Why is this unreachable?
+ gcc_unreachable ();
+ gcc_assert (TREE_OPERAND (expr, 2) == NULL);
+
+ return retval;
+}
+
+
+static bool
+rewrite_array_ref_def (tree expr, t_map &type_map,
+ const int indent)
+{
+ gcc_assert (expr);
+ gcc_assert (TREE_CODE (expr) == ARRAY_REF);
+ tree type = TREE_TYPE (expr);
+ //const_tree *up_ptr = type_map.get (type);
+ delete_info_t *delete_info = type_map.get (type);
+ const_tree *up_ptr = delete_info ? &(delete_info->new_record) : NULL;
+ if (up_ptr)
+ substitute_type(expr, up_ptr);
+
+ rewrite_expr (TREE_OPERAND (expr, 0), type_map, indent + 4);
+ rewrite_expr (TREE_OPERAND (expr, 1), type_map, indent + 4);
+ gcc_assert (TREE_OPERAND (expr, 2) == NULL);
+
+ return true;
+}
+
+static void
+rewrite_pointer_diff_def_rhs_variable_replace_constants_implementation (
+ __attribute__((unused)) gimple_stmt_iterator &gsi, tree lhs, tree pointer, __attribute__((unused)) tree variable,
+ const_tree old_type)
+{
+ // We will need this later
+ tree old_type_size = TYPE_SIZE_UNIT (TREE_TYPE (old_type));
+ int old_type_size_int = tree_to_shwi (old_type_size);
+ // lhs = op0 - op1 // <-- we are here
+ // ... SNIP ...
+ // var = lhs / [ex] old_struct_size // <-- we want to be here
+ //
+ // Let's explore the uses of lhs
+
+ gimple *stmt;
+ imm_use_iterator iterator;
+ FOR_EACH_IMM_USE_STMT (stmt, iterator, lhs)
+ {
+ // stmt is a use of lhs
+ // gimple_expr_code is only valid for non-debug statements
+ bool is_debug = is_gimple_debug (stmt);
+ if (is_debug)
+ continue;
+
+ test_log ("is not debug", 0);
+ enum tree_code code = gimple_expr_code (stmt);
+ bool is_exact_div = code == EXACT_DIV_EXPR;
+ if (!is_exact_div)
+ continue;
+
+ test_log ("is exact div expr", 0);
+ tree divisor = gimple_op (stmt, 2);
+ enum tree_code divisor_code = TREE_CODE (divisor);
+ bool is_constant = divisor_code == INTEGER_CST;
+ if (!is_constant)
+ continue;
+
+ test_log ("is constant", 0);
+ int divisor_int = tree_to_shwi (divisor);
+ test_log ("size %d %d", 0, divisor_int, old_type_size_int);
+ bool is_same_size = divisor_int == old_type_size_int;
+ if (!is_same_size)
+ continue;
+
+ const_tree new_base_type = TREE_TYPE (TREE_TYPE (pointer));
+ tree new_struct_size_tree_1 = TYPE_SIZE_UNIT (new_base_type);
+ int new_struct_size_int = tree_to_shwi (new_struct_size_tree_1);
+ tree new_struct_size_const
+ = build_int_cst (TREE_TYPE (divisor), new_struct_size_int);
+ gimple_set_op (stmt, 2, new_struct_size_const);
+ }
+}
+
+static tree
+rewrite_pointer_plus_def_rhs_variable_replace_constants_implementation (
+ __attribute__((unused)) gimple_stmt_iterator &gsi, tree lhs, __attribute__((unused)) tree pointer, tree variable,
+ const_tree old_type)
+{
+ // We need to find the definition of the 3rd operand
+ // _1 = _0 * 72
+ // ... SNIP ...
+ // _2 = _1 + CONSTANT;
+ // ... SNIP ...
+ // _3 = &array + _2; < -- this is where we are
+ gcc_assert (TREE_CODE (variable) == SSA_NAME);
+ gimple *def_for_variable = SSA_NAME_DEF_STMT (variable);
+
+ // It is also possible that we are in a negation statement.
+ // Example:
+ // _2 = _1 * 72;
+ // ... SNIP ...
+ // _3 = -_2; < -- def_for_variable **might** be this stmt.
+ // ... SNIP ...
+ // _4 = &array + _3;
+ // Let's find out how many operands we have
+ unsigned num_operands = gimple_num_ops (def_for_variable);
+ test_log ("how many operands ? %d", 0, num_operands);
+ bool need_to_skip = num_operands == 2;
+ gimple *to_change = need_to_skip
+ ? SSA_NAME_DEF_STMT (gimple_op (def_for_variable, 1))
+ : def_for_variable;
+
+ // _2 = _1 * 72; <-- to change
+ // _3 = &array + _2;
+ enum tree_code code = gimple_expr_code (to_change);
+ const_tree old_base_type = TREE_TYPE (old_type);
+ tree old_struct_size_tree_1 = TYPE_SIZE_UNIT (old_base_type);
+ int old_struct_size_int = tree_to_shwi (old_struct_size_tree_1);
+ const_tree pointer_to_unit_type = TREE_TYPE (lhs);
+ const_tree unit_type = TREE_TYPE (pointer_to_unit_type);
+ tree new_struct_size_tree_1 = TYPE_SIZE_UNIT (unit_type);
+ int new_struct_size_int = tree_to_shwi (new_struct_size_tree_1);
+
+ if (code == PLUS_EXPR)
+ {
+ // If we are here it is because we are adding an offset.
+ // It is usually whenever we do somehting like
+ // _2 = _1 + CONSTANT; <-- to change
+ // _3 = &array + _2;
+ gcc_assert (code == PLUS_EXPR);
+
+ tree constant_plus = gimple_op (to_change, 2);
+ gcc_assert (TREE_CODE (constant_plus) == INTEGER_CST);
+
+ int old_unit_size_one_plus = tree_to_uhwi (constant_plus);
+ // This used to work for unprofiled code.
+ // However, with profiling, I guess we can jump wherever we want...
+ // So, we need to find out which field we were intending to access
+ // and where that field maps to the new struct...
+ // gcc_assert(is_modulo);
+
+ bool is_modulo_old = old_unit_size_one_plus % old_struct_size_int == 0;
+ bool is_modulo_new = old_unit_size_one_plus % new_struct_size_int == 0;
+ // If we are not in flag_profile_use
+ // we will always be a modulo
+ if (!flag_profile_use)
+ gcc_assert (is_modulo_old);
+
+ test_log ("old plus constant = %d", 0, old_unit_size_one_plus);
+ test_log ("old struct size int = %d", 0, old_struct_size_int);
+ test_log ("new struct size int = %d", 0, new_struct_size_int);
+ test_log ("old_unit_size_one_plus modulo new_struct_pointer_int = %d", 0,
+ old_unit_size_one_plus % new_struct_size_int);
+
+ // FIXME:
+ // The problem is that if flag_profile_use is enabled,
+ // then we can potentially **predict** the offset
+ // to be the correct one. But not always?
+ // Therefore, we really do not have an idea if we are using
+ // a value obtained from profiling or one from "correctness".
+ if (flag_profile_use)
+ {
+ bool is_from_profiling = is_modulo_new;
+ bool is_from_correctness = is_modulo_old;
+ gcc_assert (is_from_correctness || is_from_profiling);
+ }
+
+ int field_accessed_offset = old_unit_size_one_plus % old_struct_size_int;
+
+ if (flag_profile_use && is_modulo_new)
+ gcc_assert (field_accessed_offset != 0);
+
+ int new_plus_constant_int
+ = old_unit_size_one_plus / old_struct_size_int * new_struct_size_int
+ + field_accessed_offset;
+
+ if (flag_profile_use && is_modulo_new)
+ gcc_assert(field_accessed_offset % new_struct_size_int == 0);
+
+ tree new_plus_constant
+ = build_int_cst (TREE_TYPE (constant_plus), new_plus_constant_int);
+ gimple_set_op (to_change, 2, new_plus_constant);
+
+ // And now we need to get the defintion of _1
+ variable = gimple_op (to_change, 1);
+ gcc_assert (TREE_CODE (variable) == SSA_NAME);
+ def_for_variable = SSA_NAME_DEF_STMT (variable);
+ num_operands = gimple_num_ops (def_for_variable);
+ test_log ("how many operands ? %d", 0, num_operands);
+ need_to_skip = num_operands == 2;
+ to_change = need_to_skip
+ ? SSA_NAME_DEF_STMT (gimple_op (def_for_variable, 1))
+ : def_for_variable;
+ code = gimple_expr_code (to_change);
+ }
+
+ if (code == MULT_EXPR)
+ {
+ // How do we know what type we need to change?
+ // That is _3 (or lhs) is the result of the pointer arithmetic.
+ // So we need one level of dereference in order to find
+ // the underlying type.
+
+ // We need to get the second operand
+ test_print_gimple_stmt (to_change);
+ tree constant = gimple_op (to_change, 2);
+ gcc_assert (TREE_CODE (constant) == INTEGER_CST);
+
+ // We should have the same size...
+ // Is this always true?
+ // TODO: can we enable this assertion?
+ // int old_unit_size_one = tree_to_shwi (constant);
+ // gcc_assert(old_unit_size_one == old_struct_size_int);
+
+ // Now we need to modify the second operand...
+ tree new_constant
+ = build_int_cst (TREE_TYPE (constant), new_struct_size_int);
+ gimple_set_op (to_change, 2, new_constant);
+ }
+
+ return NULL;
+}
+
+static tree
+rewrite_pointer_plus_def_rhs_integer_constant (tree pointer,
+ tree integer_constant,
+ const_tree old_type)
+{
+ gcc_assert (TREE_CODE (integer_constant) == INTEGER_CST);
+ tree pointer_type = TREE_TYPE (pointer);
+ gcc_assert (TREE_CODE (pointer_type) == POINTER_TYPE);
+
+ const_tree base_type = TREE_TYPE (TREE_TYPE (pointer));
+
+ tree size = TYPE_SIZE_UNIT (base_type);
+ int new_struct_size = tree_to_shwi (size);
+ int old_offset = tree_to_uhwi (integer_constant);
+
+ const_tree old_base_type = TREE_TYPE (old_type);
+
+ tree old_type_size = TYPE_SIZE_UNIT (old_base_type);
+ int old_struct_size = tree_to_shwi (old_type_size);
+ int modulo = old_offset % old_struct_size;
+ test_log ("old_struct_size = %d", 0, old_struct_size);
+
+ tree integer_constant_type = TREE_TYPE (integer_constant);
+
+ int new_offset = old_offset / old_struct_size * new_struct_size;
+ tree new_constant = build_int_cst (integer_constant_type, new_offset);
+ return new_constant;
+}
+
+static bool
+rewrite_pointer_plus_def_rhs (gimple *stmt, gimple_stmt_iterator &gsi, tree lhs,
+ tree op0, tree op1,
+ t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (op0 && op1);
+ tree op0_type = TREE_TYPE (lhs);
+ //const_tree *new_op0_type = type_map.get (op0_type);
+ delete_info_t *delete_info = type_map.get (op0_type);
+ const_tree *new_op0_type = delete_info ? &(delete_info->new_record) : NULL;
+ test_log ("rewrite_pointer_plus has old_type %s", 0,
+ new_op0_type ? "true" : "false");
+ // gcc_assert(!new_op0_type);
+ test_log ("rewrite_pointer_plus op0_type %s", 0, get_type_name (op0_type));
+ if (new_op0_type)
+ test_log ("rewrite_pointer_plus new_op0_type %s", 0,
+ get_type_name (*new_op0_type));
+
+ rewrite_expr (op0, type_map, 0);
+ rewrite_expr (op1, type_map, 0);
+
+ const char *new_type_name
+ = new_op0_type ? get_type_name (*new_op0_type) : get_type_name (op0_type);
+
+ test_log ("rewrite_pointer_plus new_type_name %s", 0, new_type_name);
+ //const_tree *inverse_type_ptr = inverse.get (op0_type);
+ delete_info_t *delete_info_inverse = inverse.get(op0_type);
+ const_tree *inverse_type_ptr = delete_info_inverse ? &(delete_info_inverse->old_record) : NULL;
+ bool not_in_map_nor_inverse = !new_op0_type && !inverse_type_ptr;
+ test_log ("continuing? %s", 0, not_in_map_nor_inverse ? "false" : "true");
+ if (not_in_map_nor_inverse)
+ return false;
+
+ const_tree old_type
+ = new_op0_type ? (const_tree) op0_type : *inverse_type_ptr;
+ test_log ("what is the old_type name ? %s", 0, get_type_name (old_type));
+
+ bool is_op1_int_cst = TREE_CODE (op1) == INTEGER_CST;
+ tree integer_constant = is_op1_int_cst ? op1 : op0;
+ bool has_integer_constant = (TREE_CODE (integer_constant) == INTEGER_CST);
+
+ if (has_integer_constant)
+ {
+ // I want to know if this is an invariant.
+ // TODO: Outline
+ gcc_assert (TREE_CODE (op1) == INTEGER_CST);
+ tree pointer = is_op1_int_cst ? op0 : op1;
+ tree new_constant
+ = rewrite_pointer_plus_def_rhs_integer_constant (pointer,
+ integer_constant,
+ old_type);
+ unsigned int operand = is_op1_int_cst ? 2 : 1;
+ gimple_set_op (stmt, operand, new_constant);
+ return true;
+ }
+
+ tree variable = op1;
+ tree pointer = op0;
+ // I want to know if this is an invariant.
+ tree pointer_type = TREE_TYPE (pointer);
+ gcc_assert (TREE_CODE (pointer_type) == POINTER_TYPE);
+ tree new_variable
+ = rewrite_pointer_plus_def_rhs_variable_replace_constants_implementation (
+ gsi, lhs, pointer, variable, old_type);
+ if (!new_variable)
+ return false;
+ unsigned int operand
+ = TREE_CODE (TREE_TYPE (op0)) == POINTER_TYPE ? 2 : 1;
+ gimple_set_op (stmt, operand, new_variable);
+
+ return true;
+}
+
+static bool
+rewrite_pointer_diff_def_rhs (gimple_stmt_iterator &gsi, tree lhs,
+ tree op0, tree op1,
+ t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (op0 && op1);
+ tree op0_type = TREE_TYPE (lhs);
+ //const_tree *new_op0_type = type_map.get (op0_type);
+ delete_info_t *delete_info = type_map.get(op0_type);
+ const_tree *new_op0_type = delete_info ? &(delete_info->new_record) : NULL;
+ test_log ("rewrite_pointer_diff has old_type %s", 0,
+ new_op0_type ? "true" : "false");
+ test_log ("rewrite_pointer_diff op0_type %s", 0, get_type_name (op0_type));
+ if (new_op0_type)
+ test_log ("rewrite_pointer_diff new_op0_type %s", 0,
+ get_type_name (*new_op0_type));
+
+ rewrite_expr (op0, type_map, 0);
+ rewrite_expr (op1, type_map, 0);
+
+ const char *new_type_name
+ = new_op0_type ? get_type_name (*new_op0_type) : get_type_name (op0_type);
+ // TODO: I'd prefer to have a parameter
+ // that tells me what to change
+ // several stack frames above.
+ test_log ("rewrite_pointer_diff new_type_name %s", 0, new_type_name);
+ //const_tree *inverse_type_ptr = inverse.get (op0_type);
+ delete_info_t *delete_info_inverse = inverse.get (op0_type);
+ const_tree *inverse_type_ptr = delete_info_inverse ? &(delete_info_inverse->old_record) : NULL;
+ bool not_in_map_nor_inverse = !new_op0_type && !inverse_type_ptr;
+ test_log ("continuing? %s", 0, not_in_map_nor_inverse ? "false" : "true");
+ if (not_in_map_nor_inverse)
+ return false;
+
+ const_tree old_type
+ = new_op0_type ? (const_tree) op0_type : *inverse_type_ptr;
+
+ bool is_op1_int_cst = TREE_CODE (op1) == INTEGER_CST;
+ tree integer_constant = is_op1_int_cst ? op1 : op0;
+ bool has_integer_constant = (TREE_CODE (integer_constant) == INTEGER_CST);
+
+ // I want to know if this is an invariant.
+ if (has_integer_constant)
+ gcc_unreachable ();
+
+ // I want to know if this is an invariant.
+ gcc_assert (TREE_CODE (op0_type) == POINTER_TYPE);
+ rewrite_pointer_diff_def_rhs_variable_replace_constants_implementation (
+ gsi, lhs, op0, op1, old_type);
+
+ return true;
+}
+static bool
+rewrite_assign_rhs (gimple *stmt, gimple_stmt_iterator &gsi,
+ t_map &type_map,
+ t_map &inverse)
+{
+ // WONTFIX, It looks like there is no way to obtain
+ // the expression for the rhs. So instead, we have to do
+ // this hack.
+ // Which expressions can be toplevel?
+ bool is_stmt_rewritten = false;
+ enum tree_code code = gimple_expr_code (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ switch (TREE_CODE(lhs))
+ {
+ case COMPONENT_REF:
+ test_log(" I AM HERE HERE HERE", 0);
+ break;
+ default:
+ break;
+ }
+
+ switch (code)
+ {
+ case POINTER_PLUS_EXPR:
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ tree lhs_type = TREE_TYPE (lhs);
+ gcc_assert (lhs_type);
+ delete_info_t *delete_info = type_map.get (lhs_type);
+ gcc_assert (lhs && rhs2 && rhs1);
+ bool retval = rewrite_pointer_plus_def_rhs (stmt, gsi, lhs, rhs1, rhs2,
+ type_map, inverse);
+ if (delete_info)
+ substitute_type(lhs, delete_info->new_record);
+ return retval;
+ }
+ case POINTER_DIFF_EXPR:
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ tree lhs_type = TREE_TYPE (lhs);
+ gcc_assert (lhs_type);
+ delete_info_t *delete_info = type_map.get (lhs_type);
+ gcc_assert (lhs && rhs2 && rhs1);
+ bool retval = rewrite_pointer_diff_def_rhs (gsi, lhs, rhs1, rhs2,
+ type_map, inverse);
+ if (delete_info)
+ substitute_type(lhs, delete_info->new_record);
+ return retval;
+ }
+ break;
+ default:
+ {
+ //print_gimple_stmt (dump_file, stmt, 0);
+ test_log ("DEFAULT HERE: %s", 0, get_tree_code_name (code));
+ }
+ break;
+ }
+
+ switch (gimple_assign_rhs_class (stmt))
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ tree rhs3 = gimple_assign_rhs3 (stmt);
+ is_stmt_rewritten |= rewrite_expr (rhs3, type_map, 0);
+ }
+ /* fall through */
+ case GIMPLE_BINARY_RHS:
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ is_stmt_rewritten |= rewrite_expr (rhs2, type_map, 0);
+ }
+ /* fall through */
+ case GIMPLE_SINGLE_RHS:
+ case GIMPLE_UNARY_RHS:
+ {
+ tree rhs1 = gimple_assign_rhs1 (stmt);
+ is_stmt_rewritten |= rewrite_expr (rhs1, type_map, 0);
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ break;
+ }
+
+ return is_stmt_rewritten;
+}
+
+static void
+rewrite_call_lhs (gimple *stmt, __attribute__((unused)) gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ gcc_assert (stmt);
+ test_print_gimple_stmt (stmt);
+ tree lhs = gimple_call_lhs (stmt);
+ // LHS can be null. Example `foo()`
+ if (!lhs)
+ return;
+
+ rewrite_expr (lhs, type_map, 0);
+}
+
+static void
+rewrite_call_rhs (gimple *stmt, __attribute__((unused)) gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ gcc_assert (stmt);
+ tree fn = gimple_call_fn (stmt);
+ gcc_assert (fn);
+ gcall *call = dyn_cast<gcall *> (stmt);
+ tree return_type = gimple_call_return_type (call);
+ test_log ("what is the return type %s", 0, get_type_name (return_type));
+ gcc_assert (return_type);
+
+ unsigned args = gimple_call_num_args (stmt);
+ for (unsigned i = 0; i < args; i++)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ rewrite_expr (arg, type_map, 0);
+ }
+}
+
+static void
+rewrite_call (gimple *stmt, gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ rewrite_call_lhs (stmt, gsi, type_map);
+ rewrite_call_rhs (stmt, gsi, type_map);
+}
+
+static void
+rewrite_cond (gimple *stmt, __attribute((unused)) gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ tree lhs = gimple_cond_lhs (stmt);
+ tree rhs = gimple_cond_rhs (stmt);
+ rewrite_expr (lhs, type_map, 0);
+ rewrite_expr (rhs, type_map, 0);
+}
+
+static void
+rewrite_phi (gimple *stmt, __attribute__((unused)) gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ test_log ("rewriting phi result", 0);
+ tree ssa_result = gimple_phi_result (stmt);
+ rewrite_expr (ssa_result, type_map, 0);
+ unsigned args = gimple_phi_num_args (stmt);
+ for (unsigned i = 0; i < args; i++)
+ {
+ test_log ("rewriting phi arg", 0);
+ tree arg = gimple_phi_arg_def (stmt, i);
+ rewrite_expr (arg, type_map, 0);
+ }
+}
+
+static bool
+rewrite_assign_lhs (gimple *stmt, gimple_stmt_iterator &gsi, t_map &type_map, t_map &inverse)
+{
+ tree lhs = gimple_assign_lhs(stmt);
+ enum tree_code code = TREE_CODE(lhs);
+ bool is_component_ref = code == COMPONENT_REF;
+ if (is_component_ref)
+ {
+ return rewrite_component_ref_def_lhs(gsi, lhs, type_map, 0);
+ }
+
+ rewrite_expr(lhs, type_map, 0);
+ return false;
+}
+
+static bool
+rewrite_assign (gimple *stmt, gimple_stmt_iterator &gsi,
+ t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (stmt);
+ test_print_gimple_stmt (stmt);
+ bool deleted = rewrite_assign_lhs (stmt, gsi, type_map, inverse);
+ if (deleted) {
+ unlink_stmt_vdef (stmt);
+ gsi_remove(&gsi, true);
+ return deleted;
+ }
+ rewrite_assign_rhs (stmt, gsi, type_map, inverse);
+ test_print_gimple_stmt (stmt);
+ return false;
+}
+
+static bool
+rewrite_return (gimple *stmt, gimple_stmt_iterator &gsi,
+ t_map &type_map)
+{
+ gcc_assert (stmt);
+ test_print_gimple_stmt (stmt);
+ greturn *retisn = dyn_cast<greturn *> (stmt);
+ gcc_assert(retisn);
+ tree retval = gimple_return_retval(retisn);
+ if (!retval) return false;
+
+ tree decl = DECL_RESULT (current_function_decl);
+ rewrite_expr(decl, type_map, 0);
+
+ rewrite_expr (retval, type_map, 0);
+ tree retval_type = TREE_TYPE(retval);
+ gcc_assert(retval_type);
+ log("return type %s\n", get_type_name(retval_type));
+ return false;
+}
+
+static bool
+rewrite_stmt (gimple *stmt, gimple_stmt_iterator &gsi,
+ t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (stmt);
+ const enum gimple_code code = gimple_code (stmt);
+ bool deleted = false;
+ switch (code)
+ {
+ case GIMPLE_ASSIGN:
+ deleted = rewrite_assign (stmt, gsi, type_map, inverse);
+ break;
+ case GIMPLE_CALL:
+ rewrite_call (stmt, gsi, type_map);
+ break;
+ case GIMPLE_COND:
+ rewrite_cond (stmt, gsi, type_map);
+ break;
+ case GIMPLE_PHI:
+ rewrite_phi (stmt, gsi, type_map);
+ break;
+ case GIMPLE_RETURN:
+ rewrite_return (stmt, gsi, type_map);
+ break;
+ default:
+ {
+ const char *const gimple_code_str = gimple_code_name[code];
+ test_log ("gimple_code %s", 0, gimple_code_str);
+ test_print_gimple_stmt (stmt);
+ }
+ break;
+ }
+ return deleted;
+}
+
+static void
+rewrite_basic_block (basic_block bb, t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (bb);
+ bool is_first = true;
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ bool deleted = rewrite_stmt (stmt, gsi, type_map, inverse);
+
+ if (deleted && !is_first)
+ {
+ gsi_prev(&gsi);
+ }
+
+ while (deleted && is_first)
+ {
+ stmt = gsi_stmt(gsi);
+ if (!stmt) break; // we might have deleted and was end of basic block?
+ deleted = rewrite_stmt (stmt, gsi, type_map, inverse);
+ if (gsi_end_p(gsi)) break;
+ }
+
+ if (deleted && gsi_end_p (gsi)) break;
+
+ is_first = false;
+ }
+ for (gimple_stmt_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ rewrite_stmt (stmt, gsi, type_map, inverse);
+ }
+}
+
+static void
+rewrite_function_body (cgraph_node *cnode,
+ t_map &type_map,
+ t_map &inverse)
+{
+ gcc_assert (cnode);
+ const char* name_s = cnode->name();
+ const char* dot = strstr(name_s, "."); // Updated functions have a dot on them.
+ // If there's a dot, we need to do a memcpy
+ // of the string name[0:dot]
+ size_t n = dot ? dot - name_s : strlen(name_s);
+ char precanon[100];
+ const char* canonical = dot ? strncpy(precanon, name_s, n) : name_s;
+ bool already_processed = updated_functions.find(name_s) != updated_functions.end();
+ log("original name %s\n", name_s);
+ log("canonical name %s\n", canonical);
+ log("already processed ? %s\n", already_processed ? "true" : "false");
+ if (already_processed) return;
+
+ updated_functions.insert(name_s);
+ cnode->get_untransformed_body ();
+ basic_block bb = NULL;
+ function *func = DECL_STRUCT_FUNCTION (cnode->decl);
+ push_cfun (func);
+ FOR_EACH_BB_FN (bb, func)
+ {
+ rewrite_basic_block (bb, type_map, inverse);
+ }
+ // TODO:
+ // can we move this logic into the above?
+ // Thanks!
+ size_t i;
+ tree name;
+ FOR_EACH_SSA_NAME (i, name, cfun)
+ {
+ if (SSA_NAME_VAR (name) != NULL_TREE
+ && TREE_TYPE (name) != TREE_TYPE (SSA_NAME_VAR (name)))
+ {
+ TREE_TYPE (name) = TREE_TYPE (SSA_NAME_VAR (name));
+ test_log ("changing to %s", 0,
+ get_type_name (TREE_TYPE (SSA_NAME_VAR (name))));
+ }
+ }
+ pop_cfun ();
+ print_function (cnode);
+}
+
+static void
+rewrite_local_decl (tree var_decl, t_map &type_map)
+{
+ gcc_assert (var_decl);
+ gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
+ const_tree type = TREE_TYPE (var_decl);
+ gcc_assert (type);
+ delete_info_t *delete_info = type_map.get (type);
+
+ if (!delete_info)
+ return;
+
+
+ const_tree new_type = delete_info->new_record;
+ gcc_assert (new_type);
+ test_write ("rewriting,local_decl");
+ test_print_generic_decl (var_decl);
+ test_write (",");
+ //TODO: Doing an experiment, we might need to keep qualifications...
+ substitute_type(var_decl, new_type);
+
+ // Keep this relayout_decl
+ relayout_decl (var_decl);
+ test_print_generic_decl (var_decl);
+ test_write ("\n");
+}
+
+static void
+rewrite_local_decls (cgraph_node *cnode,
+ t_map &type_map)
+{
+ gcc_assert (cnode);
+ tree decl = cnode->decl;
+ gcc_assert (decl);
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert (func);
+ tree var_decl = NULL;
+ int i = 0;
+ FOR_EACH_LOCAL_DECL (func, i, var_decl)
+ {
+ rewrite_local_decl (var_decl, type_map);
+ }
+ print_function (cnode);
+}
+
+static void
+rewrite_function_parms (tree expr, t_map &type_map,
+ const int indent)
+{
+ enum tree_code code = TREE_CODE (expr);
+ bool is_function_decl = code == FUNCTION_DECL;
+ gcc_assert (is_function_decl);
+
+ for (tree parm = DECL_ARGUMENTS (expr); parm; parm = DECL_CHAIN (parm))
+ {
+ tree parm_type = TREE_TYPE (parm);
+ delete_info_t *delete_info = type_map.get (parm_type);
+ if (!delete_info)
+ continue;
+
+ const_tree new_type = delete_info->new_record;
+ test_log ("before rewrite_function_arg %s", indent, get_type_name (parm_type));
+ substitute_type(parm, new_type);
+ relayout_decl (parm);
+ tree parm_type_2 = TREE_TYPE (parm);
+ test_log ("after rewrite_function_arg %s", indent,
+ get_type_name (parm_type_2));
+ }
+}
+
+static void
+rewrite_function_parms (cgraph_node *cnode,
+ t_map &type_map)
+{
+ rewrite_function_parms (cnode->decl, type_map, 0);
+}
+
+static void
+rewrite_function_return_type (tree expr,
+ t_map &type_map,
+ const int indent)
+{
+ enum tree_code code = TREE_CODE (expr);
+ bool is_function_decl = code == FUNCTION_DECL;
+ gcc_assert (is_function_decl);
+
+ tree function_type = TREE_TYPE (expr);
+
+ // TODO: We do not support method's yet.
+ gcc_assert (TREE_CODE (function_type) == FUNCTION_TYPE);
+ tree function_return_type = TREE_TYPE (function_type);
+ gcc_assert (function_return_type);
+
+ test_log ("before rewrite_function_return_type %s", indent,
+ get_type_name (function_return_type));
+ delete_info_t *delete_info = type_map.get (function_return_type);
+ if (!delete_info)
+ return;
+
+ const_tree new_type = delete_info->new_record;
+ tree new_type_2 = build_type_variant(const_to_tree(new_type), TYPE_READONLY(function_return_type), TYPE_VOLATILE(function_return_type));
+ substitute_type(function_type, new_type_2);
+ // Do not use relayout_decl(cnode->decl);
+ tree function_type_2 = TREE_TYPE (expr);
+ tree function_return_type_2 = TREE_TYPE (function_type_2);
+ test_log ("after rewrite_function_return_type %s", indent,
+ get_type_name (function_return_type_2));
+}
+
+static void
+rewrite_function_return_type (cgraph_node *cnode,
+ t_map &type_map)
+{
+ gcc_assert (TREE_CODE (cnode->decl) == FUNCTION_DECL);
+ tree function_type = TREE_TYPE (cnode->decl);
+ gcc_assert (function_type);
+ rewrite_function_return_type (cnode->decl, type_map, 0);
+}
+
+static void
+rewrite_global_decl (varpool_node *vnode,
+ t_map &type_map)
+{
+ int i;
+ struct ipa_ref *ref;
+
+ /* Only IPA_REF_STORE and IPA_REF_LOAD left. */
+ for (i = 0; vnode->iterate_referring (i, ref); i++)
+ {
+ test_log ("rewriting global declaration", 0);
+ rewrite_local_decl (vnode->decl, type_map);
+ test_print_generic_decl (vnode->decl);
+ }
+}
+
+static void
+rewrite_global_decls ( t_map &type_map)
+{
+ varpool_node *vnode;
+ FOR_EACH_VARIABLE (vnode)
+ {
+ rewrite_global_decl (vnode, type_map);
+ }
+}
+
+static void
+rewrite_function (cgraph_node *cnode,
+ t_map &type_map,
+ t_map &inverse)
+{
+ // rewrite_function_body should be before
+ // rewrite_local_decls to make work easier.
+ // Why? Because if we rewrite local decl types
+ // first, then we might need to look for
+ // old AND new types in rewrite_function_body.
+ // If we rewrite local decl types later,
+ // then in rewrite_function_body we only
+ // need to look for old types.
+ rewrite_function_parms (cnode, type_map);
+ rewrite_function_return_type (cnode, type_map);
+ rewrite_function_body (cnode, type_map, inverse);
+ rewrite_local_decls (cnode, type_map);
+}
+
+static void
+rewrite_functions ( t_map &type_map,
+ t_map &inverse)
+{
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION (cnode)
+ {
+ rewrite_function (cnode, type_map, inverse);
+ }
+}
+
+static void
+rewrite_references_to_modified_structs (
+ t_map &type_map,
+ t_map &inverse)
+{
+ rewrite_functions (type_map, inverse);
+ rewrite_global_decls (type_map);
+}
+
+bool
+compute_inverse_type_map_internal (
+ const_tree const &old_type, delete_info_t *delete_info,
+ t_map *inverse_map)
+{
+ gcc_assert (inverse_map && delete_info);
+ const_tree new_type = delete_info->new_record;
+ inverse_map->put (delete_info->new_record, *delete_info);
+ const char *old_identifier = get_type_name (old_type);
+ const char *new_identifier = get_type_name (new_type);
+ test_log ("inverse,%s,%s", 0, new_identifier, old_identifier);
+ return true;
+}
+
+static void
+compute_inverse_type_map ( t_map &mod_type_map,
+ t_map &inverse_map)
+{
+ mod_type_map.traverse< t_map *,
+ compute_inverse_type_map_internal> (&inverse_map);
+}
+
+
+static void
+separate_set_of_pairs_into_pair_of_sets(const record_field_set &set_of_pairs, std::set<const char*, cstrless> &one, std::set<const char*, cstrless> &two)
+{
+
+ for (auto it = set_of_pairs.cbegin(); it != set_of_pairs.cend() ; ++it)
+ {
+ fields record_field_pair = *it;
+ const_tree record = record_field_pair.first;
+ if (strcmp(get_record_name(record), "<name_tree_is_null>") == 0) continue;
+ const_tree field = record_field_pair.second;
+ one.insert(get_type_name(record));
+ one.insert(get_type_name(TYPE_MAIN_VARIANT(record)));
+ two.insert(get_field_name(field));
+ char *buffer;
+ char *buffer2;
+ asprintf(&buffer, "%s.%s", get_type_name(record), get_field_name(field));
+ asprintf(&buffer2, "%s.%s", get_type_name(TYPE_MAIN_VARIANT(record)), get_field_name(field));
+ log("putting in %s\n", buffer);
+ log("putting in %s\n", buffer2);
+ record_field_pair_name.insert(buffer);
+ record_field_pair_name.insert(buffer2);
+ }
+}
+
+static void
+iphw_execute_escape_analysis()
+{
+ gcc_assert(!flag_ipa_typelist_struct && !flag_ipa_typelist_field);
+ const record_field_set to_reorg = get_fields_to_reorg();
+ print_record_field_set(to_reorg);
+ //separate_set_of_pairs_into_pair_of_sets(to_reorg, interesting_records, interesting_fields);
+
+ //hash_set<const_tree> orig_type_map;
+ //collect_orig_structs (orig_type_map);
+ //t_map mod_type_map;
+ //compute_modified_structs (orig_type_map, mod_type_map);
+ //t_map inverse_type_map;
+ //compute_inverse_type_map (mod_type_map, inverse_type_map);
+ //rewrite_references_to_modified_structs (mod_type_map, inverse_type_map);
+}
+
+static void
+iphw_execute_cli_args()
+{
+ gcc_assert(flag_ipa_typelist_struct && flag_ipa_typelist_field);
+
+ hash_set<const_tree> orig_type_map;
+ collect_orig_structs (orig_type_map);
+
+ // So what would a client will have to implement?
+ // * Pass a set of types
+ // * A function that translates old_types to new_types
+ // class TypeRewriter {
+ // // A set might not be
+ // // sufficient to say **how** the types should
+ // // be modified
+ // TypeRewriter(set, function type -> new_type);
+ // ~TypeRewriter(); // allows me to free memory used during
+ // // the pass easily
+ // rewrite(stmt); // maybe no since it can corrupt the function?
+ // rewrite(bb); // maybe no since it can corrupt the function?
+ // rewrite(func);
+ // rewrite(set(functions));
+ // }
+ t_map mod_type_map;
+ compute_modified_structs (orig_type_map, mod_type_map);
+ t_map inverse_type_map;
+ compute_inverse_type_map (mod_type_map, inverse_type_map);
+ rewrite_references_to_modified_structs (mod_type_map, inverse_type_map);
+}
+
+static unsigned int
+iphw_execute ()
+{
+ test_log ("Executing structreorg", 0);
+ const bool perform_escape_analysis = !flag_ipa_typelist_struct && !flag_ipa_typelist_field ;
+ perform_escape_analysis ? iphw_execute_escape_analysis() : iphw_execute_cli_args();
+ return 0;
+}
+
+int
+str_reorg_dead_field_eliminate (__attribute__((unused)) Info *info)
+{
+ gcc_assert (in_lto_p);
+ return iphw_execute ();
+}
diff --git a/gcc/ipa-str-reorg-field-reorder.c b/gcc/ipa-str-reorg-field-reorder.c
new file mode 100644
index 00000000000..5c9a2bb0b9b
--- /dev/null
+++ b/gcc/ipa-str-reorg-field-reorder.c
@@ -0,0 +1,47 @@
+/* Interprocedural scalar replacement of aggregates
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Your Name & Email address go here
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "gimple-iterator.h"
+#include "pretty-print.h"
+#include <vector>
+#include <map>
+#include <set>
+#include "ipa-structure-reorg.h"
+#include "dumpfile.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "langhooks.h"
+
+int
+str_reorg_field_reorder (Info *info)
+{
+ // TBD
+ // DEBUG ( "Running str_reorg_field_reorder\n");
+ return 0;
+}
diff --git a/gcc/ipa-str-reorg-instance-interleave.c b/gcc/ipa-str-reorg-instance-interleave.c
new file mode 100644
index 00000000000..2b5d4afd81b
--- /dev/null
+++ b/gcc/ipa-str-reorg-instance-interleave.c
@@ -0,0 +1,48 @@
+/* Interprocedural scalar replacement of aggregates
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <goblock@marvell.com>
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "gimple-iterator.h"
+#include "pretty-print.h"
+#include <vector>
+#include <map>
+#include <set>
+#include "ipa-structure-reorg.h"
+#include "dumpfile.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "langhooks.h"
+
+int
+// Returns one if something was done and zero otherwise.
+str_reorg_instance_interleave (Info *info)
+{
+ // TBD
+ // DEBUG ( "Running str_reorg_instance_interleave\n");
+ return 0;
+}
diff --git a/gcc/ipa-str-reorg-utils.c b/gcc/ipa-str-reorg-utils.c
new file mode 100644
index 00000000000..cc6d5162af5
--- /dev/null
+++ b/gcc/ipa-str-reorg-utils.c
@@ -0,0 +1,300 @@
+#include "ipa-str-reorg-utils.h"
+
+// This really should be inaccessible to anyone.
+const_tree
+get_base_type_from_ptr_or_arr_type (const_tree old_pointer_type,
+ const_tree pointer_type,
+ unsigned int &indirection_level)
+{
+ if (pointer_type == NULL)
+ {
+ gcc_assert (TREE_CODE (old_pointer_type) != POINTER_TYPE);
+ gcc_assert (TREE_CODE (old_pointer_type) != ARRAY_TYPE);
+ return old_pointer_type;
+ }
+ return get_base_type_from_ptr_or_arr_type (pointer_type,
+ TREE_TYPE (pointer_type),
+ ++indirection_level);
+}
+
+const_tree
+get_base_type_from_ptr_or_arr_type (const_tree ptr_or_array,
+ unsigned int &indirection_level)
+{
+ const bool is_array = TREE_CODE (ptr_or_array) == ARRAY_TYPE;
+ const bool is_ptr = TREE_CODE (ptr_or_array) == POINTER_TYPE;
+ const bool is_array_or_ptr = is_array || is_ptr;
+ gcc_assert (is_array_or_ptr);
+ indirection_level = 0;
+ return get_base_type_from_ptr_or_arr_type (ptr_or_array,
+ TREE_TYPE (ptr_or_array),
+ indirection_level);
+}
+
+const_tree
+get_base_type_from_array_type (const_tree array_type,
+ unsigned int &indirection_level)
+{
+ gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
+ return get_base_type_from_ptr_or_arr_type (array_type, indirection_level);
+}
+
+const_tree
+get_base_type_from_array_type (const_tree array_type)
+{
+ gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
+ unsigned int indirection_level;
+ return get_base_type_from_array_type (array_type, indirection_level);
+}
+
+const_tree
+get_base_type_from_pointer_type (const_tree pointer_type,
+ unsigned int &indirection_level)
+{
+ gcc_assert (TREE_CODE (pointer_type) == POINTER_TYPE);
+ return get_base_type_from_ptr_or_arr_type (pointer_type, indirection_level);
+}
+
+const_tree
+get_base_type_from_pointer_type (const_tree pointer_type)
+{
+ gcc_assert (TREE_CODE (pointer_type) == POINTER_TYPE);
+ unsigned int indirection_level;
+ return get_base_type_from_pointer_type (pointer_type, indirection_level);
+}
+
+const_tree
+get_base_type (const_tree type)
+{
+ enum tree_code tree_code_type = TREE_CODE(type);
+ switch (tree_code_type)
+ {
+ case ARRAY_TYPE: return get_base_type_from_array_type(type); break;
+ case POINTER_TYPE: return get_base_type_from_pointer_type(type); break;
+ default: return type; break;
+ }
+
+ gcc_unreachable();
+ return NULL;
+}
+const char *
+make_pointer_name (const_tree pointer)
+{
+ gcc_assert (TREE_CODE (pointer) == POINTER_TYPE);
+ unsigned int indirection_level;
+ const_tree base_type
+ = get_base_type_from_pointer_type (pointer, indirection_level);
+ const char *pointer_name = make_pointer_name (base_type, indirection_level);
+ return pointer_name;
+}
+
+const char *
+make_pointer_or_array_name (const char *base_type, const char *postfix)
+{
+ char *ptr;
+ int calculated_size = strlen (base_type) + strlen (postfix);
+ // TODO: Do not use asprintf?
+ // We'll let exit() deal with freeing this memory.
+ int retval = asprintf (&ptr, "%s%s", base_type, postfix);
+ gcc_assert (retval == calculated_size);
+ return ptr;
+}
+
+const char *
+make_array_postfix (unsigned int indirection_level)
+{
+ gcc_assert (indirection_level > 0);
+ static const char *max_indirection_level_str_array
+ = "[][][][][][][][][][][][][]";
+ static const size_t size_array = strlen (max_indirection_level_str_array);
+ static const size_t postfix_size_array = 2;
+ static const size_t max_indirection_level_array
+ = size_array / postfix_size_array;
+ gcc_assert (indirection_level < max_indirection_level_array);
+ return max_indirection_level_str_array + size_array
+ - (indirection_level * postfix_size_array);
+}
+
+const char *
+make_pointer_postfix (unsigned int indirection_level)
+{
+ gcc_assert (indirection_level > 0);
+ static const char *max_indirection_level_str_pointer
+ = "************************";
+ static const size_t size_pointer = strlen (max_indirection_level_str_pointer);
+ static const size_t postfix_size_pointer = 1;
+ static const size_t max_indirection_level_pointer
+ = size_pointer / postfix_size_pointer;
+ gcc_assert (indirection_level < max_indirection_level_pointer);
+ return max_indirection_level_str_pointer + size_pointer
+ - (indirection_level * postfix_size_pointer);
+}
+
+const char *
+make_pointer_name (const char *base_type_name,
+ const unsigned int indirection_level)
+{
+ const char *postfix = make_pointer_postfix (indirection_level);
+ const char *ptr = make_pointer_or_array_name (base_type_name, postfix);
+ return ptr;
+}
+
+const char *
+make_pointer_name (const_tree base_type, const unsigned int indirection_level)
+{
+ const char *struct_name = get_type_name (base_type);
+ return make_pointer_name (struct_name, indirection_level);
+}
+
+
+const char *
+make_array_name (const char *base_type_name,
+ const unsigned int indirection_level)
+{
+ const char *postfix = make_array_postfix (indirection_level);
+ const char *ptr = make_pointer_or_array_name (base_type_name, postfix);
+ return ptr;
+}
+
+const char *
+make_array_name (const_tree base_type, const unsigned int indirection_level)
+{
+ const char *struct_name = get_type_name (base_type);
+ return make_array_name (struct_name, indirection_level);
+}
+
+// TODO: deal with anonymous structs.
+// Some records don't have identifier pointers
+const char *
+get_record_name (const_tree record)
+{
+ gcc_assert (record);
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+ tree name_tree = TYPE_NAME (record);
+ // The TYPE_NAME will be NULL_TREE for a type
+ // that is not a built-in type, the result of a typedef
+ // or a named class type.
+ // TODO: verify that we are never changing
+ // <name_tree_is_null> types
+ if (name_tree == NULL_TREE)
+ {
+ return "<name_tree_is_null>";
+ }
+
+ if (TREE_CODE (name_tree) == TYPE_DECL)
+ {
+ tree type_name = DECL_NAME (name_tree);
+ return IDENTIFIER_POINTER (type_name);
+ }
+ const char *identifier = IDENTIFIER_POINTER (name_tree);
+ gcc_assert (identifier);
+ return identifier;
+}
+
+const char *
+make_array_name (const_tree array)
+{
+ gcc_assert (TREE_CODE (array) == ARRAY_TYPE);
+ unsigned int indirection_level;
+ const_tree base_type
+ = get_base_type_from_array_type (array, indirection_level);
+ const char *array_name = make_array_name (base_type, indirection_level);
+ return array_name;
+}
+
+const char *
+get_array_name (const_tree array)
+{
+ gcc_assert (array);
+ gcc_assert (TREE_CODE (array) == ARRAY_TYPE);
+ const bool is_modified = TYPE_NAME (array);
+ if (is_modified)
+ return IDENTIFIER_POINTER (TYPE_NAME (array));
+
+ return make_array_name (array);
+}
+
+const char *
+get_pointer_name (const_tree pointer)
+{
+ gcc_assert (pointer);
+ gcc_assert (TREE_CODE (pointer) == POINTER_TYPE);
+ const bool is_modified = TYPE_NAME (pointer);
+ if (is_modified)
+ return IDENTIFIER_POINTER (TYPE_NAME (pointer));
+
+ const char *new_pointer_name = make_pointer_name (pointer);
+ return new_pointer_name;
+}
+
+const char *
+make_reference_name (const_tree ref)
+{
+ gcc_assert (TREE_CODE (ref) == REFERENCE_TYPE);
+ const_tree base_type = TREE_TYPE (ref);
+ const char *old_name = get_type_name (base_type);
+ char *ptr;
+ static const char *prefix = "&";
+ static const char *suffix = ".reorg";
+ int new_size = strlen (prefix) + strlen (old_name) + strlen (suffix);
+ int retval = asprintf (&ptr, "%s%s%s", prefix, old_name, suffix);
+ gcc_assert (retval == new_size);
+ return ptr;
+}
+
+
+const char *
+get_reference_name (const_tree ref)
+{
+ gcc_assert (ref);
+ gcc_assert (TREE_CODE (ref) == REFERENCE_TYPE);
+ const bool is_modified = TYPE_NAME (ref);
+ if (is_modified)
+ return IDENTIFIER_POINTER (TYPE_NAME (ref));
+
+ const char *new_pointer_name = make_reference_name (ref);
+ return new_pointer_name;
+}
+
+const char *
+get_type_name (const_tree type)
+{
+ enum tree_code code = TREE_CODE (type);
+ switch (code)
+ {
+ case ARRAY_TYPE:
+ return get_array_name (type);
+ break;
+ case POINTER_TYPE:
+ return get_pointer_name (type);
+ break;
+ case RECORD_TYPE:
+ return get_record_name (type);
+ break;
+ case REFERENCE_TYPE:
+ return get_reference_name (type);
+ break;
+ default:
+ // TODO: generalize even more?
+ // wait for experimental results to dictate what
+ // else we should specify.
+ return get_tree_code_name (code);
+ break;
+ }
+ return NULL;
+}
+
+const char *
+get_field_name (const_tree field_decl)
+{
+ gcc_assert (field_decl);
+ gcc_assert (TREE_CODE (field_decl) == FIELD_DECL);
+ // TODO: deal with anonymous fields.
+ tree id = DECL_NAME (field_decl);
+ if (!id)
+ return "anonymous";
+ gcc_assert (id);
+ const char *identifier = IDENTIFIER_POINTER (id);
+ gcc_assert (identifier);
+ return identifier;
+}
diff --git a/gcc/ipa-str-reorg-utils.h b/gcc/ipa-str-reorg-utils.h
new file mode 100644
index 00000000000..0197e88e769
--- /dev/null
+++ b/gcc/ipa-str-reorg-utils.h
@@ -0,0 +1,58 @@
+#ifndef GCC_IPA_STR_REORG_UTILS_H
+#define GCC_IPA_STR_REORG_UTILS_H
+#pragma once
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+
+const char * get_type_name (const_tree type);
+const char * get_reference_name (const_tree ref);
+const char * make_reference_name (const_tree ref);
+const char * get_pointer_name (const_tree pointer);
+const char * get_array_name (const_tree array);
+const char * get_record_name (const_tree record);
+const char * make_array_name (const_tree base_type, const unsigned int indirection_level);
+const char * make_array_name (const char *base_type_name, const unsigned int indirection_level);
+const char * make_pointer_name (const_tree base_type, const unsigned int indirection_level);
+const char * make_pointer_name (const char *base_type_name, const unsigned int indirection_level);
+const char * make_pointer_postfix (unsigned int indirection_level);
+const char * make_array_postfix (unsigned int indirection_level);
+const char * make_array_name (const_tree array);
+const char * make_pointer_or_array_name (const char *base_type, const char *postfix);
+const char * make_pointer_name (const_tree pointer);
+const_tree get_base_type_from_ptr_or_arr_type (const_tree old_pointer_type, const_tree pointer_type, unsigned int &indirection_level);
+const_tree get_base_type_from_ptr_or_arr_type (const_tree ptr_or_array, unsigned int &indirection_level);
+const_tree get_base_type_from_array_type (const_tree array_type, unsigned int &indirection_level);
+const_tree get_base_type_from_array_type (const_tree array_type);
+const_tree get_base_type_from_pointer_type (const_tree pointer_type, unsigned int &indirection_level);
+const_tree get_base_type_from_pointer_type (const_tree pointer_type);
+const_tree get_base_type (const_tree type);
+const char* get_field_name (const_tree type);
+
+#include <stdio.h>
+
+inline void
+log (const char * const format, ...)
+{
+ if (!dump_file) return;
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(dump_file, format, args);
+ va_end(args);
+}
+
+inline void
+log_2 ( const char * const format, ...)
+{
+ if (!dump_file) return;
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(dump_file, format, args);
+ va_end(args);
+}
+
+#endif
diff --git a/gcc/ipa-structure-reorg.c b/gcc/ipa-structure-reorg.c
new file mode 100644
index 00000000000..10e092b664d
--- /dev/null
+++ b/gcc/ipa-structure-reorg.c
@@ -0,0 +1,879 @@
+/* Interprocedural scalar replacement of aggregates
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <goblock@marvell.com>
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "gimple-iterator.h"
+#include "pretty-print.h"
+#include <vector>
+#include <map>
+#include <set>
+#include "ipa-structure-reorg.h"
+#include "dumpfile.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "langhooks.h"
+// TBD more includes go here
+
+static void
+setup_debug_flags (Info *);
+static void
+final_debug_info (Info *);
+static unsigned int
+reorg_analysis (Info_t *);
+static void
+reorg_analysis_debug (Info *, ReorgType *);
+static bool
+find_decls_and_types (Info_t *);
+static void
+disqualify_struct_in_struct_or_union (Info_t *);
+static void
+initial_reorg_debug (Info *info, ReorgType *reorg);
+static void
+disqualify_struct_in_struct_or_union_debug (Info *, ReorgType *);
+static void
+disq_str_in_str_or_union_helper (tree, std::set<tree> *, Info_t *);
+static unsigned int
+reorg_qualification (Info_t *);
+// Name changed and moved to its own file
+// static void reorg_transformation ( Info_t *);
+// made extern
+// static void delete_reorgtype ( ReorgType_t *, Info_t *);
+// static void undelete_reorgtype ( ReorgType_t *, Info_t *);
+// static void remove_deleted_types ( Info *, ReorgFn);
+static tree base_type_of (tree);
+static bool
+is_reorg_alloc_trigger (gimple *);
+static ReorgType_t *
+find_struct_type_ptr_to_struct (tree, Info *);
+static ReorgType_t *
+get_reorgtype_info (tree type, Info_t *info);
+static void
+print_reorg_with_msg (FILE *, ReorgType_t *, int, const char *);
+static void
+dump_reorg (ReorgType_t *reorg);
+static void
+print_reorgs (FILE *, int, Info *);
+static void
+print_reorg (FILE *, int, ReorgType_t *);
+//-- debugging only --
+static const char *code_str (enum tree_code);
+
+//---------------- Code Follows ----------------
+
+static unsigned int
+ipa_structure_reorg (void)
+{
+ std::vector<ReorgType_t> Reorg_Type;
+ std::vector<ReorgType_t> Saved_Reorg_Type;
+ std::vector<ProgDecl_t> Prog_Decl;
+ std::map<tree, BoolPair_t> StructTypes; // TBD horrible type name
+
+ // DEBUG( "Running ipa_structure_reorg\n");
+
+ // TBD we must have run the IPA points-to analysis and
+ // be running in a single LTRANS partition. Sanity check
+ // these here.
+
+ Info_t info = {&Reorg_Type, &Saved_Reorg_Type,
+ &Prog_Decl, &StructTypes,
+ 0, 0.0,
+ false, false,
+ false, false,
+ false, false};
+
+ setup_debug_flags (&info);
+
+ if (flag_ipa_dead_field_eliminate)
+ {
+ str_reorg_dead_field_eliminate (&info);
+ }
+
+ return true;
+
+ if (reorg_qualification (&info))
+ {
+ // Each of these do their own performance qualification and
+ // if they delete any types they must invoke restore_deleted_types
+ // so the next subpass has all the types to consider.
+ // Also, if they change the shape of a type the must create my
+ // type and update the ReorgTypes to reflect this.
+
+ if (flag_ipa_structure_reorg || flag_ipa_field_reorder)
+ {
+ str_reorg_field_reorder (&info);
+ }
+ if (flag_ipa_structure_reorg || flag_ipa_instance_interleave)
+ {
+ str_reorg_instance_interleave (&info);
+ }
+ }
+
+ final_debug_info (&info);
+
+ return true;
+}
+
+static void
+setup_debug_flags (Info *info)
+{
+ // The normal way of doing this would be to
+ // set the flags with dump_file && (dump_flags & TDF_XXX
+ // where XXX is some level of dump control but
+ // I think the code here would work better
+ // (where each flag is set off the dump_flags.)
+
+ if (dump_file)
+ {
+ info->show_all_reorg_cands = true;
+ info->show_all_reorg_cands_in_detail = dump_flags & TDF_DETAILS;
+ info->show_delete = dump_flags & TDF_DETAILS;
+ info->show_new_BBs = dump_flags & TDF_DETAILS;
+ info->show_transforms = dump_flags & TDF_DETAILS;
+ info->show_bounds = dump_flags & TDF_DETAILS;
+ }
+}
+
+static void
+final_debug_info (Info *info)
+{
+ // TBD
+}
+
+static unsigned int
+reorg_analysis (Info_t *info)
+{
+ struct cgraph_node *node;
+
+ find_decls_and_types (info);
+
+ // Skip computing numbOfGlobalArrays initially.
+
+ // Skip computing numbOfLocalArrays initially.
+
+ // Compute numbOfDynmAllocs per type in regtype
+ FOR_EACH_FUNCTION (node)
+ {
+ basic_block bb;
+
+ struct function *func = DECL_STRUCT_FUNCTION (node->decl);
+
+ // This is a work around
+ if (func == NULL)
+ {
+ continue;
+ }
+
+ FOR_EACH_BB_FN (bb, func)
+ {
+ gimple_stmt_iterator gsi;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ // DEBUG_F ( print_gimple_stmt, stderr, stmt, (dump_flags_t)-1);
+ // DEBUG ( "\n");
+ if (is_gimple_call (stmt))
+ {
+ // next line has issues but the mechanism is sound
+ tree t = *gimple_call_lhs_ptr (stmt);
+ // DEBUG( "t %p\n", t);
+ // Calls to a function returning void are skipped.
+ if (t != NULL)
+ {
+ tree bt = base_type_of (t);
+ if (TREE_CODE (bt) != RECORD_TYPE)
+ {
+ continue;
+ }
+ // find if in reorgtypes and get the info (in one call)
+ ReorgType_t *ri = get_reorgtype_info (bt, info);
+ if (ri != NULL && is_reorg_alloc_trigger (stmt))
+ {
+ ri->numbOfDynmAllocs++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // It's LOT clear to use an iterator here TBD
+ for (int i = 0; i < info->reorg_type->size (); i++)
+ {
+ int n = (*(info->reorg_type))[i].numbOfGlobalArrays
+ + (*(info->reorg_type))[i].numbOfLocalArrays
+ + (*(info->reorg_type))[i].numbOfDynmAllocs;
+ if (n > 1)
+ {
+ (*(info->reorg_type))[i].multi_pool = true;
+ }
+ if (n == 0)
+ {
+ delete_reorgtype (&(*(info->reorg_type))[i], info);
+ }
+ }
+
+ remove_deleted_types (info, &reorg_analysis_debug);
+
+ return !info->reorg_type->empty ();
+}
+
+void
+reorg_analysis_debug (Info *info, ReorgType *reorg)
+{
+ if (info->show_delete)
+ {
+ print_reorg_with_msg (dump_file, reorg, 2, "Was not allocated");
+ }
+}
+
+static bool
+find_decls_and_types (Info_t *info)
+{
+ // Don't keep any structure types if they aren't
+ // used in an array or have a pointer type (which
+ // hopefully will have an associated allocation.)
+ // Note, initially ignore the explicit statically
+ // allocated arrays.
+ //
+ // This initializes them too of course.
+
+ // Find all struct types for initial ReorgTypes
+ // marking them all to initially be deleted.
+ // This is done by walking all variables.
+ std::set<tree> typeset;
+ varpool_node *var;
+ FOR_EACH_VARIABLE (var)
+ {
+ tree decl = var->decl;
+ // DEBUG( "L# %d Consider var->decl\n", __LINE__);
+ // DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)-1);
+ tree base = base_type_of (decl);
+ // DEBUG( "\nBase\n");
+ // DEBUG( "TREE_CODE = %s\n", code_str( TREE_CODE ( base)));
+ // DEBUG_F( print_generic_expr, stderr, base, (dump_flags_t)-1);
+ // DEBUG( "\n");
+
+ if (TREE_CODE (base) == RECORD_TYPE)
+ {
+ // skip if found before
+ if (typeset.find (base) != typeset.end ())
+ {
+ // DEBUG( "not found\n");
+ continue;
+ }
+ else
+ {
+ // DEBUG( "found\n")
+ ;
+ }
+ ReorgType_t rt
+ = {0, base, 0, 0, 0, 0.0, 0.0, false, true, NULL, NULL};
+ info->reorg_type->push_back (rt);
+ typeset.insert (base); // ???
+ }
+ }
+
+ // NOTE, the scheme above leaves out local variables so
+ // I'll repeat the for the local variable of functions.
+ // TBD Am I doing something actually, after this, that
+ // is actually done here or above... it seems likely.
+
+ cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ tree decl;
+ unsigned i;
+
+ node->get_untransformed_body ();
+
+ struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+ // enable this to see error in test_1_8
+ // DEBUG( "L# %d, function name = %s\n",
+ //__LINE__, lang_hooks.decl_printable_name ( node->decl, 2));
+ if (fn == NULL)
+ {
+ // DEBUG( " EMPTY\n");
+ continue;
+ }
+
+ FOR_EACH_LOCAL_DECL (fn, i, decl)
+ {
+ tree base = base_type_of (decl);
+ // enable this to see error in test_1_8
+ // DEBUG( "L# %d Consider local var decl\n", __LINE__);
+ // DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)-1);
+ // DEBUG( "\n");
+
+ if (TREE_CODE (base) == RECORD_TYPE)
+ {
+ if (typeset.find (base) != typeset.end ())
+ {
+ continue;
+ }
+
+ ReorgType_t rt
+ = {0, base, 0, 0, 0, 0.0, 0.0, false, true, NULL, NULL};
+ info->reorg_type->push_back (rt);
+ typeset.insert (base); // ???
+ }
+ }
+ }
+
+ // We need this later for creating new types
+ for (std::set<tree>::iterator ti = typeset.begin (); ti != typeset.end ();
+ ti++)
+ {
+ (*(info->struct_types))[*ti] = {false, false};
+ }
+
+ if (info->show_all_reorg_cands_in_detail)
+ {
+ fprintf (dump_file, "All possible candidates:\n");
+ print_reorgs (dump_file, 2, info);
+ }
+
+ // Scan all declarations for pointers to ReorgTypes
+ // and in a later version array of them. When found
+ // clear the deletion mark.
+ // Note, there is no mechanism for looking at global declarations
+ // so use FOR_EACH_VARIABLE instead. I'm not 100% this is the thing
+ // actuall do here... but...
+ FOR_EACH_VARIABLE (var)
+ {
+ tree decl = var->decl;
+ ReorgType_t *rtype = find_struct_type_ptr_to_struct (decl, info);
+ if (rtype != NULL)
+ {
+ undelete_reorgtype (rtype, info);
+ }
+ }
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ tree decl;
+ unsigned i;
+
+ // Only need to do this once in the program and it was done
+ // above!
+ // Node->get_untransformed_body ();
+
+ struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+
+ // DEBUG( "fn %p\n", fn);
+ // DEBUG_F( print_generic_decl, stderr, node->decl, (dump_flags_t)-1);
+ // DEBUG( "\n");
+ // I don't know why this is coming up null.... but I'll
+ // skip it for now.
+ if (fn == NULL)
+ {
+ continue;
+ }
+
+ FOR_EACH_LOCAL_DECL (fn, i, decl)
+ {
+ // Does this work... see tree.c:6132
+ ReorgType_t *rtype = find_struct_type_ptr_to_struct (decl, info);
+ if (rtype != NULL)
+ {
+ undelete_reorgtype (rtype, info);
+ }
+ }
+ }
+
+ if (info->show_all_reorg_cands)
+ {
+ fprintf (dump_file, "All preliminary ReorgTypes:\n");
+ // print_reorgs ( dump_file, 2, info);
+ }
+
+ // Scan all types in ReorgTypes for structure fields
+ // and if they are pointers to a type Q in ReorgTypes
+ // then clear the deletion mark of Q. Note, at this
+ // point in the execution ReorgTypes is all the structure
+ // types.
+ //
+ // It would be a bit nuts to allocate memory and hang it
+ // off of pointer in a structure, but it's still possible.
+ // Note, if there are no pointers to a structure of a type
+ // then it is impossible to dynamically allocate memory of
+ // that type. This of course assumes sane programming
+ // practices and if they violate those structure reorg has
+ // every right to punt.
+ for (std::vector<ReorgType_t>::iterator ri = info->reorg_type->begin ();
+ ri != info->reorg_type->end (); ri++)
+ {
+ for (tree fld = TYPE_FIELDS (ri->gcc_type); fld; fld = DECL_CHAIN (fld))
+ {
+ ReorgType_t *rtype = find_struct_type_ptr_to_struct (fld, info);
+ if (rtype != NULL)
+ {
+ undelete_reorgtype (rtype, info);
+ }
+ }
+ }
+
+ remove_deleted_types (info, &initial_reorg_debug);
+
+ // Disqualifying structures in interior to structures is optional
+ // (see comment at end of type escape section) but if it's not
+ // done it commits the optimization to do something a little too
+ // involved for the initial version.
+ disqualify_struct_in_struct_or_union (info);
+
+ if (info->reorg_type->empty ())
+ {
+ if (info->show_all_reorg_cands_in_detail)
+ {
+ fprintf (dump_file, "find_decls_and_types: Found no types\n");
+ }
+ return false;
+ }
+
+ // initialize ids of ReorgTypes
+ int id = 0;
+ for (std::vector<ReorgType_t>::iterator ri = info->reorg_type->begin ();
+ ri != info->reorg_type->end (); ri++)
+ {
+ ri->id = id;
+ id++;
+ }
+
+ // Scan all declarations. If their type is in ReorgTypes
+ // add them to ProgDecl.
+ // Note, there is no mechanism for looking at global declarations
+ // so use FOR_EACH_VARIABLE instead. I'm not 100% this is the thing
+ // actuall do here... but...
+ FOR_EACH_VARIABLE (var)
+ {
+ tree decl = var->decl;
+ tree type = base_type_of (decl);
+ if (TREE_CODE (type) == RECORD_TYPE
+ && get_reorgtype_info (type, info) != NULL)
+ {
+ ProgDecl_t decl_info;
+ decl_info.gcc_decl = decl;
+ info->prog_decl->push_back (decl_info);
+ }
+ }
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ {
+ // local declarations
+ unsigned i;
+ tree decl;
+ struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
+ FOR_EACH_LOCAL_DECL (fn, i, decl)
+ {
+ tree type = base_type_of (decl);
+ if (TREE_CODE (type) == RECORD_TYPE
+ && get_reorgtype_info (type, info) != NULL)
+ {
+ ProgDecl_t decl_info;
+ decl_info.gcc_decl = decl;
+ info->prog_decl->push_back (decl_info);
+ }
+ }
+
+ // parameter declarations
+ tree parm;
+ for (parm = DECL_ARGUMENTS (fn->decl); parm; parm = DECL_CHAIN (parm))
+ {
+ tree decl = TREE_TYPE (parm);
+ tree type = base_type_of (decl);
+ if (TREE_CODE (type) == RECORD_TYPE
+ && get_reorgtype_info (type, info) != NULL)
+ {
+ ProgDecl_t decl_info;
+ decl_info.gcc_decl = decl;
+ info->prog_decl->push_back (decl_info);
+ }
+ }
+ }
+
+ if (info->show_all_reorg_cands_in_detail)
+ {
+ fprintf (dump_file, "find_decls_and_types: Found the following types:\n");
+ print_reorgs (dump_file, 2, info);
+ }
+
+ return true;
+}
+
+void
+disqualify_struct_in_struct_or_union (Info_t *info)
+{
+ varpool_node *var;
+ std::set<tree> typeset;
+ FOR_EACH_VARIABLE (var)
+ {
+ tree decl = var->decl;
+ tree base = base_type_of (decl);
+ if (TREE_CODE (base) == RECORD_TYPE || TREE_CODE (base) == UNION_TYPE)
+ {
+ disq_str_in_str_or_union_helper (base, &typeset, info);
+ typeset.insert (base);
+ }
+ }
+
+ remove_deleted_types (info, &disqualify_struct_in_struct_or_union_debug);
+}
+
+static void
+initial_reorg_debug (Info *info, ReorgType *reorg)
+{
+ if (info->show_delete)
+ {
+ print_reorg_with_msg (dump_file, reorg, 2, "No Pointer to Structure");
+ }
+}
+
+static void
+disqualify_struct_in_struct_or_union_debug (Info *info, ReorgType *reorg)
+{
+ if (info->show_delete)
+ {
+ print_reorg_with_msg (dump_file, reorg, 2, "Interior Struct or Union");
+ }
+}
+
+static void
+disq_str_in_str_or_union_helper (tree type, std::set<tree> *typeset,
+ Info_t *info)
+{
+ if (typeset->find (type) != typeset->end ())
+ return;
+ tree fld;
+ for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
+ {
+ if (TREE_CODE (fld) == RECORD_TYPE)
+ {
+ ReorgType_t *rinfo = get_reorgtype_info (fld, info);
+ if (rinfo != NULL)
+ {
+ delete_reorgtype (rinfo, info);
+ }
+ else
+ {
+ disq_str_in_str_or_union_helper (fld, typeset, info);
+ typeset->insert (fld); // might be bug here
+ }
+ }
+ else
+ {
+ if (TREE_CODE (fld) == UNION_TYPE)
+ {
+ disq_str_in_str_or_union_helper (fld, typeset, info);
+ typeset->insert (fld); // might be bug here
+ }
+ }
+ }
+ return;
+}
+
+static unsigned int
+reorg_qualification (Info_t *info)
+{
+ // TBD
+ // This only does a generic legality qualification and each
+ // subpass does its own performance qualification.
+}
+
+void
+delete_reorgtype (ReorgType_t *rt, Info_t *info)
+{
+ if (!rt->delete_me)
+ {
+ info->num_deleted++;
+ rt->delete_me = true;
+ }
+}
+
+void
+undelete_reorgtype (ReorgType_t *rt, Info_t *info)
+{
+ if (rt->delete_me)
+ {
+ info->num_deleted--;
+ rt->delete_me = false;
+ }
+}
+
+void
+clear_deleted_types (Info *info)
+{
+ info->saved_reorg_type->clear ();
+}
+
+void
+restore_deleted_types (Info *info)
+{
+ while (!info->saved_reorg_type->empty ())
+ {
+ info->reorg_type->push_back (info->saved_reorg_type->back ());
+ info->saved_reorg_type->pop_back ();
+ }
+}
+
+void
+remove_deleted_types (Info *info, ReorgFn reorg_fn)
+{
+ if (info->show_delete)
+ {
+ fprintf (dump_file, "DELETING REORG TYPES:\n");
+ }
+
+ if (info->num_deleted > 0)
+ {
+ // Do delete here and run reorg_fn on each
+ // deleted type
+ int n = info->reorg_type->size ();
+ int to = 0;
+ for (int from = 0; from < n; from++)
+ {
+ if (!(*(info->reorg_type))[from].delete_me)
+ {
+ // Save copy of removed entry
+ (*(info->reorg_type))[from].delete_me = false;
+ info->saved_reorg_type->push_back ((*(info->reorg_type))[from]);
+
+ // Delete by not copying deleted elements
+ if (from != to)
+ {
+ if (reorg_fn != NULL)
+ {
+ (*reorg_fn) (info, &(*(info->reorg_type))[from]);
+ }
+ (*(info->reorg_type))[to] = (*(info->reorg_type))[from];
+ }
+ to++;
+ }
+ }
+ info->reorg_type->resize (n - info->num_deleted);
+ info->num_deleted = 0;
+ }
+}
+
+static tree
+base_type_of (tree type)
+{
+ for (; POINTER_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == VAR_DECL;
+ type = TREE_TYPE (type))
+ ;
+ return type;
+}
+
+// There are other allocations such as alloca or
+// aligned allocs that I'm pretty sure are not
+// a good fit for structure reorg optimization.
+// Also, we do handle realloc but it doesn't
+// create a new pool of memory so we ignore it here.
+static bool
+is_reorg_alloc_trigger (gimple *stmt)
+{
+ return gimple_call_builtin_p (stmt, BUILT_IN_MALLOC)
+ || gimple_call_builtin_p (stmt, BUILT_IN_CALLOC);
+}
+
+static ReorgType_t *
+find_struct_type_ptr_to_struct (tree type, Info *info)
+{
+ if (!POINTER_TYPE_P (type))
+ {
+ return NULL;
+ }
+ for (; POINTER_TYPE_P (type); type = TREE_TYPE (type))
+ ;
+
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ return get_reorgtype_info (type, info);
+ }
+ return NULL;
+}
+
+// TBD Garbage just so it will compile
+// What's dicey about this is it may sort of work but then I
+// can see places where it wouldn't... The language has a say
+// in what types are equal so maybe language hooks are involved???
+bool
+same_type_p (tree a, tree b)
+{
+ // DEBUG( "same_type_p:\n");
+ // DEBUG( " a: TREE_CODE = %s, name = %p\n
+ // ",code_str(TREE_CODE(a)),TYPE_NAME(a)); DEBUG_F( print_generic_expr, stderr,
+ // a, (dump_flags_t)-1); DEBUG( "\n b TREE_CODE = %s, name = %p\n
+ // ",code_str(TREE_CODE(b)),TYPE_NAME(b)); DEBUG_F( print_generic_expr, stderr,
+ // b, (dump_flags_t)-1); DEBUG( "\n");
+ gcc_assert (TREE_CODE (a) == RECORD_TYPE && TYPE_NAME (a) != 0);
+ gcc_assert (TREE_CODE (b) == RECORD_TYPE && TYPE_NAME (b) != 0);
+ return TYPE_NAME (a) == TYPE_NAME (b);
+}
+
+// May need to add secondary map container to
+// look them up or even modify the container
+// type of ReorgType
+static ReorgType_t *
+get_reorgtype_info (tree type, Info_t *info)
+{
+ // Note, I'm going to use the most stupid and slowest possible way
+ // to do this. The advanage is it will be super easy and almost
+ // certainly correct. It will also almost certainly need to be
+ // improved but I get something out there now.
+ for (std::vector<ReorgType_t>::iterator ri = info->reorg_type->begin ();
+ ri != info->reorg_type->end (); ri++)
+ {
+ // TBD the internal docs lie and same_type_p doesn't exist
+ // (at least it's not available here at LTO time)
+ // so this is just a place holder until I can get an answer
+ // from the gcc community. Note, this is a big issue.
+ // Remember, the same_type_p here is my own temporary hack.
+ if (same_type_p (ri->gcc_type, type))
+ {
+ return &(*ri);
+ }
+ }
+ return NULL;
+}
+
+static void
+print_reorg_with_msg (FILE *file, ReorgType_t *reorg, int leading_space,
+ const char *msg)
+{
+ fprintf (file, "%*s%s:\n", leading_space, "", msg);
+ print_reorg (file, leading_space + 2, reorg);
+}
+
+static void
+dump_reorg (ReorgType_t *reorg)
+{
+ print_reorg (stderr, 0, reorg);
+}
+
+static void
+print_reorgs (FILE *file, int leading_space, Info *info)
+{
+ for (int i = 0; i < info->reorg_type->size (); i++)
+ {
+ print_reorg (file, leading_space, &(*(info->reorg_type))[i]);
+ }
+}
+
+static void
+print_reorg (FILE *file, int leading_space, ReorgType_t *reorg)
+{
+ // TBD
+ // note if reorg_perf & regular_perf are nonzero
+ // synthesize and display absolute_effect & raw_effect
+
+ // Note, the following is a stub.
+ const char *text
+ = identifier_to_locale (IDENTIFIER_POINTER (TYPE_NAME (reorg->gcc_type)));
+ fprintf (file, "%*s{ type:%s, id:%d, ... }\n", leading_space, "", text,
+ reorg->id);
+}
+
+//-- debugging only --
+static const char *
+code_str (enum tree_code tc)
+{
+ switch (tc)
+ {
+ case POINTER_TYPE:
+ return "POINTER_TYPE";
+ case RECORD_TYPE:
+ return "RECORD_TYPE";
+ case UNION_TYPE:
+ return "UNION_TYPE";
+ case ARRAY_TYPE:
+ return "ARRAY_TYPE";
+ case REFERENCE_TYPE:
+ return "REFERENCE_TYPE";
+ case VAR_DECL:
+ return "VAR_DECL";
+ case TYPE_DECL:
+ return "TYPE_DECL";
+ case CONST_DECL:
+ return "CONST_DECL";
+ default:
+ switch (TREE_CODE_CLASS (tc))
+ {
+ case tcc_type:
+ return "class type";
+ case tcc_declaration:
+ return "class declaration";
+ case tcc_reference:
+ return "class reference";
+ default:
+ return "unknown class";
+ }
+ }
+}
+
+//---------------- Pass Control Follows ----------------
+
+const pass_data pass_data_ipa_structure_reorg = {
+ SIMPLE_IPA_PASS, /* type */
+ "structure-reorg", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ // TV_IPA_SRA, /* tv_id */ // TBD
+ TV_IPA_STRUCTURE_REORG, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ //( TODO_dump_symtab | TODO_remove_functions ), /* todo_flags_finish */ // ???
+ (TODO_update_ssa | TODO_update_address_taken | TODO_cleanup_cfg
+ | TODO_remove_unused_locals),
+ /* todo_flags_finish */ // ???
+};
+
+class pass_ipa_structure_reorg : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_structure_reorg (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_ipa_structure_reorg, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return ((flag_ipa_structure_reorg || flag_ipa_instance_interleave
+ || flag_ipa_field_reorder || flag_ipa_dead_field_eliminate));
+ }
+
+ virtual unsigned int execute (function *) { return ipa_structure_reorg (); }
+
+}; // class ipa_structure_reorg
+
+// ipa_opt_pass_d *
+simple_ipa_opt_pass *
+make_pass_ipa_structure_reorg (gcc::context *ctxt)
+{
+ return new pass_ipa_structure_reorg (ctxt);
+}
diff --git a/gcc/ipa-structure-reorg.h b/gcc/ipa-structure-reorg.h
new file mode 100644
index 00000000000..910f066b677
--- /dev/null
+++ b/gcc/ipa-structure-reorg.h
@@ -0,0 +1,154 @@
+/* Interprocedural scalar replacement of aggregates
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <goblock@marvell.com>
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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/>. */
+
+typedef struct ReorgType ReorgType_t;
+struct ReorgType
+{
+ unsigned id;
+ tree gcc_type;
+ int numbOfGlobalArrays; // Statically allocated only
+ int numbOfLocalArrays; // Statically allocated only
+ int numbOfDynmAllocs;
+ double reorg_perf;
+ double regular_perf;
+ bool multi_pool; // single pool if not set
+ bool delete_me;
+ tree clone; // the base
+ tree pointer_rep; // new pointer format (multi-pool)
+};
+
+typedef struct ProgDecl ProgDecl_t;
+struct ProgDecl
+{
+ tree gcc_decl;
+};
+
+enum ReorgOpTrans
+{
+ ReorgT_Address, // "&x[i]"
+ ReorgT_Pointer, // "a"
+ ReorgT_Struct, // "s"
+ ReorgT_Deref, // "*a"
+ ReorgT_Array, // "x[i]"
+ ReorgT_Scalar, // "z"
+ ReorgT_Indirect, // "a->f"
+ ReorgT_AryDir // "x[i].f"
+};
+
+enum CompressionControl
+{
+ Initial,
+ Subsequent
+};
+
+enum ReorgTransformation
+{
+ ReorgT_StrAssign, // "*a = x[i]", "x[i] = y[j]", "s = *a", etc.
+ ReorgT_ElemAssign, // "a->f = z", "z = x[i].f", etc.
+ ReorgT_If_Null, // "if(a == 0)..."
+ ReorgT_If_NotNull, // "if(a != 0)..."
+ ReorgT_IfPtrEQ, // "if(a == b)..."
+ ReorgT_IfPtrNE, // "if(a != b)..."
+ ReorgT_IfPtrLT, // "if(a < b)..."
+ ReorgT_IfPtrGT, // "if(a > b)..."
+ ReorgT_IfPtrLE, // "if(a <= b)..."
+ ReorgT_IfPtrGE, // "if(a >= b)..."
+ ReorgT_PtrPlusInt, // "a = b + i"
+ ReorgT_Ptr2Zero, // "a = 0"
+ ReorgT_PtrDiff, // "i = a - b"
+ ReorgT_Adr2Ptr, // "a = &x[i]"
+ ReorgT_PtrNull, // "x = a == 0"
+ ReorgT_PtrNotNull, // "x = a != 0"
+ ReorgT_PtrEQ, // "x = a == b"
+ ReorgT_PtrNE, // "x = a != b"
+ ReorgT_PtrLT, // "x = a < b"
+ ReorgT_PtrLE, // "x = a <= b"
+ ReorgT_PtrGT, // "x = a > b"
+ ReorgT_PtrGE, // "x = a >= b"
+ ReorgT_Malloc, //
+ ReorgT_Calloc, //
+ ReorgT_Realloc, //
+ ReorgT_Free, //
+ Not_Supported
+};
+
+// Added as design bug fix
+typedef struct BoolPair BoolPair_t;
+struct BoolPair
+{
+ bool processed;
+ bool layout_changed;
+};
+
+typedef struct Info Info_t;
+struct Info
+{
+ std::vector<ReorgType_t> *reorg_type;
+ // Added to by remove_deleted_types
+ std::vector<ReorgType_t> *saved_reorg_type;
+ std::vector<ProgDecl_t> *prog_decl;
+ // Gcc doesn't have global decls readily available
+ // so this holds them
+ std::map<tree, BoolPair_t> *struct_types; // desing bug fix
+ int num_deleted;
+ double total_cache_accesses;
+ // Debug flags
+ bool show_all_reorg_cands;
+ bool show_all_reorg_cands_in_detail;
+ bool show_delete;
+ bool show_new_BBs;
+ bool show_transforms;
+ bool show_bounds;
+};
+
+// This will perform a function on the supplied
+// reorg type. It's primarily to support debugging.
+typedef void (*ReorgFn) (Info *, ReorgType_t *);
+
+extern int
+str_reorg_dead_field_eliminate (Info *);
+extern int
+str_reorg_field_reorder (Info *);
+extern int
+str_reorg_instance_interleave (Info *);
+
+extern void
+delete_reorgtype (ReorgType_t *, Info_t *);
+extern void
+undelete_reorgtype (ReorgType_t *, Info_t *);
+extern void
+clear_deleted_types (Info *);
+extern void
+restore_deleted_types (Info *);
+extern void
+remove_deleted_types (Info *, ReorgFn reorg_fn);
+
+// I have no intention of leaving this or uses of the
+// defined marcos in the code. However, some of uses
+// should obviously be converted to dump file information.
+
+#if 1
+#define DEBUG(...) fprintf (stderr, __VA_ARGS__)
+#define DEBUG_F(f, ...) f (__VA_ARGS__)
+#else
+#define DEBUG(...)
+#define DEBUG_F(...)
+#endif
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
new file mode 100644
index 00000000000..f4db0b6183f
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.c
@@ -0,0 +1,1029 @@
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "options.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "predict.h"
+#include "alloc-pool.h"
+#include "tree-pass.h"
+#include "cgraph.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "gimple-fold.h"
+#include "symbol-summary.h"
+#include "tree-vrp.h"
+#include "ipa-prop.h"
+#include "tree-pretty-print.h"
+#include "tree-cfg.h"
+#include "gimple-pretty-print.h"
+#include "tree-inline.h"
+#include "ipa-fnsummary.h"
+#include "ipa-utils.h"
+#include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include <stdbool.h>
+
+#include "ipa-str-reorg-utils.h"
+#include "ipa-type-escape-analysis.h"
+
+
+// First we need to collect all types
+
+static bool filter_type (type_map &escape_map, const_tree type);
+
+void update_escape_info (const_tree type, type_map &escape_map, bool is_escaping, escaping_reason reason);
+
+static const escaping_reason null_reason = { 0, 0, 0, 0 };
+inline escaping_reason
+new_escaping_reason()
+{
+ return null_reason;
+}
+
+//TODO:
+// Should we be using C++?
+escaping_reason
+union_op(const escaping_reason &left, const escaping_reason &right)
+{
+ escaping_reason retval;
+ retval.global_is_visible = left.global_is_visible | right.global_is_visible;
+ retval.parameter_is_visible = left.parameter_is_visible | right.parameter_is_visible;
+ retval.return_is_visible = left.return_is_visible | right.return_is_visible;;
+ retval.type_is_casted = left.type_is_casted | right.type_is_casted;;
+ return retval;
+}
+
+void
+explain_print(escaping_reason reason)
+{
+ if (reason.global_is_visible) log("global is visible");
+ if (reason.parameter_is_visible) log(", parameter is visible");
+ if (reason.return_is_visible) log(", return is visible");
+ if (reason.type_is_casted) log(", type is casted");
+ log("\n");
+}
+
+void
+update_escape_info_pointer (const_tree pointer_type, type_map &escape_map, bool is_escaping, escaping_reason reason)
+{
+ gcc_assert(pointer_type);
+ enum tree_code tree_code_pointer_type = TREE_CODE(pointer_type);
+ bool is_pointer_type = POINTER_TYPE == tree_code_pointer_type;
+ gcc_assert(is_pointer_type);
+
+ escaping_info *info = escape_map.get(pointer_type);
+ if (!info) { log("no info for %s\n", get_type_name(pointer_type)); return;}
+
+ info->is_escaping |= is_escaping;
+ info->reason = union_op(info->reason, reason);
+ tree tree_type_pointer_type = TREE_TYPE(pointer_type);
+ gcc_assert(tree_type_pointer_type);
+ update_escape_info (tree_type_pointer_type, escape_map, info->is_escaping, info->reason);
+}
+
+void
+update_escape_info_array (const_tree array_type, type_map &escape_map, bool is_escaping, escaping_reason reason)
+{
+ gcc_assert(array_type);
+ enum tree_code tree_code_array_type = TREE_CODE(array_type);
+ bool is_array_type = ARRAY_TYPE == tree_code_array_type;
+ gcc_assert(is_array_type);
+
+ escaping_info *info = escape_map.get(array_type);
+ if (!info) { log("no info for %s\n", get_type_name(array_type)); return;}
+
+ info->is_escaping |= is_escaping;
+ info->reason = union_op(info->reason, reason);
+ tree tree_type_array_type = TREE_TYPE(array_type);
+ gcc_assert(tree_type_array_type);
+ update_escape_info (tree_type_array_type, escape_map, info->is_escaping, info->reason);
+}
+
+void
+update_escape_info_record (const_tree record_type, type_map &escape_map, bool is_escaping, escaping_reason reason)
+{
+ gcc_assert(record_type);
+ enum tree_code tree_code_record_type = TREE_CODE(record_type);
+ bool is_record_type = RECORD_TYPE == tree_code_record_type;
+ gcc_assert(is_record_type);
+
+ escaping_info *info = escape_map.get(record_type);
+ // we are collecting records, therefore, we **must** have
+ // it in the escaping info
+ //FIXME: Is this true? According to creduce bug, no.
+ gcc_assert(info);
+ info->is_escaping |= is_escaping;
+ info->reason = union_op(info->reason, reason);
+
+
+ for (tree field = TYPE_FIELDS (record_type); field; field = DECL_CHAIN (field))
+ {
+ gcc_assert(field);
+ tree tree_type_field = TREE_TYPE(field);
+ gcc_assert(tree_type_field);
+ update_escape_info (tree_type_field, escape_map, info->is_escaping, info->reason);
+ }
+}
+
+void
+update_escape_info (const_tree type, type_map &escape_map, bool is_escaping, escaping_reason reason)
+{
+ // INFO: This is an optimization.
+ if (!is_escaping) { log("is not escaping\n"); return; }
+
+ gcc_assert(type);
+ enum tree_code tree_code_type = TREE_CODE(type);
+ // We need to make sure that we are only dealing with
+ // the main type and not typedefs...
+ switch (tree_code_type)
+ {
+ case ARRAY_TYPE:
+ update_escape_info_array(type, escape_map, is_escaping, reason);
+ break;
+ case POINTER_TYPE:
+ update_escape_info_pointer(type, escape_map, is_escaping, reason);
+ break;
+ case RECORD_TYPE:
+ update_escape_info_record(type, escape_map, is_escaping, reason);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool
+filter_pointer (type_map &escape_map, const_tree pointer)
+{
+ enum tree_code code = TREE_CODE (pointer);
+ gcc_assert(POINTER_TYPE == code);
+ const_tree base_type = TREE_TYPE(pointer);
+ return filter_type (escape_map, base_type);
+}
+
+static bool
+filter_array (type_map &escape_map, const_tree array)
+{
+ enum tree_code code = TREE_CODE (array);
+ gcc_assert(ARRAY_TYPE == code);
+ const_tree base_type = TREE_TYPE(array);
+ return filter_type (escape_map, base_type);
+}
+
+static bool
+filter_record (type_map &escape_map, const_tree record)
+{
+ log("filtering record %s\n", get_type_name(record));
+ gcc_assert(record);
+ enum tree_code code = TREE_CODE(record);
+ gcc_assert(RECORD_TYPE == code);
+
+ for (tree field = TYPE_FIELDS (record); field; field = DECL_CHAIN (field))
+ {
+ tree field_type = TREE_TYPE(field);
+ gcc_assert(field_type);
+ filter_type(escape_map, field_type);
+ }
+
+ return false;
+}
+
+static bool
+filter_type (type_map &escape_map, const_tree type)
+{
+ log("inside filter_type\n");
+
+ if (!type) return true;
+
+ bool retval = true;
+ enum tree_code code = TREE_CODE(type);
+ switch (code)
+ {
+ case ARRAY_TYPE: retval = filter_array(escape_map, type); break;
+ case POINTER_TYPE: retval = filter_pointer(escape_map, type); break;
+ case RECORD_TYPE: retval = filter_record(escape_map, type); break;
+ default: break;
+ }
+
+
+ log("filter_type %s boring ? %s\n", get_type_name(type), retval ? "true" : "false");
+ if (retval) return retval;
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { type , false , reason};
+ escape_map.put(type, info);
+ return retval;
+}
+
+static bool
+filter_var_decl (type_map &escape_map, const_tree var_decl)
+{
+ log("filtering var_decl\n");
+ gcc_assert(var_decl);
+ enum tree_code code = TREE_CODE(var_decl);
+ gcc_assert(code == VAR_DECL);
+ tree type = TREE_TYPE (var_decl);
+ gcc_assert(type);
+ return filter_type(escape_map, type);
+}
+
+static bool
+filter_parm_declarations (const_tree parm_decl, type_map &escape_map)
+{
+ gcc_assert(parm_decl);
+ enum tree_code code = TREE_CODE(parm_decl);
+ gcc_assert(PARM_DECL == code);
+ tree type = TREE_TYPE (parm_decl);
+ gcc_assert(type);
+ return filter_type(escape_map, type);
+}
+
+static void
+collect_global(type_map &escape_map, varpool_node *vnode)
+{
+ log("collect_global\n");
+ gcc_assert(vnode);
+
+ struct ipa_ref *ref = NULL;
+ for (int i = 0; vnode->iterate_referring (i, ref); i++)
+ {
+ log("inside vnode loop\n");
+ tree decl = vnode->decl;
+ gcc_assert(decl);
+ enum tree_code code = TREE_CODE(decl);
+ gcc_assert(VAR_DECL == code);
+ bool filter_out = filter_var_decl(escape_map, decl);
+ if (filter_out) continue;
+
+ tree type = TREE_TYPE(decl);
+ gcc_assert(type);
+ log("collecting global type escape analysis %s\n", get_type_name(type));
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { type, false, reason };
+ escape_map.put (type, info);
+ //escape_map.put (TYPE_MAIN_VARIANT(type), info);
+ }
+}
+
+static void
+collect_globals(type_map &escape_map)
+{
+ varpool_node *vnode;
+ FOR_EACH_VARIABLE (vnode)
+ {
+ collect_global(escape_map, vnode);
+ }
+}
+
+static void
+collect_parm_declarations (cgraph_node *cnode, type_map &escape_map)
+{
+ gcc_assert(cnode);
+ log("does function %s have parameters?\n", cnode->name());
+ for (tree parm = DECL_ARGUMENTS (cnode->decl); parm; parm = DECL_CHAIN (parm))
+ {
+ tree type = TREE_TYPE(parm);
+ log("about to enter parameter type %s\n", get_type_name(type));
+ bool filter_out = filter_parm_declarations (parm, escape_map);
+ if (filter_out) continue;
+
+ log("putting parameter type %s\n", get_type_name(type));
+ gcc_assert(type);
+
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { type, false, reason };
+ escape_map.put(type, info);
+ }
+}
+
+static void
+collect_local_declarations (cgraph_node *cnode, type_map &escape_map)
+{
+ gcc_assert(cnode);
+ int i = 0;
+ function *func = DECL_STRUCT_FUNCTION (cnode->decl);
+ cnode->get_untransformed_body ();
+ tree var_decl = NULL;
+ FOR_EACH_LOCAL_DECL (func, i, var_decl)
+ {
+ gcc_assert(var_decl);
+ bool filter_out = filter_var_decl(escape_map, var_decl);
+ if (filter_out) continue;
+
+ tree tree_type = TREE_TYPE(var_decl);
+ gcc_assert(tree_type);
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { tree_type, false, reason};
+ escape_map.put(tree_type, info);
+ }
+}
+
+static void collect_expr (const_tree expr, type_map &escape_map);
+
+static void
+collect_expr_in_component_ref(const_tree cref, type_map &escape_map)
+{
+ gcc_assert(cref);
+ const enum tree_code code = TREE_CODE(cref);
+ const bool is_cref = COMPONENT_REF == code;
+ gcc_assert(is_cref);
+
+ const_tree _struct = TREE_OPERAND(cref, 0);
+ gcc_assert(_struct);
+
+ const_tree _struct_type = TREE_TYPE(_struct);
+ log("we are in collect_expr_in_component_ref %s\n", get_type_name(_struct_type));
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { _struct_type, false , reason};
+ escape_map.put(_struct_type, info);
+
+ collect_expr(_struct, escape_map);
+
+}
+
+static void
+collect_expr (const_tree expr, type_map &escape_map)
+{
+ gcc_assert(expr);
+ enum tree_code tree_code_expr = TREE_CODE(expr);
+ switch (tree_code_expr)
+ {
+ case COMPONENT_REF:
+ collect_expr_in_component_ref(expr, escape_map);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+collect_pointer_plus (tree lhs, tree rhs1, tree rhs2, type_map &escape_map)
+{
+ log("collect_pointer_plus\n");
+ const_tree lhs_type = lhs ? TREE_TYPE(lhs) : NULL;
+ bool is_lhs_boring = lhs_type ? filter_type(escape_map, lhs_type) : true;
+ const_tree rhs1_type = rhs1 ? TREE_TYPE(rhs1) : NULL;
+ bool is_rhs1_boring = rhs1_type ? filter_type(escape_map, rhs1_type) : true;
+ const_tree rhs2_type = rhs2 ? TREE_TYPE(rhs2) : NULL;
+ bool is_rhs2_boring = rhs2_type ? filter_type(escape_map, rhs2_type) : true;
+
+ if (!is_lhs_boring)
+ {
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = { lhs_type , false, reason };
+ escape_map.put(lhs_type, info);
+ }
+ if (!is_rhs1_boring)
+ {
+ collect_expr(rhs1, escape_map);
+ }
+ if (!is_rhs2_boring)
+ {
+ collect_expr(rhs2, escape_map);
+ }
+}
+
+static void
+collect_assign_rhs (gimple *stmt, type_map &escape_map)
+{
+ enum tree_code code = gimple_expr_code (stmt);
+ switch (code)
+ {
+ case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
+ case COMPONENT_REF:
+ {
+ tree rhs2 = gimple_assign_rhs2(stmt);
+ tree rhs1 = gimple_assign_rhs1(stmt);
+ tree lhs = gimple_assign_lhs (stmt);
+ collect_pointer_plus (lhs, rhs1, rhs2, escape_map);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+collect_assign (gimple *stmt, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ collect_assign_rhs (stmt, escape_map);
+}
+
+static void
+collect_call_lhs (gimple *stmt, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs) return;
+
+ collect_expr (lhs, escape_map);
+}
+
+static void
+collect_call_rhs (gimple *stmt, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ tree fn = gimple_call_fn (stmt);
+
+ gcc_assert (fn);
+ gcall *call = dyn_cast <gcall *> (stmt);
+ //struct cgraph_node *n = cgraph_node::get (fn);
+ //if (n) log ("collecting arguments for %s \n", n->name());
+
+ tree return_type = gimple_call_return_type (call);
+ bool is_return_type_boring = filter_type(escape_map, return_type);
+
+ if (!is_return_type_boring) {
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = {return_type, false, reason};
+ escape_map.put(return_type, info);
+ }
+
+ unsigned args = gimple_call_num_args (stmt);
+ for (unsigned i = 0; i < args; i++)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ tree arg_type = TREE_TYPE(arg);
+ log("collecting argument of type %s\n", get_type_name(arg_type));
+ bool is_arg_boring = filter_type(escape_map, arg_type);
+ if (is_arg_boring) continue;
+
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = {arg_type, false, reason};
+ escape_map.put(arg_type, info);
+
+ }
+}
+
+static void
+collect_call(gimple *stmt, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ collect_call_lhs (stmt, escape_map);
+ collect_call_rhs (stmt, escape_map);
+}
+
+static void
+collect_stmt (gimple *stmt, type_map &escape_map)
+{
+ gcc_assert (stmt);
+ const enum gimple_code code = gimple_code (stmt);
+ switch (code)
+ {
+ case GIMPLE_ASSIGN:
+ collect_assign(stmt, escape_map);
+ break;
+ case GIMPLE_CALL:
+ collect_call(stmt, escape_map);
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+static void
+collect_basic_block (basic_block bb, type_map &escape_map)
+{
+ gcc_assert(bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ collect_stmt (stmt, escape_map);
+ }
+}
+
+static void
+collect_function_body (cgraph_node *cnode, type_map &escape_map)
+{
+ gcc_assert (cnode);
+ cnode->get_untransformed_body();
+ basic_block bb = NULL;
+ tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ push_cfun(func);
+ FOR_EACH_BB_FN (bb, func)
+ {
+ gcc_assert(bb);
+ collect_basic_block (bb, escape_map);
+ }
+ pop_cfun();
+}
+
+static void
+collect_return_type (cgraph_node *cnode, type_map &escape_map)
+{
+ gcc_assert(cnode);
+
+ const_tree decl = cnode->decl;
+ const enum tree_code code = TREE_CODE(decl);
+ const bool is_function_decl = FUNCTION_DECL == code;
+ gcc_assert (is_function_decl);
+
+ const_tree fn_type = TREE_TYPE (decl);
+ const enum tree_code fn_type_code = TREE_CODE(fn_type);
+ const bool is_fn_type = FUNCTION_TYPE == fn_type_code;
+ gcc_assert (is_fn_type);
+
+ const_tree ret_type = TREE_TYPE(fn_type);
+ gcc_assert (ret_type);
+
+ const bool is_boring = filter_type(escape_map, ret_type);
+ if (is_boring) return;
+
+ escaping_reason reason = new_escaping_reason();
+ escaping_info info = {ret_type, false, reason};
+ escape_map.put(ret_type, info);
+ return;
+}
+
+static void
+collect_types(type_map &escape_map)
+{
+ collect_globals(escape_map);
+
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION (cnode)
+ {
+ collect_function_body (cnode, escape_map);
+ collect_local_declarations (cnode, escape_map);
+ collect_parm_declarations (cnode, escape_map);
+ collect_return_type (cnode, escape_map);
+ }
+}
+
+bool
+_print_types( const_tree const &type, escaping_info *info, __attribute__((unused)) void*)
+{
+ log("collected,%s\n", get_type_name(type));
+ bool is_escaping = info->is_escaping;
+ log("type %s is escaping %s : ", get_type_name(type), is_escaping ? "true" : "false");
+ explain_print(info->reason);
+ return true;
+}
+
+static void
+print_types(type_map &escape_map)
+{
+ log("printing_types\n");
+ escape_map.traverse<void*, _print_types> (NULL);
+}
+
+static bool
+is_variable_escaping(varpool_node *vnode)
+{
+ gcc_assert(vnode);
+ return vnode->externally_visible;
+}
+
+static bool
+is_function_escaping(const cgraph_node *cnode)
+{
+ gcc_assert(cnode);
+ return cnode->externally_visible; /* TODO: How are FOR_EACH_FUNCTION and FOR_EACH_DEFINED_FUNCTION different */ // || !cnode->definition;
+}
+
+void calculate_escaping_parameters(const cgraph_node *cnode, type_map &escape_map, bool override = false);
+
+void
+calculate_escaping_parameters(const cgraph_node *cnode, type_map &escape_map, bool override)
+{
+ gcc_assert(cnode);
+ tree function = cnode->decl;
+ gcc_assert(function);
+ enum tree_code code = TREE_CODE (function);
+ bool is_function_decl = FUNCTION_DECL == code;
+ gcc_assert (is_function_decl);
+
+ bool is_escaping = is_function_escaping(cnode) || override;
+ function_args_iterator iter;
+ tree arg;
+ const_tree function_type = TREE_TYPE(function);
+ FOREACH_FUNCTION_ARGS (function_type, arg, iter)
+ {
+ //const_tree main_type = TYPE_MAIN_VARIANT(arg);
+ log("parameter type %s is escaping %s in function %s\n", get_type_name(arg), is_escaping ? "true" : "false", cnode->name());
+ escaping_reason reason = new_escaping_reason();
+ reason.parameter_is_visible = is_escaping;
+ update_escape_info(arg, escape_map, is_escaping, reason);
+ }
+}
+void is_return_type_escaping(const cgraph_node *cnode, type_map &escape_map, bool override = false);
+
+void
+is_return_type_escaping(const cgraph_node *cnode, type_map &escape_map, bool override)
+{
+ gcc_assert(cnode);
+ bool is_escaping = is_function_escaping(cnode) || override;
+ tree function = cnode->decl;
+ gcc_assert(function);
+ enum tree_code code = TREE_CODE(function);
+ bool is_function = FUNCTION_DECL == code;
+ gcc_assert(is_function);
+
+ tree tree_type = TREE_TYPE(function);
+ gcc_assert(tree_type);
+ tree return_type = TREE_TYPE(tree_type);
+ gcc_assert(return_type);
+ log("return type %s\n", get_type_name(return_type));
+
+ // void update_escaping_info (const_tree type, type_map &escape_map, bool is_escaping);
+/*struct escaping_reason_s {
+ unsigned global_is_visible : 1;
+ unsigned function_is_visible : 1;
+};
+*/
+ escaping_reason reason = new_escaping_reason();
+ reason.return_is_visible = is_escaping;
+ update_escape_info(return_type, escape_map, is_escaping, reason);
+ //escaping_info *info = escape_map.get(return_type);
+ // If there's no info it means it is not interesting...
+ //if (!info) return;
+ //info->is_escaping |= is_escaping;
+}
+
+
+bool
+calculate_escaping_types_from_function_signatures (
+ cgraph_node * const &cnode, type_map *escape_map)
+{
+
+ gcc_assert(escape_map);
+ gcc_assert(cnode);
+ bool is_escaping = is_function_escaping(cnode);
+ log("function %s is escaping %s\n", cnode->name(), is_escaping ? "true" : "false");
+ calculate_escaping_parameters(cnode, *escape_map, is_escaping);
+ is_return_type_escaping(cnode, *escape_map, is_escaping);
+ return true;
+}
+
+void
+find_calls_to_undefined_functions_from_call(gimple *stmt, hash_set<tree> &set, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code(stmt);
+ const bool is_gimple_call = GIMPLE_CALL == code;
+ gcc_assert(is_gimple_call);
+
+ gcall *call = dyn_cast<gcall *>(stmt);
+ tree fn = gimple_call_fndecl(stmt);
+
+ // Function pointer?
+ if (!fn) return;
+
+ // Do we ever see a function with the name __xstat?
+ gcc_assert(fn);
+ cgraph_node *n = cgraph_node::get (fn);
+ //gcc_assert(n);
+ log("here2 %s\n", n ? n->name() : "there's no cnode!");
+ log("is contained in set ? %s\n", set.contains(fn) ? "true" : "false");
+
+ // if fn is in set... then it means that it is undefined.
+ if (!set.contains(fn)) return;
+
+ unsigned num_arguments = gimple_call_num_args(call);
+ for (unsigned i = 0; i < num_arguments; i++)
+ {
+ tree argument = gimple_call_arg(stmt, i);
+ /*
+ // TODO: Why is this the case?
+ gimple *def_for_arg = SSA_NAME_DEF_STMT(argument);
+ gcc_assert(def_for_arg);
+ const enum gimple_code code2 = gimple_code(def_for_arg);
+ const bool is_gimple_call2 = GIMPLE_CALL == code2;
+ const bool is_gimple_assign = GIMPLE_ASSIGN == code2;
+ const bool is_assignable = is_gimple_call2 ^ is_gimple_assign;
+ gcc_assert(is_assignable);
+
+ tree arg_var = is_gimple_assign ? gimple_assign_lhs(def_for_arg) : gimple_call_lhs(def_for_arg);
+ gcc_assert(arg_var);
+ */
+ tree arg_type = TREE_TYPE(argument);
+ gcc_assert(arg_type);
+
+ bool is_escaping = true;
+ escaping_reason reason = new_escaping_reason();
+ reason.parameter_is_visible = is_escaping;
+ update_escape_info(arg_type, escape_map, is_escaping, reason);
+ }
+}
+
+void
+find_calls_to_undefined_functions_from_stmt(gimple *stmt, hash_set<tree> &set, type_map &escape_map)
+{
+ gcc_assert(stmt);
+ const enum gimple_code code = gimple_code (stmt);
+ const bool is_gimple_call = GIMPLE_CALL == code;
+ if (!is_gimple_call) return;
+
+ find_calls_to_undefined_functions_from_call(stmt, set, escape_map);
+}
+
+
+void
+find_calls_to_undefined_functions_from_bb(basic_block bb, hash_set<tree> &set, type_map &escape_map)
+{
+ gcc_assert(bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ find_calls_to_undefined_functions_from_stmt(stmt, set, escape_map);
+ }
+}
+
+void
+find_calls_to_undefined_functions_from_function(cgraph_node *cnode, hash_set<tree> &set, type_map &escape_map)
+{
+ gcc_assert(cnode);
+ cnode->get_untransformed_body ();
+ log("%s is an undefined function\n", cnode->name());
+ function *func = DECL_STRUCT_FUNCTION(cnode->decl);
+ basic_block bb = NULL;
+ push_cfun(func);
+ FOR_EACH_BB_FN(bb, func)
+ {
+ find_calls_to_undefined_functions_from_bb(bb, set, escape_map);
+ }
+ pop_cfun();
+}
+
+void
+is_any_function_escaping(type_map &escape_map)
+{
+ cgraph_node *cnode = NULL;
+ hash_set<tree> not_defined_functions;
+
+ FOR_EACH_FUNCTION (cnode)
+ {
+ gcc_assert(cnode);
+ const char* _free = "free";
+ //const char* _memset = "memset";
+ const char* _malloc = "malloc";
+ const char* _realloc = "realloc";
+ const char* _calloc= "calloc";
+ const char* ob_name = cnode->name();
+ //log("for each function %s\n", cnode->name()); // We do see __xstat...
+ if (strcmp(ob_name, _free) == 0) continue;
+ //if (strcmp(ob_name, _memset) == 0) continue;
+ if (strcmp(ob_name, _malloc) == 0) continue;
+ if (strcmp(ob_name, _realloc) == 0) continue;
+ if (strcmp(ob_name, _calloc) == 0) continue;
+
+ not_defined_functions.add(cnode->decl);
+ }
+
+
+ FOR_EACH_DEFINED_FUNCTION(cnode)
+ {
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ not_defined_functions.remove(cnode->decl);
+ //log("for each defined function %s\n", cnode->name()); // We don't see __xstat...
+ calculate_escaping_types_from_function_signatures (cnode, &escape_map);
+ }
+
+ // not_defined_functions.traverse<type_map *, calculate_escaping_types_from_function_signatures> (&escape_map);
+ //TODO: Walk gimple code and identify GIMPLE_CALL to see if function is not defined...
+ FOR_EACH_DEFINED_FUNCTION(cnode)
+ {
+ find_calls_to_undefined_functions_from_function(cnode, not_defined_functions, escape_map);
+ }
+}
+
+void
+is_any_variable_escaping(type_map &escape_map)
+{
+ varpool_node *vnode = NULL;
+ // Global variables
+ FOR_EACH_VARIABLE(vnode)
+ {
+ bool is_escaping = is_variable_escaping(vnode);
+ log("variable %s is escaping %s\n", vnode->name(), is_escaping ? "true" : "false");
+ tree decl = vnode->decl;
+ gcc_assert(decl);
+ tree type = TREE_TYPE(decl);
+ gcc_assert(type);
+ // void update_escaping_info (const_tree type, type_map &escape_map, bool is_escaping);
+ escaping_reason reason = new_escaping_reason();
+ reason.global_is_visible = is_escaping;
+ update_escape_info (type, escape_map, is_escaping, reason);
+ //escaping_info *info = escape_map.get(type);
+ //if (!info) return;
+ //info->is_escaping |= is_escaping;
+ }
+}
+
+//TODO: place in header file
+inline static void
+print_function (cgraph_node *cnode)
+{
+ if (!dump_file)
+ return;
+ gcc_assert (cnode);
+ cnode->get_untransformed_body ();
+ dump_function_to_file (cnode->decl, dump_file, TDF_NONE);
+}
+
+static bool
+cast_to_void_in_assign(const_tree lhs, const_tree rhs, type_map &escape_map)
+{
+ gcc_assert(lhs);
+ gcc_assert(rhs);
+ const_tree tree_type_lhs = TREE_TYPE(lhs);
+ gcc_assert(tree_type_lhs);
+ const_tree tree_type_rhs = TREE_TYPE(rhs);
+ gcc_assert(tree_type_rhs);
+ const char* const type_name_lhs = get_type_name(tree_type_lhs);
+ const char* const type_name_rhs = get_type_name(tree_type_rhs);
+ enum tree_code tree_code_rhs = TREE_CODE(rhs);
+ bool is_ssa_name = SSA_NAME == tree_code_rhs;
+ bool is_var_decl = VAR_DECL == tree_code_rhs;
+ bool is_var_decl_or_ssa_name = is_ssa_name || is_var_decl;
+ log("lhs = %s, rhs = %s\n", type_name_lhs, type_name_rhs);
+ if (!is_var_decl_or_ssa_name) return false;
+
+ // We need to find out the base...
+ const_tree base_type_lhs = get_base_type(tree_type_lhs);
+ gcc_assert(base_type_lhs);
+ const_tree base_type_rhs = get_base_type(tree_type_rhs);
+ gcc_assert(base_type_rhs);
+ // TODO: FIXME:
+ // Is this always correct? I think this can only happen
+ // if we are mallocing and friends...
+ enum tree_code tree_code_base_type_rhs = TREE_CODE(base_type_rhs);
+ if (tree_code_base_type_rhs == VOID_TYPE) return false;
+
+ bool is_casting_stmt = TYPE_MAIN_VARIANT(base_type_lhs) != TYPE_MAIN_VARIANT(base_type_rhs);
+ log("is casting stmt ? %s\n", is_casting_stmt ? "true" : "false");
+ if (!is_casting_stmt) return false;
+
+ log("escaping lhs %s\n", type_name_lhs);
+ escaping_reason reason = new_escaping_reason();
+ reason.type_is_casted = is_casting_stmt;
+ update_escape_info(tree_type_lhs, escape_map, is_casting_stmt, reason);
+
+ log("escaping rhs %s\n", type_name_rhs);
+ update_escape_info(tree_type_rhs, escape_map, is_casting_stmt, reason);
+ return true;
+}
+
+static void
+cast_to_void_in_assign (gimple *stmt, type_map &escape_map)
+{
+ enum gimple_code gcode = gimple_code (stmt);
+ const char* const gcode_str = gimple_code_name[gcode];
+ gcc_assert(gcode_str);
+
+ switch (gimple_assign_rhs_class (stmt))
+ {
+ case GIMPLE_SINGLE_RHS:
+ case GIMPLE_UNARY_RHS:
+ {
+ tree lhs = gimple_assign_lhs(stmt);
+ tree rhs = gimple_assign_rhs1(stmt);
+ bool retval = cast_to_void_in_assign(lhs, rhs, escape_map);
+ if (!retval) break;
+
+ tree tree_type_lhs = TYPE_MAIN_VARIANT(TREE_TYPE(lhs));
+ tree tree_type_rhs = TYPE_MAIN_VARIANT(TREE_TYPE(rhs));
+ const char* const type_name_lhs = get_type_name(tree_type_lhs);
+ const char* const type_name_rhs = get_type_name(tree_type_rhs);
+ log("type casting %s != %s ", type_name_lhs, type_name_rhs);
+ if (dump_file) print_gimple_stmt (dump_file, stmt, 0, TDF_NONE);
+ log("\n");
+ }
+ default:
+ break;
+ }
+}
+
+static void
+cast_to_void_in_stmt (gimple *stmt, type_map &escape_map)
+{
+ gcc_assert (stmt);
+ const enum gimple_code code = gimple_code (stmt);
+ switch (code)
+ {
+ case GIMPLE_ASSIGN:
+ cast_to_void_in_assign(stmt, escape_map);
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+static void
+cast_to_void_in_bb(basic_block bb, type_map &escape_map)
+{
+ gcc_assert(bb);
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+ cast_to_void_in_stmt (stmt, escape_map);
+ }
+}
+
+static void
+cast_to_void_in_function(cgraph_node *cnode, type_map &escape_map)
+{
+ gcc_assert (cnode);
+ print_function (cnode);
+ basic_block bb = NULL;
+ tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION (decl);
+ gcc_assert(func);
+ push_cfun(func);
+ FOR_EACH_BB_FN (bb, func)
+ {
+ gcc_assert(bb);
+ cast_to_void_in_bb(bb, escape_map);
+ }
+ pop_cfun();
+}
+
+static void
+cast_to_void_in_program(type_map &escape_map)
+{
+ cgraph_node *cnode = NULL;
+ FOR_EACH_DEFINED_FUNCTION (cnode)
+ {
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ cast_to_void_in_function(cnode, escape_map);
+ }
+}
+
+/* INFO:
+ * Yes, I know we are returning a std::map.
+ * Bad pattern? Maybe, but this will only be called once
+ * and I rather pass by value because that allows
+ * me to have a pure function and not worry about
+ * garbage collection
+ *
+ * TODO: I'd like to change type_map for a std::map
+ * TODO: I'd like to make this a template that can work
+ * for std::map and std::set
+ */
+void
+calculate_escaping_types(type_map &escape_map)
+{
+ collect_types(escape_map);
+ is_any_variable_escaping(escape_map);
+ is_any_function_escaping(escape_map);
+ cast_to_void_in_program(escape_map);
+ print_types(escape_map);
+}
+
+static unsigned int
+iphw_execute()
+{
+ // We can ignore the return value here...
+ type_map escape_map;
+ calculate_escaping_types(escape_map);
+ return 0;
+}
+
+
+namespace {
+const pass_data pass_data_ipa_type_escape_analysis =
+{
+ SIMPLE_IPA_PASS,
+ "type-escape-analysis",
+ OPTGROUP_NONE,
+ TV_NONE,
+ (PROP_cfg | PROP_ssa),
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+class pass_ipa_type_escape_analysis : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_type_escape_analysis (gcc::context *ctx)
+ : simple_ipa_opt_pass(pass_data_ipa_type_escape_analysis, ctx)
+ {}
+
+ virtual bool gate(function*) { return in_lto_p && flag_ipa_type_escape_analysis; }
+ virtual unsigned execute (function*) { return iphw_execute(); }
+};
+} // anon namespace
+
+simple_ipa_opt_pass*
+make_pass_ipa_type_escape_analysis (gcc::context *ctx)
+{
+ return new pass_ipa_type_escape_analysis (ctx);
+}
diff --git a/gcc/ipa-type-escape-analysis.h b/gcc/ipa-type-escape-analysis.h
new file mode 100644
index 00000000000..7dcda948189
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.h
@@ -0,0 +1,21 @@
+#ifndef GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
+#define GCC_IPA_TYPE_ESCAPE_ANALYSIS_H
+#pragma once
+
+struct escaping_reason_s {
+ unsigned global_is_visible : 1;
+ unsigned parameter_is_visible : 1;
+ unsigned return_is_visible : 1;
+ unsigned type_is_casted : 1;
+};
+typedef struct escaping_reason_s escaping_reason;
+
+struct escaping_info_s { const_tree type; bool is_escaping; escaping_reason reason; };
+typedef struct escaping_info_s escaping_info;
+//TODO: Maybe change this to a std::map?
+//Can we get an idea of what conventions gcc want?
+//Maybe I should ask...
+typedef hash_map<const_tree, escaping_info> type_map;
+void calculate_escaping_types(type_map&);
+
+#endif
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 76aa6fe34b8..6dd64e2e455 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -237,7 +237,7 @@ enum lto_section_type
LTO_section_ipa_hsa,
LTO_section_lto,
LTO_section_ipa_sra,
- LTO_N_SECTION_TYPES /* Must be last. */
+ LTO_N_SECTION_TYPES /* Must be last. */
};
/* Indices to the various function, type and symbol streams. */
diff --git a/gcc/passes.def b/gcc/passes.def
index 853e512e227..e0d2711c432 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -149,6 +149,8 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_ipa_profile);
NEXT_PASS (pass_ipa_icf);
NEXT_PASS (pass_ipa_devirt);
+ NEXT_PASS (pass_ipa_type_escape_analysis);
+ NEXT_PASS (pass_ipa_hello_world);
NEXT_PASS (pass_ipa_escape_analysis);
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_sra);
@@ -172,6 +174,7 @@ along with GCC; see the file COPYING3. If not see
compiled unit. */
INSERT_PASSES_AFTER (all_late_ipa_passes)
NEXT_PASS (pass_materialize_all_clones);
+ NEXT_PASS (pass_ipa_structure_reorg);
NEXT_PASS (pass_ipa_pta);
NEXT_PASS (pass_omp_simd_clone);
TERMINATE_PASS_LIST (all_late_ipa_passes)
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
new file mode 100644
index 00000000000..88f96ea3be4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ printf("%d\n", astruct.a);
+ printf("%d\n", astruct.a);
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 2" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c
new file mode 100644
index 00000000000..6e7b3236294
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ astruct.a++;
+ astruct.a = 3;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 1" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 2" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c
new file mode 100644
index 00000000000..1b6755565ff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s *astruct = NULL;
+
+
+int
+main ()
+{
+ printf("%d\n", astruct->a);
+ printf("%d\n", astruct->a);
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 2" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c
new file mode 100644
index 00000000000..68e2f40a12a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s *astruct;
+
+
+int
+main ()
+{
+ astruct->a++;
+ astruct->a = 3;
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 1" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 2" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c
new file mode 100644
index 00000000000..0dd152a2783
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c
@@ -0,0 +1,19 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ if (astruct.a) {
+ puts("hello world");
+ }
+}
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c
new file mode 100644
index 00000000000..f9c4af5d6cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-00-collect-global-record-0.c
@@ -0,0 +1,13 @@
+/* { dg-do link } */
+/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+int
+main ()
+{
+ astruct.a = 0;
+}
+
+/* { dg-final { scan-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c
new file mode 100644
index 00000000000..e1147844f18
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-01-collect-global-pointers-to-record-0.c
@@ -0,0 +1,16 @@
+/* { dg-do link } */
+/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s *astruct;
+
+int
+main ()
+{
+ astruct = NULL;
+}
+
+/* { dg-final { scan-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,astruct_s*" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c
new file mode 100644
index 00000000000..aed61d4ef69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-02-collect-global-array-to-record-0.c
@@ -0,0 +1,16 @@
+/* { dg-do link } */
+/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct[2];
+
+int
+main ()
+{
+ struct astruct_s another = astruct[0];
+}
+
+/* { dg-final { scan-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,astruct_s[]" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c
new file mode 100644
index 00000000000..e300b0b598a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-03-collect-nested-record-0.c
@@ -0,0 +1,20 @@
+/* { dg-do link } */
+/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct[2];
+struct outer_struct { _Bool d; struct astruct_s a; };
+struct outer_struct bstruct;
+
+int
+main ()
+{
+ bstruct.d = 0;
+ struct astruct_s another = astruct[0];
+}
+
+/* { dg-final { scan-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,outer_struct" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,astruct_s[]" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c
new file mode 100644
index 00000000000..7b40c7701bf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-04-collect-parameters-0.c
@@ -0,0 +1,20 @@
+/* { dg-do link } */
+/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+
+void record_parameter(struct astruct_s a) {}
+void pointer_parameter(struct astruct_s *a) {}
+void array_parameter(struct astruct_s a[]) {}
+
+
+int
+main ()
+{
+}
+
+/* { dg-final { scan-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,astruct_s*" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "collected,astruct_s[]" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c
new file mode 100644
index 00000000000..32a77195322
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-05-global-escapes-0.c
@@ -0,0 +1,23 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+/* { dg-require-effective-target lto } */
+
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+__attribute__((externally_visible)) struct astruct_s astruct; // This should escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "variable bstruct is escaping false" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "variable astruct is escaping true" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c
new file mode 100644
index 00000000000..2e7024ab907
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-06-global-type-escapes-0.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+__attribute__((externally_visible)) struct astruct_s astruct; // This should escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type astruct_s is escaping true" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c
new file mode 100644
index 00000000000..d1842987735
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-08-parameter-escapes-0.c
@@ -0,0 +1,27 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+/* { dg-require-effective-target lto } */
+
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+__attribute__((externally_visible)) void escaping(struct astruct_s cstruct) {}
+void non_escaping(struct bstruct_s dstruct) {}
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "variable bstruct is escaping false" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "parameter type astruct_s is escaping true" "hello-world" } } */
+/* { dg-final { scan-wpa-ipa-dump "parameter type bstruct_s is escaping false" "hello-world" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-09-parameter-type-escapes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-09-parameter-type-escapes-0.c
new file mode 100644
index 00000000000..79809249942
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-09-parameter-type-escapes-0.c
@@ -0,0 +1,24 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+// This will make astruct_s escape
+__attribute__((externally_visible)) void escaping(struct astruct_s cstruct) {}
+void non_escaping(struct bstruct_s dstruct) {}
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c
new file mode 100644
index 00000000000..f2c5f307f01
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-10-return-type-escapes-0.c
@@ -0,0 +1,24 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+// This will make astruct_s escape
+__attribute__((externally_visible)) struct astruct_s escaping() { struct astruct_s a; return a; }
+void non_escaping(struct bstruct_s dstruct) {}
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c
new file mode 100644
index 00000000000..5ef153eb5f9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-11-cast-to-void-ptr-0.c
@@ -0,0 +1,26 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+void casting_to_void (struct astruct_s *s)
+{
+ void *nullify_non_escape = s;
+}
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type astruct_s\\\* is escaping true" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c
new file mode 100644
index 00000000000..1f298b1415b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-12-cast-to-void-ptr-0.c
@@ -0,0 +1,27 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct; // This should not escape
+struct bstruct_s { _Bool a; _Bool b; _Bool c;};
+struct bstruct_s bstruct; // This should not escape
+
+void casting_to_void (struct astruct_s *s)
+{
+ void *nullify_non_escape = s;
+}
+
+int main()
+{
+ astruct.a = 0;
+ bstruct.b = 0;
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type astruct_s\\\* is escaping true" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type astruct_s is escaping true" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "collected,bstruct_s" "type-escape-analysis" } } */
+/* { dg-final { scan-wpa-ipa-dump "type bstruct_s is escaping false" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c
new file mode 100644
index 00000000000..aa3e97b5444
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-13-calling-printf-0.c
@@ -0,0 +1,15 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
+
+#include <stddef.h>
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+ char *filename = "helloworld.txt";
+ FILE* f = fopen(filename);
+ fclose(f);
+}
+
+
+/* { dg-final { scan-wpa-ipa-dump "type FILE is escaping true" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c
new file mode 100644
index 00000000000..22185badeab
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+// Dummy test to find out if
+// our optimization is registered
+
+int
+main ()
+{
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
new file mode 100644
index 00000000000..07d6ea35e0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c
new file mode 100644
index 00000000000..af0c175515a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-10-array-0.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s a;
+ struct astruct_s b[2];
+ a = b[0];
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c
new file mode 100644
index 00000000000..448db9759ef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-11-rewrites-minus-expr-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ _Bool *c_ptr = &(astruct.c);
+ _Bool *a_ptr = &(astruct.a);
+ ptrdiff_t diff = c_ptr - a_ptr;
+ assert (diff == 1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c
new file mode 100644
index 00000000000..dd14c66f600
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-12-delete-last-field-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool b;
+ };
+ struct astruct_s b[2];
+ _Bool *first_of_second = &(b[1].a);
+ _Bool *c_0 = &(b[0].c);
+ _Bool *a_1 = &(b[1].a);
+ _Bool *a_1_from_c_0 = c_0 + 1;
+ _Bool test = a_1_from_c_0 == a_1;
+ char compile_test[test ? 1 : -1];
+ assert (test);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c
new file mode 100644
index 00000000000..df1b546906c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-13-modify-size-four-0.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s astruct;
+ _Bool *a = &(astruct.a);
+ _Bool *c = &(astruct.c);
+ _Bool *d = &(astruct.d);
+ ptrdiff_t diff_1 = c - a;
+ ptrdiff_t diff_2 = d - a;
+ assert (diff_1 == 1);
+ assert (diff_2 == 2);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c
new file mode 100644
index 00000000000..e458b14c820
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-14-rewrite-plus-expr-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ int d = astruct.c + 1;
+ _Bool *a = &(astruct.a);
+ _Bool *c = a + 1;
+ assert (*c == 1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c
new file mode 100644
index 00000000000..2f7ab7d8927
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-15-rewrite-mult-expr-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <stddef.h>
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ int d = astruct.c * 2;
+ _Bool *a = &(astruct.a);
+ _Bool *c = a + 1;
+ assert (*c == 0);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c
new file mode 100644
index 00000000000..3c4b7b08dd1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-16-rewrite-field-reads-ptr-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ astruct.c = 1;
+ struct astruct_s *astruct_p = &astruct;
+ _Bool c = astruct_p->c;
+ _Bool *a = &(astruct.a);
+ _Bool *c_ptr = a + 1;
+ assert (*c_ptr == c);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c
new file mode 100644
index 00000000000..f297eea6aa0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-17-rewrite-field-write-ptr-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ struct astruct_s *astruct_p = &astruct;
+ astruct_p->c = 1;
+ _Bool *a = &(astruct.a);
+ _Bool *c = a + 1;
+ assert (*c == 1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c
new file mode 100644
index 00000000000..bc204f4017f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-18-field-writes-deref-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool e;
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s astruct;
+ _Bool *c_ptr = &astruct.c;
+ c_ptr--;
+ *c_ptr = 1;
+ _Bool *e_ptr = &astruct.e;
+ e_ptr++;
+ return *e_ptr - 1;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c
new file mode 100644
index 00000000000..10f850bb801
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-19-middle-pointer-equal-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s astruct;
+ _Bool *a = &astruct.a;
+ _Bool *d = &astruct.d;
+ _Bool *c_from_a = a + 1;
+ _Bool *c_from_d = d - 1;
+ _Bool test = c_from_a == c_from_d;
+ char compile_test[test ? 1 : -1];
+ assert (test);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
new file mode 100644
index 00000000000..e32e18af2f4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ return 0;
+}
+
+/* "modifying,astruct_s" "typelist" */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c
new file mode 100644
index 00000000000..f93b642586e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-20-array-offset-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s b[2];
+ _Bool *first_of_second = &(b[1].a);
+ _Bool *a_ptr = &(b[0].a);
+ _Bool *c_from_a = ++a_ptr;
+ _Bool *c_from_array = --first_of_second;
+ _Bool test = c_from_a == c_from_array;
+ assert (test);
+ char compile_test[test ? 1 : -1];
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-21-rewrites-clobber-type-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-21-rewrites-clobber-type-0.c
new file mode 100644
index 00000000000..080d8509c26
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-21-rewrites-clobber-type-0.c
@@ -0,0 +1,17 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ return 0;
+}
+
+// CLOBBERS :(
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c
new file mode 100644
index 00000000000..68c75427640
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-22-rewrites-addr-expr-read-0.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ _Bool *a = &astruct.a;
+ _Bool *c = &astruct.c;
+ _Bool *c_1 = a + 1;
+ assert (c_1 == c);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c
new file mode 100644
index 00000000000..c86bce1f885
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-23-array-cast-0.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s a[2];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ };
+ struct astruct_s *a_0 = &(a[0]);
+ struct astruct_s *a_1 = a_0 + 1;
+ struct bstruct_s *b_0 = (struct bstruct_s *) a_0;
+ struct bstruct_s *b_1 = b_0 + 1;
+ assert ((struct bstruct_s *) a_1 == b_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-24-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-24-array-cast-0.c
new file mode 100644
index 00000000000..f42acd18d93
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-24-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+
+ struct astruct_s *a_0 = &(a[0]);
+ struct astruct_s *a_1 = a_0 + 1;
+ struct bstruct_s *b_0 = (struct bstruct_s *) a_0;
+ struct bstruct_s *b_1 = b_0 + 1;
+ assert ((struct bstruct_s *) a_1 == b_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c
new file mode 100644
index 00000000000..ef4c1c10772
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-25-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+
+ struct astruct_s *a_0 = &(a[1]);
+ struct astruct_s *a_1 = a_0 - 1;
+ struct bstruct_s *b_0 = (struct bstruct_s *) a_0;
+ struct bstruct_s *b_1 = b_0 - 1;
+ assert ((struct bstruct_s *) a_1 == b_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c
new file mode 100644
index 00000000000..7ec3c82a916
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-26-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+
+ struct astruct_s *a_0 = &(a[0]);
+ struct astruct_s *a_1 = a_0 + argc;
+ struct bstruct_s *b_0 = (struct bstruct_s *) a_0;
+ struct bstruct_s *b_1 = b_0 + argc;
+ assert ((struct bstruct_s *) a_1 == b_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c
new file mode 100644
index 00000000000..b3c8f739ef3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-27-array-cast-0.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2][2];
+ struct astruct_s b = a[argc][argc];
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-28-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-28-array-cast-0.c
new file mode 100644
index 00000000000..aba8eefe3dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-28-array-cast-0.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[3];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+
+ struct astruct_s *a_0 = &(a[0]);
+ struct astruct_s *a_1 = a_0 + 2;
+ struct bstruct_s *b_0 = (struct bstruct_s *) a_0;
+ struct bstruct_s *b_1 = b_0 + 2;
+ assert ((struct bstruct_s *) a_1 == b_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c
new file mode 100644
index 00000000000..43a74ce963c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-29-heterogeneous-struct.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ int a;
+ _Bool b;
+ int c;
+ };
+ struct astruct_s astruct;
+ int *a = &(astruct.a);
+ int *c = &(astruct.c);
+ ptrdiff_t d = c - a;
+ assert (d == 1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-3-new-offsets-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-3-new-offsets-0.c
new file mode 100644
index 00000000000..07d6ea35e0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-3-new-offsets-0.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c
new file mode 100644
index 00000000000..49436d8bb87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-30-heterogenous-struct-0.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ // unmodified { a = 1, b = 4; c = 5; d = 8; e = 12
+ // modified { a = 1, c = 2; d = 4, e = 8
+ struct astruct_s
+ {
+ _Bool a;
+ int b;
+ _Bool c;
+ int d;
+ _Bool e;
+ };
+ struct astruct_s astruct;
+ _Bool *a = &(astruct.a);
+ _Bool *e = &(astruct.e);
+ ptrdiff_t diff = e - a;
+ assert (diff == 8);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c
new file mode 100644
index 00000000000..4f9853af425
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-31-heterogenous-struct-0.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ // unmodified a = 0, d = 1; e = 2; f = 3; b = 4; c = 8
+ // modified a = 0, d = 1, e = 2, f = 3, c = 4;
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool d;
+ _Bool e;
+ _Bool f;
+ _Bool b;
+ int c;
+ };
+ struct astruct_s astruct;
+ struct astruct_s *p = &astruct;
+ _Bool *a = &(p->a);
+ _Bool *c = (_Bool *) &(p->c);
+ ptrdiff_t d = c - a;
+ assert (d == 4);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-32-pointer-indirection-level-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-32-pointer-indirection-level-0.c
new file mode 100644
index 00000000000..687ef04ac77
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-32-pointer-indirection-level-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ struct astruct_s *p0 = &astruct;
+ struct astruct_s **p1 = &p0;
+ _Bool *a_ptr_0 = (_Bool *) p0;
+ _Bool *c_ptr_0 = a_ptr_0 + 1;
+ _Bool **a_ptr_1 = (_Bool **) p1;
+ _Bool *c_ptr_1 = (_Bool *) ((*a_ptr_1) + 1);
+ assert (c_ptr_0 == c_ptr_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c
new file mode 100644
index 00000000000..ca942339efe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-nested-struct-0.c
@@ -0,0 +1,42 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct outerstruct_s
+ {
+ struct astruct_s a;
+ struct astruct_s b;
+ struct astruct_s c;
+ struct astruct_s d;
+ };
+ struct outerstruct_s outerstruct;
+ _Bool *outer_a = (_Bool *) &outerstruct.a;
+ _Bool *outer_b = (_Bool *) &outerstruct.b;
+ _Bool *outer_c = (_Bool *) &outerstruct.c;
+ _Bool *outer_d = (_Bool *) &outerstruct.d;
+ _Bool *outer_b_1 = outer_a + 3;
+ _Bool *outer_c_1 = outer_a + 6;
+ _Bool *outer_d_1 = outer_a + 9;
+ assert (outer_b == outer_b_1);
+ assert (outer_c == outer_c_1);
+ assert (outer_d == outer_d_1);
+}
+
+/* " offset,astruct_s.reorg,a,0" "typelist" } } */
+/* " offset,astruct_s.reorg,c,1" "typelist" } } */
+/* " offset,astruct_s.reorg,d,2" "typelist" } } */
+/* " offset,outerstruct_s.reorg,a,0" "typelist" } } */
+/* " offset,outerstruct_s.reorg,b,3" "typelist" } } */
+/* " offset,outerstruct_s.reorg,c,6" "typelist" } } */
+/* " offset,outerstruct_s.reorg,d,9" "typelist" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c
new file mode 100644
index 00000000000..0fc5f0f9e46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-33-pointer-indirection-level-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s astruct;
+ struct astruct_s *p0 = &astruct;
+ struct astruct_s **p1 = &p0;
+ _Bool *a_ptr = &(astruct.a);
+ _Bool *c_ptr = a_ptr + 1;
+ _Bool *a_ptr_2 = &((*p1)->a);
+ _Bool *c_ptr_2 = a_ptr_2 + 1;
+ assert (c_ptr == c_ptr_2);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c
new file mode 100644
index 00000000000..5ae01feb7bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-34-array-cast-0.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2][2];
+
+ struct astruct_s b = a[argc][argc];
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-35-array-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-35-array-cast-0.c
new file mode 100644
index 00000000000..ea4d49258a2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-35-array-cast-0.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s a[2][2];
+ struct bstruct_s
+ {
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+ struct bstruct_s *b_ptr = (struct bstruct_s *) &a;
+ // a[0][0] = b_ptr + 0 + 0;
+ // a[0][1] = b_ptr + 0 + sizeof(astruct_s)
+ // a[1][0] = b_ptr + 2*sizeof(astruct_s) + 0;
+ // a[1][1] = b_ptr + 2*sizeof(astruct_s) + sizeof(astruct_s);
+ // as a function of argc
+ // a[argc][argc] = b_ptr + 2*sizeof(astruct_s)* argc + sizeof(astruct_s)*argc
+ // TODO: Can't put size of astruct_s because
+ // we don't change sizeof yet...
+ int size = sizeof (struct bstruct_s);
+ struct bstruct_s *b_ptr_2 = b_ptr + 2 * argc + argc;
+ struct bstruct_s *b = (struct bstruct_s *) &(a[argc][argc]);
+ assert (b_ptr_2 == b);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c
new file mode 100644
index 00000000000..2b2e70a0b16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-36-arguments-0.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+};
+
+// PASS BY VALUE
+_Bool
+foo (struct astruct_s astruct)
+{
+ _Bool *a = &astruct.a;
+ assert (!*a);
+ _Bool *c = a + 1;
+ assert (*c);
+ _Bool *d = a + 2;
+ assert (*d);
+ return *c;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s astruct;
+ astruct.a = 0;
+ astruct.c = argc;
+ astruct.d = 1;
+ foo (astruct);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c
new file mode 100644
index 00000000000..b8a3a01ba0a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-37-arguments-0.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+};
+
+// PASS BY REFERENCE
+_Bool
+foo (struct astruct_s *astruct)
+{
+ _Bool *a = (_Bool *) &(astruct->a);
+ assert (!*a);
+ _Bool *c = a + 1;
+ assert (*c);
+ _Bool *d = a + 2;
+ assert (*d);
+ return *c;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s astruct;
+ astruct.a = 0;
+ astruct.c = argc;
+ astruct.d = 1;
+ foo (&astruct);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c
new file mode 100644
index 00000000000..0df611a7d7b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-38-return-values-0.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stddef.h>
+
+struct astruct_s
+{
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+};
+
+// RETURN BY VALUE
+struct astruct_s
+foo (_Bool c)
+{
+ struct astruct_s astruct;
+ astruct.a = 0;
+ astruct.c = c;
+ astruct.d = 1;
+ return astruct;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s astruct;
+ astruct = foo (argc);
+ _Bool *a = &(astruct.a);
+ assert (!*a);
+ _Bool *c = a + 1;
+ assert (*c == argc);
+ _Bool *d = a + 2;
+ assert (*d);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c
new file mode 100644
index 00000000000..c8f0569e932
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-39-typedef-0.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ typedef struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ } astruct_s;
+ astruct_s astruct;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-4-layout-compile-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-4-layout-compile-0.c
new file mode 100644
index 00000000000..d933f3a5e85
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-4-layout-compile-0.c
@@ -0,0 +1,22 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ int a;
+ int b;
+ int c;
+ };
+ struct astruct_s astruct;
+ int *c = &astruct.c;
+ int *a = &astruct.a;
+ ptrdiff_t d = c - a;
+ char ch[d == 1 ? 1 : -1];
+}
+
+/* "Executing structreorg" "typelist" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c
new file mode 100644
index 00000000000..d1f752ff005
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-40-typedef-0.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ typedef struct astruct_s astruct_s;
+ astruct_s astruct;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c
new file mode 100644
index 00000000000..a0c8d4a1f3e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-41-deref-0.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ struct astruct_s *t, copy;
+ t = &astruct;
+ copy = *t;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c
new file mode 100644
index 00000000000..5cc493d2f3f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-42-mem-ref-0.c
@@ -0,0 +1,29 @@
+/* { dg-do link } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc" } */
+
+#include <stdlib.h>
+
+typedef struct arc arc_t;
+typedef struct arc *arc_p;
+
+struct arc
+{
+ int id;
+ long cost;
+ void *tail, *head;
+ short ident;
+ arc_p nextout, nextin;
+ long flow;
+ long org_cost;
+};
+
+int
+main ()
+{
+ int num_threads = 10;
+ arc_p *deleted_arcs;
+ register arc_t *arcnew = (arc_t*) malloc (num_threads * sizeof (arc_p));
+ deleted_arcs = (arc_p *) malloc (num_threads * num_threads * sizeof (arc_p));
+ deleted_arcs[num_threads - 1][num_threads - 1] = arcnew[0];
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c
new file mode 100644
index 00000000000..a3890b404a7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-43-args-0.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc" } */
+
+#include <stdlib.h>
+
+struct astruct_s
+{
+ _Bool a;
+ _Bool b;
+ _Bool c;
+};
+struct wrapper_s
+{
+ struct astruct_s *a;
+};
+
+void
+foo (struct wrapper_s *wrapper){};
+void
+bar (struct wrapper_s *wrapper)
+{
+ foo (wrapper);
+};
+
+int
+main ()
+{
+ struct wrapper_s a_wrapper;
+ bar (&a_wrapper);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c
new file mode 100644
index 00000000000..749dad5995e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-44-cond-0.c
@@ -0,0 +1,14 @@
+/* { dg-do link } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc" } */
+
+struct a
+{
+ struct arc *b;
+} c (struct a *d)
+{
+ while (d)
+ ;
+}
+void
+main ()
+{}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c
new file mode 100644
index 00000000000..c490c17de6b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-45-phis-0.c
@@ -0,0 +1,14 @@
+/* { dg-do link } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc" } */
+
+struct a
+{
+ struct arc *b;
+} c (struct a *d, struct a *e)
+{
+ while (e)
+ d = d;
+}
+int
+main ()
+{}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c
new file mode 100644
index 00000000000..f0befcd814c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-46-static-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc -o ipa-structreorg-46-static-0.exe " } */
+
+#include <assert.h>
+#include <stddef.h>
+
+struct arc
+{
+ _Bool a;
+ _Bool nextout;
+ _Bool c;
+};
+
+struct arc an_arc;
+
+int
+main ()
+{
+ _Bool *a = &(an_arc.a);
+ _Bool *c = &(an_arc.c);
+ ptrdiff_t diff = c - a;
+ assert (diff == 1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c
new file mode 100644
index 00000000000..28d18a54957
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-47-constructor-0.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc -o ipa-structreorg-46-static-0.exe " } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main ()
+{
+ struct arc
+ {
+ _Bool a;
+ _Bool nextout;
+ _Bool c;
+ };
+ struct arc an_arc;
+ struct another
+ {
+ _Bool a;
+ struct arc d;
+ _Bool c;
+ };
+ struct another an_another = {0, {0, 1}, 1};
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c
new file mode 100644
index 00000000000..2e55ad41d34
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-48-function-ptr-0.c
@@ -0,0 +1,38 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout -fipa-typelist-struct=arc " } */
+
+#include <assert.h>
+#include <stddef.h>
+
+struct arc
+{
+ _Bool a;
+ _Bool nextout;
+ _Bool c;
+};
+
+_Bool
+returnLast (struct arc anArc)
+{
+ return anArc.c;
+}
+
+_Bool
+returnLast2 (struct arc anArc)
+{
+ _Bool *ptr = &(anArc.a);
+ ptr = ptr + 1;
+ return *ptr;
+}
+
+int
+main (int argc, char **argv)
+{
+ _Bool (*func1) (struct arc);
+ func1 = &returnLast;
+ _Bool (*func2) (struct arc);
+ func2 = &returnLast2;
+ struct arc anArc;
+ anArc.c = argc;
+ assert (func1 (anArc) == func2 (anArc));
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c
new file mode 100644
index 00000000000..6f4fb557d16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-49-array-0.c
@@ -0,0 +1,48 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=nextout,nextin -fipa-typelist-struct=astruct_s " } */
+
+#include <assert.h>
+#include <stddef.h>
+
+int
+main (int argc, char **argv)
+{
+ struct astruct_s
+ {
+ int id;
+ long cost;
+ void *tail;
+ void *head;
+ void *nextin;
+ void *nextout;
+ short ident;
+ long flow;
+ long org_cost;
+ };
+ struct cstruct_s
+ {
+ int id;
+ long cost;
+ void *tail;
+ void *head;
+ short ident;
+ long flow;
+ long org_cost;
+ };
+ struct bstruct_s
+ {
+ struct astruct_s *basic_arc;
+ };
+ long num = argc;
+ struct astruct_s array[100];
+ struct astruct_s *old_arcs = array;
+ struct bstruct_s b;
+ struct bstruct_s *c = &b;
+ c->basic_arc = array + num;
+ c->basic_arc->cost = num;
+ struct cstruct_s *other = ((struct cstruct_s *) (array)) + num;
+ size_t off = c->basic_arc - old_arcs;
+ size_t off2 = other - (struct cstruct_s *) old_arcs;
+ assert ((struct cstruct_s *) c->basic_arc == other);
+ assert (c->basic_arc->cost == other->cost);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-field-reads-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-field-reads-0.c
new file mode 100644
index 00000000000..3e37a780774
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-field-reads-0.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ _Bool c = astruct.c;
+ return 0;
+}
+
+/* "rewrite,field_offset,c,1" "typelist" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-rewrite-local-decl-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-rewrite-local-decl-0.c
new file mode 100644
index 00000000000..07d6ea35e0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-5-rewrite-local-decl-0.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c
new file mode 100644
index 00000000000..a504400aaad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-50-field-write-delete-0.c
@@ -0,0 +1,15 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=delete_me -fipa-typelist-struct=astruct_s " } */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+int
+main (int argc, char **argv)
+{
+struct astruct_s { _Bool a; _Bool delete_me; _Bool c;};
+struct astruct_s astruct;
+astruct.delete_me = false;
+return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c
new file mode 100644
index 00000000000..d03f511078a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-51-creduce-0.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+struct {
+} main() {
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c
new file mode 100644
index 00000000000..6a9994f3e46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-52-creduce-1.c
@@ -0,0 +1,11 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+union a {
+ int16_t b
+} c() {
+ union a d;
+ -d.b;
+}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c
new file mode 100644
index 00000000000..df33fb7aeb7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-53-csmith-2.c
@@ -0,0 +1,5 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+struct {
+} a;
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c
new file mode 100644
index 00000000000..f49627eeeba
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-54-csmith-3.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+//TODO: So, our analysis says that we are deleting a field "a".
+//And that the field "a" is contained in struct "b".
+//However, we are doing is_interesting_struct("c") == yes
+//is_interesting_field("a") == yes
+//and so we delete field a from struct c.
+struct {
+ uint64_t a
+} b[];
+struct {
+ unsigned : 5;
+ unsigned a
+} c;
+d() {
+ uint16_t e = b;
+ int8_t f = c.a;
+}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c
new file mode 100644
index 00000000000..e745c6aa8fb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-55-csmith-4.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+union a {
+ int8_t b
+} c() {
+ union a d = {4073709551608};
+}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c
new file mode 100644
index 00000000000..27da3daa29d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-56-csmith-5.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+struct a {
+ int8_t b
+};
+struct c {
+ struct a d
+} e[];
+
+/* Analysis failed because e[2].d was considered not read
+ * we were only looking at e[2].d.b which is considered read.
+ * So we need to recurse
+ */
+f() { g(e[2].d.b, 0); }
+
+void g(int8_t a, int8_t b) { a + b ;}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c
new file mode 100644
index 00000000000..9827d228e31
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-57-csmith-6.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+struct a {};
+b(struct a c) {}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c
new file mode 100644
index 00000000000..3edc8a44499
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-58-csmith-7.c
@@ -0,0 +1,12 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+struct a {
+ int32_t b
+} c;
+d() {
+ for (;; c.b = 0)
+ ;
+}
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c
new file mode 100644
index 00000000000..050e3177fb1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-59-csmith-8.c
@@ -0,0 +1,10 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+struct a {
+ signed b
+};
+struct {
+ struct a b
+} volatile c;
+main() { c.b.b; }
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-6-field-writes-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-6-field-writes-0.c
new file mode 100644
index 00000000000..c7092516692
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-6-field-writes-0.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ };
+ struct astruct_s astruct;
+ astruct.c = 0;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c
new file mode 100644
index 00000000000..b1001a6286c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-60-csmith-9.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-w -flto -flto-partition=none -fipa-dead-field-eliminate" } */
+
+#include <stdint.h>
+
+void foo(uint64_t a, uint64_t b)
+{ a + b; }
+
+struct a {
+ uint64_t b;
+ uint8_t c
+} d() {
+ // I think the problem here is with the const attribute...
+ const struct a e;
+ foo(0, e.b);
+ return e;
+}
+
+
+main() {}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-7-delete-first-field-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-7-delete-first-field-0.c
new file mode 100644
index 00000000000..b0fdc15d63e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-7-delete-first-field-0.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ _Bool b;
+ _Bool a;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s astruct;
+
+ _Bool *a_ptr = &astruct.a;
+ struct astruct_s *astruct_ptr = &astruct;
+ _Bool test = (_Bool *) astruct_ptr == a_ptr;
+ char compile_test[test ? 1 : -1];
+ assert (test);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-8-modify-double-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-8-modify-double-struct-0.c
new file mode 100644
index 00000000000..83c508ee24e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-8-modify-double-struct-0.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+#include <assert.h>
+int
+main ()
+{
+ struct inner_s
+ {
+ _Bool a;
+ _Bool b;
+ _Bool c;
+ _Bool d;
+ };
+ struct astruct_s
+ {
+ struct inner_s a;
+ struct inner_s b;
+ struct inner_s c;
+ struct inner_s d;
+ };
+ struct astruct_s astruct;
+ struct inner_s a = astruct.a;
+ struct inner_s c = astruct.c;
+ struct inner_s d = astruct.d;
+ _Bool *pa = (_Bool *) &(astruct.a);
+ _Bool *pc = (_Bool *) &(astruct.c);
+ _Bool *pd = (_Bool *) &(astruct.d);
+ _Bool *c_1 = pa + 4;
+ _Bool *d_1 = pa + 8;
+ assert (pc == c_1);
+ assert (pd == d_1);
+}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-9-modify-int-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-9-modify-int-struct-0.c
new file mode 100644
index 00000000000..be51f9e06e9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-9-modify-int-struct-0.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+
+int
+main ()
+{
+ struct astruct_s
+ {
+ int a;
+ int b;
+ int c;
+ int d;
+ };
+ struct astruct_s astruct;
+ int a = astruct.a;
+ int c = astruct.c;
+ int d = astruct.d;
+}
diff --git a/gcc/timevar.def b/gcc/timevar.def
index f467d0251f7..28d3f8cc020 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -80,6 +80,7 @@ DEFTIMEVAR (TV_IPA_INLINING , "ipa inlining heuristics")
DEFTIMEVAR (TV_IPA_FNSPLIT , "ipa function splitting")
DEFTIMEVAR (TV_IPA_COMDATS , "ipa comdats")
DEFTIMEVAR (TV_IPA_OPT , "ipa various optimizations")
+DEFTIMEVAR (TV_IPA_STRUCTURE_REORG , "ipa structure reorg")
DEFTIMEVAR (TV_IPA_LTO_DECOMPRESS , "lto stream decompression")
DEFTIMEVAR (TV_IPA_LTO_COMPRESS , "lto stream compression")
DEFTIMEVAR (TV_IPA_LTO_OUTPUT , "lto stream output")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index a35ac21d324..a9a9c96a4dc 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -501,6 +501,8 @@ extern ipa_opt_pass_d *make_pass_ipa_fn_summary (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_inline (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_type_escape_analysis (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_hello_world (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_escape_analysis (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_cp (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_sra (gcc::context *ctxt);
@@ -509,6 +511,8 @@ extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_hsa (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
+extern simple_ipa_opt_pass *
+make_pass_ipa_structure_reorg (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_pta (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_ipa_tm (gcc::context *ctxt);
extern simple_ipa_opt_pass *make_pass_target_clone (gcc::context *ctxt);