summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-10-08 08:59:42 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-10-08 08:59:42 +0200
commit0eb4d9cc6a786c2597cdca84c7057ed0650bfdc1 (patch)
treecb26f0afee739b4065766fbfa681742bce2d7f6a
parente1336703f8220dcffdeddb5e19dd032c766fbb8f (diff)
Updating everything
-rwxr-xr-xbuild.sh19
-rw-r--r--gary/error-summary31
-rw-r--r--gary/how_to_organize_reorg40
-rw-r--r--gcc/Makefile.in29
-rw-r--r--gcc/collect-types.c86
-rw-r--r--gcc/collect-types.h21
-rw-r--r--gcc/common.opt50
-rw-r--r--gcc/doc/invoke.texi25
-rw-r--r--gcc/expr-accessor.c106
-rw-r--r--gcc/expr-accessor.hpp31
-rw-r--r--gcc/expr-collector.c38
-rw-r--r--gcc/expr-collector.hpp15
-rw-r--r--gcc/expr-escaper.c63
-rw-r--r--gcc/expr-escaper.hpp23
-rw-r--r--gcc/expr-rewriter.c432
-rw-r--r--gcc/expr-rewriter.hpp33
-rw-r--r--gcc/expr-walker.c312
-rw-r--r--gcc/expr-walker.hpp47
-rw-r--r--gcc/gimple-accesser.c105
-rw-r--r--gcc/gimple-accesser.hpp25
-rw-r--r--gcc/gimple-caster.c116
-rw-r--r--gcc/gimple-caster.hpp19
-rw-r--r--gcc/gimple-collector.c124
-rw-r--r--gcc/gimple-collector.hpp22
-rw-r--r--gcc/gimple-escaper.c263
-rw-r--r--gcc/gimple-escaper.hpp30
-rw-r--r--gcc/gimple-rewriter.c268
-rw-r--r--gcc/gimple-rewriter.hpp22
-rw-r--r--gcc/gimple-walker.c257
-rw-r--r--gcc/gimple-walker.hpp69
-rw-r--r--gcc/gimple.h28
-rw-r--r--gcc/ipa-prototype.c330
-rw-r--r--gcc/ipa-prototype.h60
-rw-r--r--gcc/ipa-str-reorg-dead-field-eliminate.c2783
-rw-r--r--gcc/ipa-str-reorg-field-reorder.c60
-rw-r--r--gcc/ipa-str-reorg-instance-interleave.c2536
-rw-r--r--gcc/ipa-str-reorg-utils.c300
-rw-r--r--gcc/ipa-str-reorg-utils.h39
-rw-r--r--gcc/ipa-structure-reorg.c2851
-rw-r--r--gcc/ipa-structure-reorg.h293
-rw-r--r--gcc/ipa-type-escape-analysis.c369
-rw-r--r--gcc/passes.def3
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-pass.h3
-rw-r--r--gcc/type-accessor.c34
-rw-r--r--gcc/type-accessor.hpp47
-rw-r--r--gcc/type-canonical-equality.c56
-rw-r--r--gcc/type-canonical-equality.hpp10
-rw-r--r--gcc/type-collector.c271
-rw-r--r--gcc/type-collector.hpp49
-rw-r--r--gcc/type-escaper.c231
-rw-r--r--gcc/type-escaper.hpp42
-rw-r--r--gcc/type-incomplete-equality.c61
-rw-r--r--gcc/type-incomplete-equality.hpp10
-rw-r--r--gcc/type-reconstructor.c412
-rw-r--r--gcc/type-reconstructor.hpp47
-rw-r--r--gcc/type-stringifier.c246
-rw-r--r--gcc/type-stringifier.hpp48
-rw-r--r--gcc/type-structural-equality.c199
-rw-r--r--gcc/type-structural-equality.hpp38
-rw-r--r--gcc/type-structural-main-variant.c49
-rw-r--r--gcc/type-structural-main-variant.hpp10
-rw-r--r--gcc/type-walker.c282
-rw-r--r--gcc/type-walker.hpp50
-rw-r--r--gcc/types-inlines.h104
65 files changed, 14667 insertions, 6 deletions
diff --git a/build.sh b/build.sh
new file mode 100755
index 00000000000..97158b0cf59
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+
+set -e
+set -u
+
+installdir=${1:-"gcc-inst"}
+mkdir -p $HOME/code/gcc-build/
+mkdir -p $HOME/code/${installdir}/
+pushd $HOME/code/gcc-build/
+if find . -mindepth 1 -print -quit 2>/dev/null | grep -q . ; then
+ echo "not empty?"
+else
+ $OLDPWD/configure --disable-bootstrap --disable-libsanitizer --enable-__cxa_atexit --enable-shared --disable-libsanitizer --enable-languages=c,c++,fortran --enable-lto --enable-gold --enable-linker-build-id --with-cpu-emag --prefix="$HOME/code/${installdir}/"
+fi
+
+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 79e854aa938..5fda9aacdcd 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1408,6 +1408,30 @@ OBJS = \
incpath.o \
init-regs.o \
internal-fn.o \
+ ipa-prototype.o \
+ ipa-type-escape-analysis.o \
+ type-walker.o \
+ type-reconstructor.o \
+ expr-walker.o \
+ gimple-walker.o \
+ gimple-accesser.o \
+ expr-accessor.o \
+ type-accessor.o \
+ type-collector.o \
+ expr-collector.o \
+ gimple-collector.o \
+ gimple-caster.o \
+ gimple-rewriter.o \
+ expr-rewriter.o \
+ type-escaper.o \
+ type-structural-equality.o \
+ type-structural-main-variant.o \
+ type-canonical-equality.o \
+ type-incomplete-equality.o \
+ expr-escaper.o \
+ gimple-escaper.o \
+ type-stringifier.o \
+ collect-types.o \
ipa-cp.o \
ipa-sra.o \
ipa-devirt.o \
@@ -1428,6 +1452,11 @@ OBJS = \
ipa-icf-gimple.o \
ipa-reference.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/collect-types.c b/gcc/collect-types.c
new file mode 100644
index 00000000000..f4ad113b56f
--- /dev/null
+++ b/gcc/collect-types.c
@@ -0,0 +1,86 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "types-inlines.h"
+#include "type-stringifier.hpp"
+#include <set>
+
+#include "collect-types.h"
+
+
+void
+points_to_record_sets_s::insert(const_tree type, bool in_points_to_record)
+{
+ gcc_assert(type);
+ this->universe.insert(type);
+ in_points_to_record ? this->points_to_record.insert(type) : this->complement.insert(type);
+ const bool in_points_to_set = this->in_points_to_record(type);
+ const bool in_complement = this->in_complement(type);
+ const bool _xor = in_points_to_set != in_complement;
+ // sanity check...
+ gcc_assert(_xor);
+}
+
+bool
+points_to_record_sets_s::in_universe(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->universe.find(type) != this->universe.end();
+ return seen_before;
+}
+
+bool
+points_to_record_sets_s::in_points_to_record(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->points_to_record.find(type) != this->points_to_record.end();
+ return seen_before;
+}
+
+bool
+points_to_record_sets_s::in_complement(const_tree type) const
+{
+ gcc_assert(type);
+ const bool seen_before = this->complement.find(type) != this->complement.end();
+ return seen_before;
+}
+
+void
+points_to_record_sets_s::print_in_points_to_record() const
+{
+ TypeStringifier stringifier;
+ for (auto i = this->points_to_record.cbegin(), e = this->points_to_record.cend(); i != e; ++i)
+ {
+ const_tree t = *i;
+ gcc_assert(t);
+ std::string name = stringifier.stringify(t);
+ log("collected: %s\n", name.c_str());
+ }
+}
diff --git a/gcc/collect-types.h b/gcc/collect-types.h
new file mode 100644
index 00000000000..a2439557332
--- /dev/null
+++ b/gcc/collect-types.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "tree.h"
+#include <set>
+
+
+typedef std::set<const_tree> typeset;
+struct points_to_record_sets_s {
+ typeset universe;
+ typeset points_to_record;
+ typeset complement;
+ typeset escaping;
+ typeset non_escaping;
+ bool in_universe(const_tree) const;
+ bool in_points_to_record(const_tree) const;
+ bool in_complement(const_tree) const;
+ void insert(const_tree, bool);
+ void print_in_points_to_record() const;
+};
+
+typedef struct points_to_record_sets_s ptrset_t;
diff --git a/gcc/common.opt b/gcc/common.opt
index dd68c61ae1d..32fcce9593a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1869,6 +1869,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.
@@ -3448,4 +3464,38 @@ 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
+
+ftp-types-compared=
+Common Joined Report Var(flag_tp_types_compared) Init(0)
+
+ftp-comparison-functions=
+Common Joined Report Var(flag_tp_comparison_functions) Init(0)
+
+fipa-prototype
+Common Report Var(flag_ipa_prototype) Optimization
+TBD
+
+fipa-type-escape-analysis
+Common Report Var(flag_ipa_type_escape_analysis) Optimization
+This flag is only used for debugging the type escape analysis
+
+fprint-escape-analysis
+Common Report Var(flag_print_escape_analysis) Optimization
+This flag is used to print the escape analysis proper. It does not include type casting.
+
+fprint-cast-analysis
+Common Report Var(flag_print_cast_analysis) Optimization
+This flag is used to print the escape analysis including type casting.
+
+fprint-access-analysis
+Common Report Var(flag_print_access_analysis) Optimization
+This flag is used to print the access analysis (if field is read or written to).
+
; This comment is to ensure we retain the blank line above.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index bca8c856dc8..5bcf90d3140 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -475,6 +475,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
@@ -9834,6 +9836,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/expr-accessor.c b/gcc/expr-accessor.c
new file mode 100644
index 00000000000..6169f6d6b52
--- /dev/null
+++ b/gcc/expr-accessor.c
@@ -0,0 +1,106 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-stringifier.hpp"
+#include "expr-accessor.hpp"
+#include "expr-walker.hpp"
+#include "type-accessor.hpp"
+
+void
+ExprAccessor::add_all_fields_in_struct(const_tree t)
+{
+ // Inefficient
+ TypeAccessor typeAccessor(record_field_map);
+ typeAccessor.walk(t);
+}
+
+void
+ExprAccessor::_walk_pre(const_tree e)
+{
+ const_tree t = TREE_TYPE(e);
+ add_all_fields_in_struct(t);
+}
+
+void
+ExprAccessor::update(const_tree e, unsigned access)
+{
+ _access = access;
+ walk(e);
+}
+
+void
+ExprAccessor::_walk_COMPONENT_REF_pre(const_tree e)
+{
+ assert_is_type(e, COMPONENT_REF);
+ const_tree op0 = TREE_OPERAND(e, 0);
+ gcc_assert(op0);
+ const_tree op0_t = TREE_TYPE(op0);
+ gcc_assert(op0_t);
+ // op0_t can either be a RECORD_TYPE or a UNION_TYPE
+ const enum tree_code code = TREE_CODE(op0_t);
+ const bool is_record = RECORD_TYPE == code;
+ const bool is_union = UNION_TYPE == code;
+ const bool valid = is_record != is_union;
+ gcc_assert(valid);
+
+ const_tree op1 = TREE_OPERAND(e, 1);
+ assert_is_type(op1, FIELD_DECL);
+ const bool record_already_in_map = record_field_map.find(op0_t) != record_field_map.end();
+ field_access_map_t field_map;
+ field_map = record_already_in_map ? record_field_map[op0_t] : field_map;
+ const bool field_already_in_map = field_map.find(op1) != field_map.end();
+ unsigned prev_access = field_already_in_map ? field_map[op1] : Empty;
+
+ prev_access |= _access;
+ field_map[op1] = prev_access;
+ add_all_fields_in_struct(op0_t);
+ record_field_map[op0_t] = field_map;
+}
+
+void
+ExprAccessor::print_accesses()
+{
+ for (auto i = record_field_map.cbegin(), e = record_field_map.cend(); i != e; ++i)
+ {
+ const_tree record = i->first;
+ field_access_map_t field_map = i->second;
+ for (auto j = field_map.cbegin(), f = field_map.cend(); j != f; ++j)
+ {
+ const_tree field = j->first;
+ const std::string name_r = TypeStringifier::get_type_identifier(record);
+ const std::string name_f = TypeStringifier::get_field_identifier(field);
+ unsigned access = j->second;
+ log("%s.%s = 0x%04x\n", name_r.c_str(), name_f.c_str(), access);
+ }
+ }
+}
diff --git a/gcc/expr-accessor.hpp b/gcc/expr-accessor.hpp
new file mode 100644
index 00000000000..bdc43e46aa7
--- /dev/null
+++ b/gcc/expr-accessor.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "ipa-prototype.h"
+#include "expr-walker.hpp"
+#include "type-escaper.hpp"
+#include "collect-types.h"
+#include "type-accessor.hpp"
+#include <tuple>
+#include <map>
+
+constexpr unsigned Empty = 0x0u;
+constexpr unsigned Read = 0x01u;
+constexpr unsigned Write = 0x02u;
+
+typedef std::map<const_tree, unsigned> field_access_map_t;
+typedef std::map<const_tree, field_access_map_t> record_field_map_t;
+
+class ExprAccessor : public ExprWalker
+{
+public:
+ ExprAccessor() {};
+ void update(const_tree e, unsigned a);
+ void print_accesses();
+ void add_all_fields_in_struct(const_tree t);
+ record_field_map_t get_map() { return record_field_map; };
+private:
+ unsigned _access;
+ record_field_map_t record_field_map;
+ virtual void _walk_COMPONENT_REF_pre(const_tree e);
+ virtual void _walk_pre(const_tree t);
+};
diff --git a/gcc/expr-collector.c b/gcc/expr-collector.c
new file mode 100644
index 00000000000..1271c63cfdf
--- /dev/null
+++ b/gcc/expr-collector.c
@@ -0,0 +1,38 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "expr-collector.hpp"
+
+inline void
+ExprCollector::_walk_pre(const_tree e)
+{
+ const_tree t = TREE_TYPE(e);
+ gcc_assert(t);
+ typeCollector.collect(t);
+}
diff --git a/gcc/expr-collector.hpp b/gcc/expr-collector.hpp
new file mode 100644
index 00000000000..7b3ca3ccd6a
--- /dev/null
+++ b/gcc/expr-collector.hpp
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "expr-walker.hpp"
+#include "type-collector.hpp"
+
+class ExprCollector : public ExprWalker {
+private:
+ TypeCollector typeCollector;
+public:
+ ExprCollector() {};
+ ptrset_t get_pointer_set() { return typeCollector.get_pointer_set(); }
+private:
+ virtual void _walk_pre(const_tree e) final;
+};
+
diff --git a/gcc/expr-escaper.c b/gcc/expr-escaper.c
new file mode 100644
index 00000000000..a7750feb9e7
--- /dev/null
+++ b/gcc/expr-escaper.c
@@ -0,0 +1,63 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-escaper.hpp"
+#include "expr-escaper.hpp"
+
+
+void
+ExprEscaper::update(const_tree t, Reason r)
+{
+ gcc_assert(t);
+ _r = r;
+ walk(t);
+}
+
+void
+ExprEscaper::_walk_pre(const_tree e)
+{
+ const_tree t = TREE_TYPE(e);
+ gcc_assert(t);
+ typeEscaper.update(t, _r);
+}
+
+void
+ExprEscaper::_walk_CONSTRUCTOR_pre(const_tree e)
+{
+ if (TREE_CLOBBER_P(e)) return;
+
+ _r.global_is_visible = true; // just for now...
+ const_tree t = TREE_TYPE(e);
+ typeEscaper.update(t, _r);
+}
+
diff --git a/gcc/expr-escaper.hpp b/gcc/expr-escaper.hpp
new file mode 100644
index 00000000000..c58e1830133
--- /dev/null
+++ b/gcc/expr-escaper.hpp
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "ipa-prototype.h"
+#include "expr-walker.hpp"
+#include "type-escaper.hpp"
+#include "collect-types.h"
+
+class ExprEscaper : public ExprWalker
+{
+public:
+ TypeEscaper typeEscaper;
+ ExprEscaper(ptrset_t &types) : typeEscaper(types) {};
+ ptrset_t get_sets() { return typeEscaper.get_sets(); };
+ void update(const_tree t, Reason r);
+ void update_single_level(const_tree t, Reason r) { typeEscaper.update_single_level(TREE_TYPE(t), r); };
+ void print_reasons() { typeEscaper.print_reasons(); };
+private:
+ Reason _r;
+ virtual void _walk_pre(const_tree e);
+ virtual void _walk_CONSTRUCTOR_pre(const_tree e);
+};
+
+
diff --git a/gcc/expr-rewriter.c b/gcc/expr-rewriter.c
new file mode 100644
index 00000000000..66295d32c74
--- /dev/null
+++ b/gcc/expr-rewriter.c
@@ -0,0 +1,432 @@
+#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 "expr-rewriter.hpp"
+#include "type-stringifier.hpp"
+#include <string>
+#include <map>
+
+void
+ExprTypeRewriter::_walk_PARM_DECL_post(const_tree t)
+{
+ tree temp = (tree)(t);
+ tree ttemp = TREE_TYPE(temp);
+ const bool is_interesting = is_interesting_type(ttemp);
+ if (!is_interesting) return;
+ relayout_decl(temp);
+}
+
+void
+ExprTypeRewriter::_walk_FUNCTION_DECL_post(const_tree t)
+{
+ tree fn_type = TREE_TYPE(t);
+ gcc_assert(t);
+ tree ret_type = TREE_TYPE(fn_type);
+ if (!ret_type) return;
+
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(ret_type);
+ // WARNING: You cannot use is interesting here because you haven't
+ // changed the return type
+ // This is because the return type is not an expression.
+ // Therefore it is awkward to do this in the expr-walker...
+ // const bool is_interesting = is_interesting_type(ret_type);
+ const bool is_interesting = _map.find(ret_type) != _map.end();
+ if (!is_interesting) return;
+
+ tree r_t = _map[ret_type];
+ TREE_TYPE(fn_type) = r_t;
+}
+
+void
+ExprTypeRewriter::_walk_MEM_REF_post(const_tree e)
+{
+ // The second operand is a pointer constant.
+ // Its type specifying the type used for type based alias analysis
+ tree op1 = TREE_OPERAND(e, 1);
+ gcc_assert(TREE_CODE(op1) == INTEGER_CST);
+
+ tree t = TREE_TYPE(op1);
+ const bool already_rewritten = is_interesting_type(t);
+
+ // This is where we do the transformation
+ if (!already_rewritten) return;
+
+ const_tree old_type = _imap[t];
+ assert_is_type(old_type, POINTER_TYPE);
+ const_tree old_base_type = TREE_TYPE(old_type);
+ tree old_type_size_tree = TYPE_SIZE_UNIT(old_base_type);
+ int old_type_size_int = tree_to_shwi(old_type_size_tree);
+
+ tree reorg_type = t;
+ assert_is_type(reorg_type, POINTER_TYPE);
+ tree reorg_base_type = TREE_TYPE(reorg_type);
+ tree reorg_type_size_tree = TYPE_SIZE_UNIT(reorg_base_type);
+ int reorg_type_size_int = tree_to_shwi(reorg_type_size_tree);
+
+ // Let's find out what is the previous offset
+ int old_offset = tree_to_uhwi(op1);
+ int remainder = old_offset % old_type_size_int;
+
+ int new_offset = old_offset / old_type_size_int * reorg_type_size_int + remainder;
+
+ tree new_offset_tree = build_int_cst(TREE_TYPE(op1), new_offset);
+ TREE_OPERAND(e, 1) = new_offset_tree;
+}
+
+void
+ExprTypeRewriter::_walk_SSA_NAME_post(const_tree t)
+{
+ // Here, we need to find out
+ log("we are in expr-rewriter SSA_NAME_post\n");
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(TREE_TYPE(t));
+ log("%s\n", name.c_str());
+}
+
+//TODO:
+//Change name of this method...
+bool
+ExprTypeRewriter::is_interesting_type(tree t)
+{
+ const bool in_imap = _imap.find(t) != _imap.end();
+ bool interesting = in_imap;
+ if (!interesting) return false;
+
+ tree possibly_copy = (tree)_imap[t];
+ const bool is_copy = possibly_copy == t;
+ interesting = !is_copy;
+ if (!interesting) return false;
+
+ // Let's just do a quick sanity check
+ tree interesting_type = t;
+ const bool has_valid_suffix = strstr(TypeStringifier::get_type_identifier(interesting_type).c_str(), ".reorg");
+ gcc_assert(has_valid_suffix);
+ return true;
+}
+
+void
+ExprTypeRewriter::handle_pointer_arithmetic_diff(gimple *s, tree op_0, tree op_1)
+{
+
+ // 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
+ tree lhs = gimple_assign_lhs(s);
+
+ tree reorg_type = TREE_TYPE(op_0);
+ const enum tree_code code = TREE_CODE(reorg_type);
+ const bool is_pointer = POINTER_TYPE == code;
+ const bool is_array = ARRAY_TYPE == code;
+ const bool is_valid_input = is_pointer != is_array;
+ gcc_assert(is_valid_input);
+
+ tree inner_reorg_type = TREE_TYPE(reorg_type);
+ gcc_assert(inner_reorg_type);
+ tree reorg_type_size_tree = TYPE_SIZE_UNIT(inner_reorg_type);
+ int reorg_type_size_int = tree_to_shwi(reorg_type_size_tree);
+
+ tree old_type = (tree)_imap[reorg_type];
+ tree inner_old_type = TREE_TYPE(old_type);
+ gcc_assert(old_type);
+ tree old_type_size_tree = TYPE_SIZE_UNIT(inner_old_type);
+ int old_type_size_int = tree_to_shwi(old_type_size_tree);
+
+
+ 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;
+
+ enum tree_code code = gimple_expr_code (stmt);
+ bool is_exact_div = code == EXACT_DIV_EXPR;
+ if (!is_exact_div)
+ continue;
+
+ 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;
+
+ int divisor_int = tree_to_shwi (divisor);
+ bool is_same_size = divisor_int == old_type_size_int;
+ if (!is_same_size)
+ continue;
+
+ tree new_integer_cst_tree = build_int_cst(TREE_TYPE(divisor), reorg_type_size_int);
+ gimple_set_op (stmt, 2, new_integer_cst_tree);
+ }
+}
+
+void
+ExprTypeRewriter::handle_pointer_arithmetic_nonconstant(gimple *s, tree op_0, tree op_1, bool is_pointer_plus)
+{
+ if (!is_pointer_plus)
+ {
+ handle_pointer_arithmetic_diff(s, op_0, op_1);
+ return;
+ }
+ // _1 = _0 * 72
+ // ... SNIP ...
+ // _2 = _1 + CONSTANT;
+ // ... SNIP ...
+ // _3 = &array + _2; < -- this is where we are
+ //enum tree_code code = TREE_CODE(op_1);
+ //assert_is_type(op_1, SSA_NAME);
+ tree new_type = TREE_TYPE(gimple_assign_lhs(s));
+
+
+ gimple *def_for_variable = SSA_NAME_DEF_STMT(op_1);
+ // It is 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);
+ // Here operands is kind of a minomer.
+ // operand 0 is the lhs
+ // operand 1 is the rhs
+ // I.e. lhs = (unary_operator) rhs;
+ bool get_another_definition = num_operands == 2;
+ tree possibly_not_needed = get_another_definition ? gimple_op (def_for_variable, 1) : NULL;
+ def_for_variable = get_another_definition ? SSA_NAME_DEF_STMT(possibly_not_needed) : def_for_variable;
+
+ // Example:
+ // _2 = _1 * 72; <-- Now we are here...
+ // ... SNIP ...
+ // _3 = -_2;
+ // ... SNIP ...
+ // _4 = &array + _3;
+
+ enum gimple_code gcode = gimple_code(def_for_variable);
+ switch (gcode)
+ {
+ //TODO: FIXME:
+ //This is unsafe, waiting for the sizeof solution
+ case GIMPLE_COND:
+ case GIMPLE_CALL:
+ case GIMPLE_ASSIGN:
+ break;
+ default:
+ return;
+ break;
+ }
+ enum tree_code code = gimple_expr_code (def_for_variable);
+ const bool is_plus_expr = PLUS_EXPR == code;
+
+ // op_0 is the variable
+ // That means that the reorg_type is
+ // The truth is that op_0 might not have the correct type
+ tree reorg_type_tree = new_type;
+ tree reorg_inner_type = TREE_TYPE(reorg_type_tree);
+ tree reorg_type_size_tree = TYPE_SIZE_UNIT(reorg_inner_type);
+ int reorg_type_size_int = tree_to_shwi(reorg_type_size_tree);
+ // That means that the old type is
+ tree old_type_tree = (tree)_imap[reorg_type_tree];
+ tree old_inner_type = TREE_TYPE(old_type_tree);
+ tree old_type_size_tree = TYPE_SIZE_UNIT(old_inner_type);
+ int old_type_size_int = tree_to_shwi(old_type_size_tree);
+
+ if (is_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;
+ tree constant_plus = gimple_op (def_for_variable, 2);
+ assert_is_type(constant_plus, INTEGER_CST);
+
+ int old_integer_cst_int = tree_to_uhwi(constant_plus);
+ int modulo = old_integer_cst_int % old_type_size_int;
+ int new_integer_cst_int = old_integer_cst_int / old_type_size_int * reorg_type_size_int + modulo;
+
+ tree new_integer_cst_tree = build_int_cst(TREE_TYPE(constant_plus), new_integer_cst_int);
+ gimple_set_op(def_for_variable, 2, new_integer_cst_tree);
+
+ tree variable = gimple_op (def_for_variable, 1);
+ def_for_variable = SSA_NAME_DEF_STMT(variable);
+ num_operands = gimple_num_ops (def_for_variable);
+ get_another_definition = num_operands == 2;
+ def_for_variable = get_another_definition ? SSA_NAME_DEF_STMT(gimple_op(def_for_variable, 1)) : def_for_variable;
+ code = gimple_expr_code(def_for_variable);
+
+
+ }
+
+ if (code == MULT_EXPR) {
+
+ tree op_0_earlier = gimple_assign_rhs1(def_for_variable);
+ tree op_1_earlier = gimple_assign_rhs2(def_for_variable);
+
+ // We should be able to just call the constant implementation
+ //handle_pointer_arithmetic_constants(def_for_variable, op_0, op_1);
+ //However...
+ //these variables no longer hold the type needed for them to change correctly
+ //so, let's do it from here...
+
+ assert_is_type(op_1_earlier, INTEGER_CST);
+
+
+ tree old_integer_cst_tree = op_1_earlier;
+ int old_integer_cst_int = tree_to_uhwi(old_integer_cst_tree);
+
+ int offset = old_integer_cst_int % old_type_size_int ;
+ int new_integer_cst_int = old_integer_cst_int / old_type_size_int * reorg_type_size_int + offset;
+ log("%d = %d / %d * %d + %d\n", new_integer_cst_int, old_integer_cst_int, old_type_size_int, reorg_type_size_int, offset);
+
+ tree new_integer_cst_tree = build_int_cst(TREE_TYPE(old_integer_cst_tree), new_integer_cst_int);
+ gimple_set_op(def_for_variable, 2, new_integer_cst_tree);
+ }
+}
+
+void
+ExprTypeRewriter::handle_pointer_arithmetic_constants(gimple *s, tree p, tree i, bool is_pointer_plus)
+{
+ // So, because we have already changed the type
+ // tree p will either be the original type
+ // if we do not need to modify this expression
+ // How do we know if we have an original type?
+ // It is when we don't have a type in our map
+ tree possibly_reorged_type = TREE_TYPE(p);
+ bool is_interesting_case = is_interesting_type(possibly_reorged_type);
+ if (!is_interesting_case) return;
+
+ tree reorg_type = possibly_reorged_type; // this is the type of the variable
+ const_tree original_type = _imap[reorg_type];
+ // If we are here, that means that our type has the ".reorg" suffix
+ const bool has_suffix = strstr(TypeStringifier::get_type_identifier(reorg_type).c_str(), ".reorg");
+ bool is_valid_input = has_suffix;
+ gcc_assert(is_valid_input);
+
+ // We need to know what size is the previous original type
+ tree inner_reorg_type = TREE_TYPE(reorg_type);
+ tree inner_orig_type = TREE_TYPE(original_type);
+ tree old_size_tree = TYPE_SIZE_UNIT(inner_orig_type);
+ int old_size_int = tree_to_shwi(old_size_tree);
+ tree new_size_tree = TYPE_SIZE_UNIT(inner_reorg_type);
+ int new_size_int = tree_to_shwi(new_size_tree);
+ tree old_integer_cst_tree = i;
+ int old_integer_cst_int = tree_to_uhwi(old_integer_cst_tree);
+
+ int offset = old_integer_cst_int % old_size_int;
+ const bool is_modulo = offset == 0;
+ is_valid_input = is_modulo;
+ gcc_assert(is_valid_input);
+
+ int new_integer_cst_int = old_integer_cst_int / old_size_int * new_size_int + offset;
+ log("%d = %d / %d * %d\n", new_integer_cst_int, old_integer_cst_int, old_size_int, new_size_int);
+
+ tree new_integer_cst_tree = build_int_cst(TREE_TYPE(old_integer_cst_tree), new_integer_cst_int);
+ gimple_set_op(s, 2, new_integer_cst_tree);
+
+
+}
+
+void
+ExprTypeRewriter::_walk_post(const_tree e)
+{
+ gcc_assert(e);
+ tree t = TREE_TYPE(e);
+ const bool in_map = _map.find(t) != _map.end();
+ if (!in_map) return;
+
+ const enum tree_code code = TREE_CODE(e);
+ tree r_t = _map[t];
+ TREE_TYPE((tree)e) = r_t;
+
+ return;
+ if (code != MEM_REF) return;
+
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(r_t);
+ tree m = TYPE_MAIN_VARIANT(r_t);
+ std::string name_m = stringifier.stringify(m);
+ const bool main_variant = TYPE_MAIN_VARIANT(r_t) == r_t;
+ log("main: %s\n", name_m.c_str());
+ log("we are in memref: %s is_main_variant %s\n", name.c_str(), main_variant ? "t" : "f");
+ tree type_size = TYPE_SIZE(r_t);
+ log("type size 1 %s?", type_size ? "t" : "f");
+ if (!type_size) TYPE_SIZE(r_t) = TYPE_SIZE(m);
+ log("type size 2 %s?", TYPE_SIZE(r_t) ? "t" : "f");
+ if (!TYPE_SIZE(r_t)) layout_type(r_t);
+ log("type size 3 %s?", TYPE_SIZE(r_t) ? "t" : "f");
+ // still no type_size
+ gcc_assert(TYPE_SIZE(r_t));
+ const enum tree_code cc = TREE_CODE(TYPE_SIZE(r_t));
+ log("%s\n", get_tree_code_name(cc));
+
+ //tree type_main_variant = TYPE_MAIN_VARIANT(TREE_TYPE(e));
+ //const bool do_we_have_mv_in_map = _map.find(type_main_variant) != _map.end();
+
+ // TODO: Fix this hack
+ // We need to make sure that the type main variant is already good here...
+ //TYPE_MAIN_VARIANT(TREE_TYPE(e)) = do_we_have_mv_in_map ? _map[type_main_variant] : TYPE_MAIN_VARIANT(TREE_TYPE(e));
+
+}
+
+void
+ExprTypeRewriter::_walk_COMPONENT_REF_post(const_tree e)
+{
+
+ const_tree r = TREE_OPERAND(e, 0);
+ tree record_type = TREE_TYPE(r);
+ const bool in_map1 = _map.find(record_type) != _map.end();
+
+ const_tree f = TREE_OPERAND(e, 1);
+ // So, what we need is a map between this field and the new field
+ const bool in_map = _map2.find(f) != _map2.end();
+ if (!in_map) return;
+
+ auto p = _map2[f];
+ tree n_f = p.first;
+ bool is_deleted = p.second;
+
+ unsigned f_byte_offset = tree_to_uhwi(DECL_FIELD_OFFSET(f));
+ unsigned f_bit_offset = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(f));
+ unsigned f_offset = 8 * f_byte_offset + f_bit_offset;
+
+ unsigned nf_byte_offset = tree_to_uhwi(DECL_FIELD_OFFSET(n_f));
+ unsigned nf_bit_offset = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(n_f));
+ unsigned nf_offset = 8 * nf_byte_offset + nf_bit_offset;
+ TREE_OPERAND(e, 1) = n_f;
+
+ if (!is_deleted) return;
+
+ _delete = true;
+
+}
+
+
diff --git a/gcc/expr-rewriter.hpp b/gcc/expr-rewriter.hpp
new file mode 100644
index 00000000000..23c0005bcd5
--- /dev/null
+++ b/gcc/expr-rewriter.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "expr-walker.hpp"
+#include "type-reconstructor.hpp"
+
+class ExprTypeRewriter : public ExprWalker
+{
+public:
+ ExprTypeRewriter(TypeReconstructor::reorg_record_map_t map, TypeReconstructor::reorg_field_map_t map2) : _delete(false), _map(map), _map2(map2) {
+ for (auto i = map.cbegin(), e = map.cend(); i != e; ++i)
+ {
+ const_tree original = i->first;
+ tree modified = i->second;
+ _imap[modified] = original;
+ }
+ };
+ void handle_pointer_arithmetic_constants(gimple *s, tree p, tree i, bool);
+ void handle_pointer_arithmetic_diff(gimple *s, tree p, tree i);
+ void handle_pointer_arithmetic_nonconstant(gimple *s, tree p, tree i, bool);
+ bool is_interesting_type(tree);
+ bool delete_statement();
+ bool _delete;
+private:
+ TypeReconstructor::reorg_record_map_t _map;
+ TypeReconstructor::reorg_field_map_t _map2;
+ std::map<tree, const_tree> _imap;
+ void _walk_post(const_tree e);
+ void _walk_MEM_REF_post(const_tree e);
+ void _walk_COMPONENT_REF_post(const_tree e);
+ void _walk_PARM_DECL_post(const_tree e);
+ void _walk_SSA_NAME_post(const_tree e);
+ void _walk_FUNCTION_DECL_post(const_tree e);
+};
diff --git a/gcc/expr-walker.c b/gcc/expr-walker.c
new file mode 100644
index 00000000000..f5f795dfa97
--- /dev/null
+++ b/gcc/expr-walker.c
@@ -0,0 +1,312 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "expr-walker.hpp"
+#include "types-inlines.h"
+
+void
+ExprWalker::walk(const_tree e)
+{
+ _walk_pre(e);
+ _walk(e);
+ _walk_post(e);
+}
+
+void
+ExprWalker::_walk(const_tree e)
+{
+ gcc_assert(e);
+ const enum tree_code code = TREE_CODE(e);
+ switch (code)
+ {
+ case INTEGER_CST:
+ walk_INTEGER_CST(e);
+ break;
+ case REAL_CST:
+ walk_REAL_CST(e);
+ break;
+ case STRING_CST:
+ walk_STRING_CST(e);
+ break;
+ case BIT_FIELD_REF:
+ walk_BIT_FIELD_REF(e);
+ break;
+ case ARRAY_REF:
+ walk_ARRAY_REF(e);
+ break;
+ case MEM_REF:
+ walk_MEM_REF(e);
+ break;
+ case COMPONENT_REF:
+ walk_COMPONENT_REF(e);
+ break;
+ case SSA_NAME:
+ walk_SSA_NAME(e);
+ break;
+ case ADDR_EXPR:
+ walk_ADDR_EXPR(e);
+ break;
+ case VIEW_CONVERT_EXPR:
+ walk_VIEW_CONVERT_EXPR(e);
+ break;
+ case IMAGPART_EXPR:
+ walk_IMAGPART_EXPR(e);
+ break;
+ case VAR_DECL:
+ walk_VAR_DECL(e);
+ break;
+ case FIELD_DECL:
+ walk_FIELD_DECL(e);
+ break;
+ case RESULT_DECL:
+ walk_RESULT_DECL(e);
+ break;
+ case PARM_DECL:
+ walk_PARM_DECL(e);
+ break;
+ case FUNCTION_DECL:
+ walk_FUNCTION_DECL(e);
+ break;
+ case CONSTRUCTOR:
+ walk_CONSTRUCTOR(e);
+ break;
+ case LE_EXPR:
+ walk_LE_EXPR(e);
+ break;
+ case EQ_EXPR:
+ walk_EQ_EXPR(e);
+ break;
+ case GT_EXPR:
+ walk_GT_EXPR(e);
+ break;
+ default:
+ {
+ log("missing %s\n", get_tree_code_name(code));
+ gcc_unreachable();
+ }
+ break;
+ }
+}
+
+#define ExprWalkerFuncDef(code) \
+void \
+ExprWalker::walk_ ## code (const_tree e) \
+{ \
+ assert_is_type(e, code); \
+ _walk_pre(e); \
+ _walk_ ## code ## _pre (e); \
+ _walk_ ## code (e); \
+ _walk_ ## code ## _post (e); \
+ _walk_post(e); \
+}
+
+ExprWalkerFuncDef(CONSTRUCTOR)
+ExprWalkerFuncDef(INTEGER_CST)
+ExprWalkerFuncDef(REAL_CST)
+ExprWalkerFuncDef(STRING_CST)
+ExprWalkerFuncDef(BIT_FIELD_REF)
+ExprWalkerFuncDef(ARRAY_REF)
+ExprWalkerFuncDef(MEM_REF)
+ExprWalkerFuncDef(COMPONENT_REF)
+ExprWalkerFuncDef(SSA_NAME)
+ExprWalkerFuncDef(ADDR_EXPR)
+ExprWalkerFuncDef(VIEW_CONVERT_EXPR)
+ExprWalkerFuncDef(IMAGPART_EXPR)
+ExprWalkerFuncDef(FIELD_DECL)
+ExprWalkerFuncDef(VAR_DECL)
+ExprWalkerFuncDef(RESULT_DECL)
+ExprWalkerFuncDef(PARM_DECL)
+ExprWalkerFuncDef(FUNCTION_DECL)
+ExprWalkerFuncDef(LE_EXPR)
+ExprWalkerFuncDef(EQ_EXPR)
+ExprWalkerFuncDef(GT_EXPR)
+
+void
+ExprWalker::_walk_leaf(const_tree e, const enum tree_code c)
+{
+ assert_is_type(e, c);
+}
+
+void
+ExprWalker::_walk_op_n(const_tree e, unsigned n)
+{
+ gcc_assert(e);
+ const_tree op_n = TREE_OPERAND(e, n);
+ gcc_assert(op_n);
+ walk(op_n);
+}
+
+void
+ExprWalker::_walk_op_0(const_tree e, const enum tree_code c)
+{
+ assert_is_type(e, c);
+ _walk_op_n(e, 0);
+}
+
+void
+ExprWalker::_walk_op_1(const_tree e, const enum tree_code c)
+{
+ assert_is_type(e, c);
+ _walk_op_n(e, 0);
+ _walk_op_n(e, 1);
+}
+
+void
+ExprWalker::_walk_CONSTRUCTOR(const_tree e)
+{
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+void
+ExprWalker::_walk_LE_EXPR(const_tree e)
+{
+ _walk_op_1(e, LE_EXPR);
+}
+
+void
+ExprWalker::_walk_EQ_EXPR(const_tree e)
+{
+ _walk_op_1(e, EQ_EXPR);
+}
+
+void
+ExprWalker::_walk_GT_EXPR(const_tree e)
+{
+ _walk_op_1(e, GT_EXPR);
+}
+
+
+void
+ExprWalker::_walk_INTEGER_CST(const_tree e)
+{
+ _walk_leaf(e, INTEGER_CST);
+}
+
+void
+ExprWalker::_walk_REAL_CST(const_tree e)
+{
+ _walk_leaf(e, REAL_CST);
+}
+
+void
+ExprWalker::_walk_STRING_CST(const_tree e)
+{
+ _walk_leaf(e, STRING_CST);
+}
+
+void
+ExprWalker::_walk_BIT_FIELD_REF(const_tree e)
+{
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+void
+ExprWalker::_walk_ARRAY_REF(const_tree e)
+{
+ _walk_op_1(e, ARRAY_REF);
+}
+
+void
+ExprWalker::_walk_MEM_REF(const_tree e)
+{
+ _walk_op_1(e, MEM_REF);
+}
+
+void
+ExprWalker::_walk_COMPONENT_REF(const_tree e)
+{
+ _walk_op_1(e, COMPONENT_REF);
+}
+
+void
+ExprWalker::_walk_SSA_NAME(const_tree e)
+{
+ _walk_leaf(e, SSA_NAME);
+}
+
+void
+ExprWalker::_walk_ADDR_EXPR(const_tree e)
+{
+ _walk_op_0(e, ADDR_EXPR);
+}
+
+void
+ExprWalker::_walk_VIEW_CONVERT_EXPR(const_tree e)
+{
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+void
+ExprWalker::_walk_IMAGPART_EXPR(const_tree e)
+{
+#ifdef FUZZ_MODE
+ gcc_unreachable();
+#endif
+}
+
+void
+ExprWalker::_walk_FIELD_DECL(const_tree e)
+{
+ _walk_leaf(e, FIELD_DECL);
+}
+
+void
+ExprWalker::_walk_VAR_DECL(const_tree e)
+{
+ _walk_leaf(e, VAR_DECL);
+}
+
+void
+ExprWalker::_walk_RESULT_DECL(const_tree e)
+{
+ _walk_leaf(e, RESULT_DECL);
+}
+
+void
+ExprWalker::_walk_PARM_DECL(const_tree e)
+{
+ _walk_leaf(e, PARM_DECL);
+}
+
+void
+ExprWalker::_walk_FUNCTION_DECL(const_tree e)
+{
+ _walk_leaf(e, FUNCTION_DECL);
+ for (tree parm = DECL_ARGUMENTS(e); parm; parm = DECL_CHAIN(parm))
+ {
+ walk(parm);
+ }
+
+}
diff --git a/gcc/expr-walker.hpp b/gcc/expr-walker.hpp
new file mode 100644
index 00000000000..e38084c8838
--- /dev/null
+++ b/gcc/expr-walker.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "types-inlines.h"
+
+
+class ExprWalker
+{
+public:
+ ExprWalker() {};
+ void walk(const_tree e);
+private:
+ virtual void _walk_pre(__attribute__((unused)) const_tree e) {};
+ void _walk(const_tree e);
+ virtual void _walk_post(__attribute__((unused)) const_tree e) {};
+ inline void _walk_leaf(const_tree e, const enum tree_code c);
+ inline void _walk_op_n(const_tree e, unsigned n);
+ inline void _walk_op_0(const_tree e, const enum tree_code c);
+ inline void _walk_op_1(const_tree e, const enum tree_code c);
+
+#define ExprWalkerFuncDecl(code) \
+ virtual void _walk_ ## code ## _pre(__attribute__((unused)) const_tree e) {}; \
+ void walk_ ## code (const_tree e); \
+ void _walk_ ## code (const_tree e); \
+ virtual void _walk_ ## code ## _post(__attribute__((unused)) const_tree e) {}
+
+ ExprWalkerFuncDecl(CONSTRUCTOR);
+ ExprWalkerFuncDecl(INTEGER_CST);
+ ExprWalkerFuncDecl(REAL_CST);
+ ExprWalkerFuncDecl(STRING_CST);
+ ExprWalkerFuncDecl(BIT_FIELD_REF);
+ ExprWalkerFuncDecl(ARRAY_REF);
+ ExprWalkerFuncDecl(MEM_REF);
+ ExprWalkerFuncDecl(COMPONENT_REF);
+ ExprWalkerFuncDecl(SSA_NAME);
+ ExprWalkerFuncDecl(ADDR_EXPR);
+ ExprWalkerFuncDecl(VIEW_CONVERT_EXPR);
+ ExprWalkerFuncDecl(IMAGPART_EXPR);
+ ExprWalkerFuncDecl(FIELD_DECL);
+ ExprWalkerFuncDecl(VAR_DECL);
+ ExprWalkerFuncDecl(RESULT_DECL);
+ ExprWalkerFuncDecl(PARM_DECL);
+ ExprWalkerFuncDecl(FUNCTION_DECL);
+ ExprWalkerFuncDecl(LE_EXPR);
+ ExprWalkerFuncDecl(EQ_EXPR);
+ ExprWalkerFuncDecl(GT_EXPR);
+};
+
diff --git a/gcc/gimple-accesser.c b/gcc/gimple-accesser.c
new file mode 100644
index 00000000000..18d74f499c0
--- /dev/null
+++ b/gcc/gimple-accesser.c
@@ -0,0 +1,105 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "types-inlines.h"
+#include "gimple-accesser.hpp"
+
+
+void
+GimpleAccesser::_walk_pre(gassign *s)
+{
+ // There seems to be quite a bit of code duplication here...
+ const enum gimple_rhs_class code = gimple_assign_rhs_class(s);
+ switch (code)
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ const_tree rhs3 = gimple_assign_rhs3(s);
+ gcc_assert(rhs3);
+ exprAccessor.update(rhs3, Read);
+ }
+ /* fall-through */
+ case GIMPLE_BINARY_RHS:
+ {
+ const_tree rhs2 = gimple_assign_rhs2(s);
+ gcc_assert(rhs2);
+ exprAccessor.update(rhs2, Read);
+ }
+ /* fall-through */
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ {
+ const_tree rhs1 = gimple_assign_rhs1(s);
+ exprAccessor.update(rhs1, Read);
+ const_tree lhs = gimple_assign_lhs(s);
+ if (!lhs) break;
+ exprAccessor.update(lhs, Write);
+ break;
+ }
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+void
+GimpleAccesser::_walk_pre(gcall *s)
+{
+ tree fndecl = gimple_call_fndecl(s);
+ unsigned n = gimple_call_num_args(s);
+ for (unsigned i = 0; i < n; i++)
+ {
+ const_tree a = gimple_call_arg(s, i);
+ gcc_assert(a);
+ exprAccessor.update(a, Read);
+ }
+
+ const_tree lhs = gimple_call_lhs(s);
+ if (!lhs) return;
+ exprAccessor.update(lhs, Write);
+}
+
+void
+GimpleAccesser::_walk_pre(greturn *s)
+{
+ const_tree val = gimple_return_retval(s);
+ if (!val) return;
+ exprAccessor.update(val, Read);
+}
+
+void
+GimpleAccesser::_walk_pre(gcond *s)
+{
+ const_tree lhs = gimple_cond_lhs(s);
+ const_tree rhs = gimple_cond_rhs(s);
+ gcc_assert(lhs && rhs);
+ exprAccessor.update(lhs, Read);
+ exprAccessor.update(rhs, Read);
+}
diff --git a/gcc/gimple-accesser.hpp b/gcc/gimple-accesser.hpp
new file mode 100644
index 00000000000..81228724daa
--- /dev/null
+++ b/gcc/gimple-accesser.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "gimple-walker.hpp"
+#include "expr-accessor.hpp"
+
+/*
+ * GimpleAccesser is intended to walk gimple
+ * and update a map that will hold information
+ * on whether a type was casted or not.
+ */
+class GimpleAccesser : public GimpleWalker
+{
+public:
+ GimpleAccesser() : GimpleWalker() {};
+ void print_accesses() { exprAccessor.print_accesses(); };
+ record_field_map_t get_map() { return exprAccessor.get_map(); };
+private:
+ ExprAccessor exprAccessor;
+ virtual void _walk_pre(gcall *s) final;
+ virtual void _walk_pre(gassign *s) final;
+ virtual void _walk_pre(greturn *s) final;
+ virtual void _walk_pre(gcond *s) final;
+ // Do we need a glabel? I don't think so...
+ // But we might need a gswitch.
+};
diff --git a/gcc/gimple-caster.c b/gcc/gimple-caster.c
new file mode 100644
index 00000000000..04283c9237a
--- /dev/null
+++ b/gcc/gimple-caster.c
@@ -0,0 +1,116 @@
+#include "gimple-caster.hpp"
+#include "gimple-pretty-print.h"
+
+#include "type-incomplete-equality.hpp"
+#include "type-stringifier.hpp"
+
+
+void
+GimpleCaster::_walk_pre(gassign *s)
+{
+ const enum gimple_rhs_class code = gimple_assign_rhs_class(s);
+ const bool valid_input = GIMPLE_SINGLE_RHS == code;
+ if (!valid_input) return;
+
+ // I originally was using gimple_assign_cast_p
+ // but that proved to be insufficient...
+ // So we have to use our equality comparison...
+ TypeIncompleteEquality equality;
+ const_tree lhs = gimple_assign_lhs(s);
+ const_tree rhs = gimple_assign_rhs1(s);
+ gcc_assert(lhs && rhs);
+ Reason reason {};
+ const_tree t_lhs = TREE_TYPE(lhs);
+ const_tree t_rhs = TREE_TYPE(rhs);
+ gcc_assert(t_lhs && t_rhs);
+ bool is_cast = !equality.equal(t_lhs, t_rhs);
+ TypeStringifier stringifier;
+ const std::string name_l = stringifier.stringify(t_lhs);
+ const std::string name_r = stringifier.stringify(t_rhs);
+ // If it is cast, we might need to look at the definition of rhs
+ // If the definition comes from a known function... then we are good...
+ bool is_ssa = TREE_CODE(rhs) == SSA_NAME;
+ while (is_ssa) {
+ gimple *def_for_rhs = SSA_NAME_DEF_STMT(rhs);
+ gcall *is_call = dyn_cast<gcall*>(def_for_rhs);
+ // poor man's goto
+ if (!is_call) break;
+
+ const_tree fn = gimple_call_fndecl(is_call);
+ // poor man's goto
+ if (!fn) break;
+
+ bool known_function = GimpleEscaper::filter_known_function(fn);
+ is_cast = !known_function;
+
+ is_ssa = false;
+ }
+ reason.type_is_casted = is_cast;
+ exprEscaper.update(lhs, reason);
+ exprEscaper.update(rhs, reason);
+ // TODO:
+ // I think this will re-do the work... But it might be necessary?
+ GimpleEscaper::_walk_pre(s);
+}
+
+void
+GimpleCaster::_walk_pre(gcall *s)
+{
+ GimpleEscaper::_walk_pre(s);
+
+ const_tree fn = gimple_call_fndecl(s);
+ // If there's no function declaration, how do we
+ // know the argument types?
+ if (!fn) return;
+
+ cgraph_node *node = cgraph_node::get(fn);
+ const bool known_function = GimpleEscaper::filter_known_function(node) || GimpleEscaper::filter_known_function(fn);
+ if (known_function) return;
+
+ const_tree f_t = TREE_TYPE(fn);
+ TypeIncompleteEquality equality;
+ TypeStringifier stringifier;
+
+ unsigned i = 0;
+ unsigned n = gimple_call_num_args(s);
+ for (tree a = TYPE_ARG_TYPES(f_t); NULL_TREE != a; a = TREE_CHAIN(a))
+ {
+ const_tree formal_t = TREE_VALUE(a);
+ // There seems to be a final VOID_TYPE at the end of some functions?
+ const enum tree_code code = TREE_CODE(formal_t);
+ const bool is_void = VOID_TYPE == code;
+ if (is_void) continue;
+
+ const_tree real = gimple_call_arg(s, i);
+ const_tree real_t = TREE_TYPE(real);
+ const bool is_casted = !equality.equal(formal_t, real_t);
+ const std::string name_r = stringifier.stringify(real_t);
+ const std::string name_f = stringifier.stringify(formal_t);
+ Reason arg_reason;
+ arg_reason.type_is_casted = is_casted;
+ exprEscaper.update(real, arg_reason);
+ i++;
+ }
+
+ /*
+ unsigned n = gimple_call_num_args(s);
+ for (unsigned i = 0; i < n; i++)
+ {
+ const_tree a = gimple_call_arg(s, i);
+ gcc_assert(a);
+ exprEscaper.update(a, reason);
+ }
+ */
+
+ const_tree lhs = gimple_call_lhs(s);
+ if (!lhs) return;
+
+ const_tree r_t = TREE_TYPE(f_t);
+ const_tree l_t TREE_TYPE(lhs);
+ const bool is_casted = !equality.equal(r_t, l_t);
+ const std::string name_r_t = stringifier.stringify(r_t);
+ const std::string name_l_t = stringifier.stringify(r_t);
+ Reason ret_reason;
+ ret_reason.type_is_casted = is_casted;
+ exprEscaper.update(lhs, ret_reason);
+}
diff --git a/gcc/gimple-caster.hpp b/gcc/gimple-caster.hpp
new file mode 100644
index 00000000000..74086606862
--- /dev/null
+++ b/gcc/gimple-caster.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "gimple-escaper.hpp"
+
+/*
+ * GimpleCaster is intended to walk gimple
+ * and update a map that will hold information
+ * on whether a type was casted or not.
+ */
+class GimpleCaster : public GimpleEscaper
+{
+public:
+ GimpleCaster(ptrset_t &types) : GimpleEscaper(types) {};
+private:
+ virtual void _walk_pre(gcall *s) final;
+ // Find out which structs are casted.
+ // Technically we could find this out on parent
+ virtual void _walk_pre(gassign *s) final;
+};
diff --git a/gcc/gimple-collector.c b/gcc/gimple-collector.c
new file mode 100644
index 00000000000..3a38e2334dd
--- /dev/null
+++ b/gcc/gimple-collector.c
@@ -0,0 +1,124 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "types-inlines.h"
+#include <set>
+#include <string>
+#include <map>
+
+#include "collect-types.h"
+#include "type-stringifier.hpp"
+
+#include "type-collector.hpp"
+#include "expr-walker.hpp"
+#include "expr-collector.hpp"
+#include "gimple-collector.hpp"
+
+void
+GimpleTypeCollector::_walk_pre(const_tree t)
+{
+ exprCollector.walk(t);
+}
+
+void
+GimpleTypeCollector::_walk_pre(gassign *s)
+{
+ const_tree lhs = gimple_assign_lhs(s);
+ exprCollector.walk(lhs);
+
+ const enum gimple_rhs_class gclass = gimple_assign_rhs_class(s);
+ switch (gclass)
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ const_tree rhs = gimple_assign_rhs3(s);
+ exprCollector.walk(rhs);
+ }
+ /* fall-through */
+ case GIMPLE_BINARY_RHS:
+ {
+ const_tree rhs = gimple_assign_rhs2(s);
+ exprCollector.walk(rhs);
+ }
+ /* fall-through */
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ {
+ const_tree rhs = gimple_assign_rhs1(s);
+ exprCollector.walk(rhs);
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+void
+GimpleTypeCollector::_walk_pre(greturn *s)
+{
+ const_tree retval = gimple_return_retval(s);
+ if (!retval) return;
+
+ exprCollector.walk(retval);
+}
+
+void
+GimpleTypeCollector::_walk_pre(gcond *s)
+{
+ const_tree lhs = gimple_cond_lhs(s);
+ exprCollector.walk(lhs);
+ const_tree rhs = gimple_cond_rhs(s);
+ exprCollector.walk(rhs);
+}
+
+void
+GimpleTypeCollector::_walk_pre(gcall *s)
+{
+ unsigned n = gimple_call_num_args(s);
+ for (unsigned i = 0; i < n; i++)
+ {
+ const_tree a = gimple_call_arg(s, i);
+ exprCollector.walk(a);
+ }
+
+ const_tree lhs = gimple_call_lhs(s);
+ if (!lhs) return;
+
+ exprCollector.walk(lhs);
+}
+
+void
+GimpleTypeCollector::print_collected()
+{
+ ptrset_t sets = get_pointer_set();
+ sets.print_in_points_to_record();
+
+}
diff --git a/gcc/gimple-collector.hpp b/gcc/gimple-collector.hpp
new file mode 100644
index 00000000000..0c7bba0720e
--- /dev/null
+++ b/gcc/gimple-collector.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "gimple-walker.hpp"
+#include "expr-collector.hpp"
+
+class GimpleTypeCollector : public GimpleWalker
+{
+private:
+ ExprCollector exprCollector;
+public:
+ GimpleTypeCollector() {};
+ ptrset_t get_pointer_set() { return exprCollector.get_pointer_set(); }
+ // TODO: I believe this could be made const
+ void print_collected();
+private:
+ virtual void _walk_pre(const_tree) final;
+ virtual void _walk_pre(gassign *s) final;
+ virtual void _walk_pre(greturn *s) final;
+ virtual void _walk_pre(gcond *s) final;
+ virtual void _walk_pre(gcall *s) final;
+};
+
diff --git a/gcc/gimple-escaper.c b/gcc/gimple-escaper.c
new file mode 100644
index 00000000000..0b45cee3ee9
--- /dev/null
+++ b/gcc/gimple-escaper.c
@@ -0,0 +1,263 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "gimple-pretty-print.h"
+#include <stdbool.h>
+
+#include "gimple-escaper.hpp"
+#include "type-stringifier.hpp"
+#include "type-incomplete-equality.hpp"
+
+
+void
+GimpleEscaper::_init()
+{
+ cgraph_node *cnode = NULL;
+ FOR_EACH_FUNCTION(cnode)
+ {
+ gcc_assert(cnode);
+ const bool filter = GimpleEscaper::filter_known_function(cnode);
+ if (filter) continue;
+
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ undefined.insert(decl);
+ }
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
+ {
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ undefined.erase(decl);
+ }
+}
+
+bool
+GimpleEscaper::is_function_escaping(cgraph_node *cnode)
+{
+ const bool filter = GimpleEscaper::filter_known_function(cnode);
+ if (filter) return false;
+
+ return cnode->externally_visible;
+}
+
+bool
+GimpleEscaper::is_function_escaping(const_tree fndecl)
+{
+ if (!fndecl) return true;
+
+ if (!TREE_PUBLIC(fndecl) || DECL_EXTERNAL(fndecl)) return false;
+
+ return true;
+}
+
+bool
+GimpleEscaper::is_variable_escaping(varpool_node *vnode)
+{
+ gcc_assert(vnode);
+ return vnode->externally_visible;
+}
+
+void
+GimpleEscaper::_walk_global(varpool_node *vnode)
+{
+ gcc_assert(vnode);
+ const_tree var_decl = vnode->decl;
+ Reason reason {} ;
+ const bool is_escaping = is_variable_escaping(vnode);
+ reason.global_is_visible = is_escaping;
+
+ tree initial = DECL_INITIAL (var_decl);
+ const bool constructor = initial ? TREE_CODE (initial) == CONSTRUCTOR : false;
+ const bool error_mark = initial ? TREE_CODE (initial) == ERROR_MARK: false;
+ reason.global_is_visible |= constructor || error_mark; // static initialization...
+
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(TREE_TYPE(var_decl));
+ log("%s %s\n", vnode->name(), name.c_str());
+ exprEscaper.update(var_decl, reason);
+ GimpleWalker::_walk_global(vnode);
+
+}
+
+bool
+GimpleEscaper::filter_known_function(const_tree fndecl)
+{
+ assert_is_type(fndecl, FUNCTION_DECL);
+ if (fndecl_built_in_p (fndecl))
+ {
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case BUILT_IN_FREE:
+ case BUILT_IN_MALLOC:
+ case BUILT_IN_REALLOC:
+ case BUILT_IN_CALLOC:
+ case BUILT_IN_MEMSET:
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ const_tree identifier_node = DECL_NAME(fndecl);
+ gcc_assert(identifier_node);
+ bool filter = false;
+ const char *_specqsort= "spec_qsort";
+ const char *_med3 = "arc_compare";
+ const char *_getArcPosition = "getArcPosition";
+ const char *_med3_ = "med3.part.0";
+ const char *_med3_2 = "med3";
+ const char* name = IDENTIFIER_POINTER(identifier_node);
+ gcc_assert(name);
+ filter |= strcmp(_specqsort, name) == 0;
+ filter |= strcmp(_med3, name) == 0;
+ filter |= strcmp(_med3_, name) == 0;
+ filter |= strcmp(_med3_2, name) == 0;
+ filter |= strcmp(_getArcPosition, name) == 0;
+ return filter;
+}
+
+bool
+GimpleEscaper::filter_known_function(cgraph_node *node)
+{
+ if (!node) return false;
+ return filter_known_function(node->decl);
+}
+
+void
+GimpleEscaper::_walk_pre(const_tree t)
+{
+ // Is any global variable escaping?
+ Reason reason;
+ exprEscaper.update(t, reason);
+}
+
+void
+GimpleEscaper::_walk_pre(gassign *s)
+{
+ Reason reason;
+ const enum gimple_rhs_class code = gimple_assign_rhs_class(s);
+ switch (code)
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ const_tree rhs3 = gimple_assign_rhs3(s);
+ exprEscaper.update(rhs3, reason);
+ }
+ /* fall-through */
+ case GIMPLE_BINARY_RHS:
+ {
+ const_tree rhs2 = gimple_assign_rhs2(s);
+ exprEscaper.update(rhs2, reason);
+ }
+ /* fall-through */
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ {
+ const_tree rhs1 = gimple_assign_rhs1(s);
+ exprEscaper.update(rhs1, reason);
+ const_tree lhs = gimple_assign_lhs(s);
+ if (!lhs) break;
+ exprEscaper.update(lhs, reason);
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+}
+
+void
+GimpleEscaper::_walk_pre(greturn *s)
+{
+ Reason reason;
+ const_tree val = gimple_return_retval(s);
+ if (!val) return;
+ exprEscaper.update(val, reason);
+}
+
+void
+GimpleEscaper::_walk_pre(gcond *s)
+{
+ Reason reason;
+ const_tree lhs = gimple_cond_lhs(s);
+ const_tree rhs = gimple_cond_rhs(s);
+ gcc_assert(lhs && rhs);
+ exprEscaper.update(lhs, reason);
+ exprEscaper.update(rhs, reason);
+}
+
+void
+GimpleEscaper::_walk_pre(gcall *s)
+{
+ const_tree fn = gimple_call_fndecl(s);
+ // gcc_assert(fn);
+ // The above will not always be true
+ cgraph_node *node = fn ? cgraph_node::get(fn) : NULL;
+ // const bool fn_and_node = fn && node;
+ // const bool not_function_and_not_node = !fn && !node;
+ // const bool test = fn_and_node ^ not_function_and_not_node;
+ // gcc_assert(test);
+ // The above is not true...
+ // which means that there are functions with function declarations
+ // but no corresponding cgraph_node.
+ //
+ // What does that mean for our analysis?
+ // It means that we cannot find out if a function is escaping all the time..?
+ // Or at least via the cnode...
+ // It seems to me that the correct way to deal with this is saying that
+ // functions which do not have a cgraph_node should be escaping,
+ // but this will mark some interesting types as escaping...
+ const bool _is_function_escaping = node ? is_function_escaping(node) : is_function_escaping(fn);
+ const bool is_undefined = undefined.find(fn) != undefined.end();
+ const bool _is_escaping = is_undefined || _is_function_escaping;
+
+ TypeStringifier stringifier;
+ Reason arg_reason;
+ arg_reason.parameter_is_visible = _is_escaping;
+ arg_reason.is_indirect = !fn;
+ unsigned n = gimple_call_num_args(s);
+ for (unsigned i = 0; i < n; i++)
+ {
+ const_tree a = gimple_call_arg(s, i);
+ gcc_assert(a);
+ exprEscaper.update(a, arg_reason);
+ }
+
+ const_tree lhs = gimple_call_lhs(s);
+ if (!lhs) return;
+ Reason return_reason;
+ return_reason.return_is_visible = _is_escaping;
+ return_reason.is_indirect = !fn;
+ exprEscaper.update(lhs, return_reason);
+}
diff --git a/gcc/gimple-escaper.hpp b/gcc/gimple-escaper.hpp
new file mode 100644
index 00000000000..490ebc20fe0
--- /dev/null
+++ b/gcc/gimple-escaper.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "gimple-walker.hpp"
+#include "expr-escaper.hpp"
+#include "collect-types.h"
+
+class GimpleEscaper : public GimpleWalker
+{
+public:
+ GimpleEscaper(ptrset_t &types) : exprEscaper(types) { _init(); };
+ ExprEscaper exprEscaper;
+ ptrset_t get_sets() { return exprEscaper.get_sets(); };
+ void print_reasons() { exprEscaper.print_reasons(); };
+protected:
+ typedef std::set<const_tree> undefset;
+ undefset undefined;
+ void _init();
+ static bool filter_known_function(cgraph_node *);
+ static bool filter_known_function(const_tree);
+ static bool is_function_escaping(cgraph_node *);
+ static bool is_function_escaping(const_tree);
+ static bool is_variable_escaping(varpool_node *);
+ static bool _is_assignment_casted(gassign *s);
+ virtual void _walk_global(varpool_node *);
+ virtual void _walk_pre(gassign *s) ;
+ virtual void _walk_pre(greturn *s) ;
+ virtual void _walk_pre(gcond *s) ;
+ virtual void _walk_pre(gcall *s) ;
+ virtual void _walk_pre(const_tree) ;
+};
diff --git a/gcc/gimple-rewriter.c b/gcc/gimple-rewriter.c
new file mode 100644
index 00000000000..31fcb74ed86
--- /dev/null
+++ b/gcc/gimple-rewriter.c
@@ -0,0 +1,268 @@
+#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 "gimple-rewriter.hpp"
+#include "type-stringifier.hpp"
+
+void
+GimpleTypeRewriter::_walk_pre(const_tree e)
+{
+ // This is for local variables
+ // and other declarations
+ exprTypeRewriter.walk(e);
+ bool _delete = exprTypeRewriter._delete;
+ exprTypeRewriter._delete = false;
+ // I don't think it is possible here (local variable delcarations and such);
+ gcc_assert(!_delete);
+ const bool is_interesting = exprTypeRewriter.is_interesting_type(TREE_TYPE(e));
+
+ /*
+ const bool is_ssa_name = TREE_CODE(e) == SSA_NAME;
+ if (is_ssa_name)
+ {
+ tree l = (tree) e;
+ if (SSA_NAME_VAR(l) == NULL_TREE) return;
+ if (TREE_TYPE(l) != TREE_TYPE(SSA_NAME_VAR(l))) { log("unequal\n"); }
+
+ TREE_TYPE(l) = TREE_TYPE(SSA_NAME_VAR(l));
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(TREE_TYPE(l));
+ log("new name %s\n", name.c_str());
+ }
+ */
+
+ const bool is_var_decl = TREE_CODE(e) == VAR_DECL;
+ const bool is_valid = is_interesting && is_var_decl;
+ if (!is_valid) return;
+ relayout_decl((tree)e);
+}
+
+void
+GimpleTypeRewriter::_walk_pre(gimple *s)
+{
+}
+
+void
+GimpleTypeRewriter::_walk_pre(gcall *s)
+{
+}
+
+void
+GimpleTypeRewriter::_walk_pre(greturn *s)
+{
+ const_tree val = gimple_return_retval(s);
+ if (!val) return;
+ log("rewriting a return value\n");
+ exprTypeRewriter.walk(val);
+ bool _delete = exprTypeRewriter._delete;
+ exprTypeRewriter._delete = false;
+ // We can't probably have a write in a return statement.
+ gcc_assert(!_delete);
+}
+
+void
+GimpleTypeRewriter::handle_pointer_arithmetic(gimple *s)
+{
+ const enum tree_code p = POINTER_PLUS_EXPR;
+ const enum tree_code d = POINTER_DIFF_EXPR;
+ const enum tree_code e = gimple_expr_code(s);
+ const bool is_pointer_plus = p == e;
+ const bool is_pointer_diff = d == e;
+ bool is_valid_input = is_pointer_plus != is_pointer_diff;
+ gcc_assert(is_valid_input);
+ // TODO: Implement pointer diff
+
+ const enum gimple_rhs_class rhs_class = gimple_assign_rhs_class(s);
+ is_valid_input = GIMPLE_BINARY_RHS == rhs_class;
+ gcc_assert(is_valid_input);
+
+ tree op_0 = gimple_assign_rhs1(s);
+ tree op_1 = gimple_assign_rhs2(s);
+ tree lhs = gimple_assign_lhs(s);
+ tree op_0_t = TREE_TYPE(op_0);
+ tree op_1_t = TREE_TYPE(op_1);
+ tree lhs_t = TREE_TYPE(lhs);
+ const bool is_op_0_t_interesting = exprTypeRewriter.is_interesting_type(op_0_t);
+ const bool is_op_1_t_interesting = exprTypeRewriter.is_interesting_type(op_1_t);
+ const bool is_lhs_t_interesting = exprTypeRewriter.is_interesting_type(lhs_t);
+ bool is_interesting_case = is_op_0_t_interesting || is_op_1_t_interesting || is_lhs_t_interesting;
+ TypeStringifier stringifier;
+ std::string name_0 = stringifier.stringify(op_0_t);
+ std::string name_1 = stringifier.stringify(op_1_t);
+ std::string name_l = stringifier.stringify(lhs_t);
+ log("is interesting case %s\n", is_interesting_case ? "t" : "f");
+ log("op_0 %s\n", name_0.c_str());
+ log("op_1 %s\n", name_1.c_str());
+ log("lhs_t%s\n", name_l.c_str());
+ if (!is_interesting_case) return;
+
+ const enum tree_code op_1_code = TREE_CODE(op_1);
+ const enum tree_code op_0_code = TREE_CODE(op_0);
+ const bool is_op_0_icst = INTEGER_CST == op_0_code;
+ const bool is_op_1_icst = INTEGER_CST == op_1_code;
+ const bool is_constant_case = is_op_0_icst != is_op_1_icst;
+ if (!is_constant_case)
+ {
+ exprTypeRewriter.handle_pointer_arithmetic_nonconstant(s, op_0, op_1, is_pointer_plus);
+ bool _delete = exprTypeRewriter._delete;
+ exprTypeRewriter._delete = false;
+ // probably no deletion in pointer arithmetic...
+ gcc_assert(!_delete);
+ return;
+ }
+
+ tree integer_constant = is_op_0_icst ? op_0 : op_1;
+ tree maybe_pointer = is_op_0_icst ? op_1 : op_0;
+ const_tree maybe_pointer_t = TREE_TYPE(maybe_pointer);
+ assert_is_type(maybe_pointer_t, POINTER_TYPE);
+ tree pointer_variable = maybe_pointer;
+
+ exprTypeRewriter.handle_pointer_arithmetic_constants(s, pointer_variable, integer_constant, is_pointer_plus);
+ bool _delete = exprTypeRewriter._delete;
+ exprTypeRewriter._delete = false;
+ // probably no deletion in pointer arithmetic
+ gcc_assert(!_delete);
+}
+
+
+void
+GimpleTypeRewriter::_walk_pre(gassign *s)
+{
+ const enum gimple_rhs_class code = gimple_assign_rhs_class(s);
+
+ switch (code)
+ {
+ case GIMPLE_TERNARY_RHS:
+ {
+ const_tree rhs3 = gimple_assign_rhs3(s);
+ exprTypeRewriter.walk(rhs3);
+ }
+ /* fall-through */
+ case GIMPLE_BINARY_RHS:
+ {
+ const_tree rhs2 = gimple_assign_rhs2(s);
+ exprTypeRewriter.walk(rhs2);
+ }
+ /* fall-through */
+ case GIMPLE_UNARY_RHS:
+ case GIMPLE_SINGLE_RHS:
+ {
+ const_tree rhs1 = gimple_assign_rhs1(s);
+ exprTypeRewriter.walk(rhs1);
+ const_tree lhs = gimple_assign_lhs(s);
+ if (!lhs) break;
+ // Here is the only place where we likely can delete a statement.
+ exprTypeRewriter.walk(lhs);
+ bool _delete = exprTypeRewriter._delete;
+ exprTypeRewriter._delete = false;
+ if (_delete)
+ {
+ _deleted = true;
+ }
+ }
+ break;
+ default:
+ gcc_unreachable();
+ break;
+ }
+
+
+ const enum tree_code e_code = gimple_expr_code(s);
+ log("is this the statment i'm looking for? %s\n", get_tree_code_name(e_code));
+ print_gimple_stmt(dump_file, s, 0);
+ log("\n");
+ switch (e_code)
+ {
+ case POINTER_PLUS_EXPR:
+ case POINTER_DIFF_EXPR:
+ handle_pointer_arithmetic(s);
+ break;
+ case COMPONENT_REF:
+ {
+ log("i am missing a component ref\n");
+ print_gimple_stmt(dump_file, s, 0);
+ log("\n");
+
+ TypeStringifier stringifier;
+ tree e = gimple_assign_rhs1(s);
+ const_tree type = TREE_TYPE(e);
+ std::string name = stringifier.stringify(type);
+ log("%s\n", name.c_str());
+ }
+ break;
+ case MULT_EXPR:
+ {
+ TypeStringifier stringifier;
+ tree op1 = gimple_assign_rhs2(s);
+ tree op2 = gimple_assign_rhs1(s);
+ tree op1_t = TREE_TYPE(op1);
+ tree op2_t = TREE_TYPE(op2);
+ std::string op1_s = stringifier.stringify(op1_t);
+ std::string op2_s = stringifier.stringify(op2_t);
+ log("multiplication\n");
+ log("%s * %s\n", op1_s.c_str(), op2_s.c_str());
+ }
+ break;
+ default:
+ {
+ log("missing %s\n", get_tree_code_name(e_code));
+ }
+ break;
+ }
+
+}
+
+void
+GimpleTypeRewriter::_walk_pre(gcond *s)
+{
+}
+
+void
+GimpleTypeRewriter::_rewrite_function_decl()
+{
+ // NOTE: It seems we only need to rewrite the return type
+ // for now...
+ cgraph_node *node = NULL;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node)
+ {
+ node->get_untransformed_body();
+ tree fndecl = node->decl;
+ gcc_assert(fndecl);
+ exprTypeRewriter.walk(fndecl);
+ tree decl = DECL_RESULT(fndecl);
+ if (decl) exprTypeRewriter.walk(decl);
+ }
+}
+
+void
+GimpleTypeRewriter::_walk_pre(gphi *s)
+{
+ unsigned n = gimple_phi_num_args (s);
+ for (unsigned i = 0; i < n; i++)
+ {
+ tree a = gimple_phi_arg_def(s, i);
+ exprTypeRewriter.walk(a);
+ }
+}
diff --git a/gcc/gimple-rewriter.hpp b/gcc/gimple-rewriter.hpp
new file mode 100644
index 00000000000..03d5bfa21ad
--- /dev/null
+++ b/gcc/gimple-rewriter.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "gimple-walker.hpp"
+#include "expr-rewriter.hpp"
+#include "type-reconstructor.hpp"
+
+class GimpleTypeRewriter : public GimpleWalker
+{
+public:
+ GimpleTypeRewriter(TypeReconstructor::reorg_record_map_t map, TypeReconstructor::reorg_field_map_t map2) : exprTypeRewriter(map, map2) {};
+ void _rewrite_function_decl();
+private:
+ ExprTypeRewriter exprTypeRewriter;
+ void handle_pointer_arithmetic(gimple *s);
+ virtual void _walk_pre(gphi* ) final;
+ virtual void _walk_pre(const_tree) final;
+ virtual void _walk_pre(gimple*) final;
+ virtual void _walk_pre(gcall *s) final;
+ virtual void _walk_pre(greturn *s) final;
+ virtual void _walk_pre(gassign *s) final;
+ virtual void _walk_pre(gcond *s) final;
+};
diff --git a/gcc/gimple-walker.c b/gcc/gimple-walker.c
new file mode 100644
index 00000000000..1a858419c27
--- /dev/null
+++ b/gcc/gimple-walker.c
@@ -0,0 +1,257 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "types-inlines.h"
+#include <set>
+#include <string>
+#include <map>
+
+#include "collect-types.h"
+#include "type-stringifier.hpp"
+
+#include "type-collector.hpp"
+#include "expr-walker.hpp"
+#include "expr-collector.hpp"
+#include "gimple-walker.hpp"
+#include "tree-cfg.h"
+
+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);
+}
+
+void
+GimpleWalker::walk()
+{
+ _walk_globals();
+
+ std::set<tree> fndecls;
+ cgraph_node *node = NULL;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node)
+ {
+ print_function(node);
+ node->get_untransformed_body();
+ const bool already_in_set = fndecls.find(node->decl) != fndecls.end();
+ if (already_in_set) continue;
+ _walk_cnode(node);
+ fndecls.insert(node->decl);
+ }
+}
+
+void
+GimpleWalker::_walk_globals()
+{
+ varpool_node *vnode = NULL;
+ FOR_EACH_VARIABLE(vnode)
+ {
+ _walk_global(vnode);
+ }
+}
+
+void
+GimpleWalker::_walk_global(varpool_node *vnode)
+{
+ gcc_assert(vnode);
+ struct ipa_ref *ref = NULL;
+ for (unsigned i = 0; vnode->iterate_referring(i, ref); i++)
+ {
+ tree var_decl = vnode->decl;
+ walk(var_decl);
+ }
+}
+
+void
+GimpleWalker::_walk_ssa_names(cgraph_node *cnode)
+{
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION(decl);
+ gcc_assert(func);
+ size_t i = 0;
+ tree ssa_name = NULL;
+ push_cfun(func);
+ FOR_EACH_SSA_NAME(i, ssa_name, cfun)
+ {
+ gcc_assert(ssa_name);
+ walk(ssa_name);
+ }
+ pop_cfun();
+}
+
+void
+GimpleWalker::_walk_cnode(cgraph_node *cnode)
+{
+ gcc_assert(cnode);
+ _walk_decl(cnode);
+ _walk_locals(cnode);
+ _walk_ssa_names(cnode);
+ _walk_bb(cnode);
+}
+
+
+void
+GimpleWalker::_walk_decl(cgraph_node *cnode)
+{
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ walk(decl);
+}
+
+void
+GimpleWalker::_walk_locals(cgraph_node *cnode)
+{
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION(decl);
+ gcc_assert(func);
+ int i = 0;
+ tree var_decl = NULL;
+ FOR_EACH_LOCAL_DECL(func, i, var_decl)
+ {
+ gcc_assert(var_decl);
+ walk(var_decl);
+ }
+}
+
+
+void
+GimpleWalker::_walk_bb(cgraph_node* cnode)
+{
+ gcc_assert(cnode);
+ cnode->get_untransformed_body();
+ const_tree decl = cnode->decl;
+ gcc_assert(decl);
+ function *func = DECL_STRUCT_FUNCTION(decl);
+ gcc_assert(func);
+ basic_block bb = NULL;
+ push_cfun(func);
+ FOR_EACH_BB_FN(bb, func)
+ {
+ _walk(bb);
+ }
+ pop_cfun();
+}
+
+void
+GimpleWalker::_walk(basic_block bb)
+{
+ gcc_assert(bb);
+ bool first = true;
+ gimple_stmt_iterator gsi = gsi_start_bb(bb);
+
+ while (!gsi_end_p(gsi))
+ {
+ gimple *stmt = gsi_stmt(gsi);
+ walk(stmt);
+ if (_deleted) unlink_stmt_vdef (stmt);
+ if (_deleted) { gsi_remove(&gsi, true); }
+ else { gsi_next(&gsi); }
+ _deleted = false;
+ }
+
+
+ for (gimple_stmt_iterator gsi = gsi_start_phis(bb); !gsi_end_p(gsi); gsi_next(&gsi))
+ {
+ gimple *stmt = gsi_stmt(gsi);
+ walk(stmt);
+ }
+}
+
+void
+GimpleWalker::walk(gimple *stmt)
+{
+ _walk_pre(stmt);
+ _walk(stmt);
+ _walk_post(stmt);
+}
+
+void
+GimpleWalker::_walk(gimple *stmt)
+{
+ gcc_assert(stmt);
+
+#define GimpleWalkerWalk(type) \
+ if (type s = dyn_cast< type >(stmt)) \
+ { \
+ _walk_pre(stmt); \
+ walk(s); \
+ _walk_post(stmt); \
+ return; \
+ }
+
+ GimpleWalkerWalk(gassign*);
+ GimpleWalkerWalk(greturn*);
+ GimpleWalkerWalk(gcond*);
+ GimpleWalkerWalk(gcall*);
+ GimpleWalkerWalk(glabel*);
+ GimpleWalkerWalk(gswitch*);
+ GimpleWalkerWalk(gphi*);
+
+
+ const enum gimple_code code = gimple_code (stmt);
+ switch (code)
+ {
+ case GIMPLE_PREDICT: return;
+ case GIMPLE_DEBUG: return;
+ default: break;
+ }
+ const char* name = gimple_code_name[code];
+ log("gimple code name %s\n", name);
+ gcc_unreachable();
+}
+
+#define GimpleWalkerFuncDef(type) \
+void \
+GimpleWalker::walk (type e) \
+{ \
+ _walk_pre (e); \
+ _walk (e); \
+ _walk_post (e); \
+} \
+\
+void \
+GimpleWalker::_walk (__attribute__((unused)) type e) \
+{ \
+}
+
+GimpleWalkerFuncDef(const_tree)
+GimpleWalkerFuncDef(gassign *)
+GimpleWalkerFuncDef(greturn *)
+GimpleWalkerFuncDef(gcond *)
+GimpleWalkerFuncDef(gcall *)
+GimpleWalkerFuncDef(glabel *)
+GimpleWalkerFuncDef(gswitch *)
+GimpleWalkerFuncDef(gphi *)
+
diff --git a/gcc/gimple-walker.hpp b/gcc/gimple-walker.hpp
new file mode 100644
index 00000000000..6c3742afb0b
--- /dev/null
+++ b/gcc/gimple-walker.hpp
@@ -0,0 +1,69 @@
+#pragma once
+
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include <set>
+
+class GimpleWalker
+{
+public:
+ GimpleWalker() : _deleted(false) {};
+ void walk();
+
+protected:
+
+ bool _deleted;
+ virtual void _walk_global(varpool_node*);
+ void _walk_globals();
+ void _walk_ssa_names(cgraph_node *cnode);
+ void _walk_cnode(cgraph_node *cnode);
+ void _walk_decl(cgraph_node *cnode);
+ void _walk_locals(cgraph_node *cnode);
+ void _walk_bb(cgraph_node *cnode);
+ void _walk(basic_block bb);
+
+#define GimpleWalkerFuncDecl(type) \
+ virtual void _walk_pre(type stmt) {}; \
+ void walk(type stmt); \
+ void _walk(type stmt); \
+ virtual void _walk_post(type stmt) {}
+
+ GimpleWalkerFuncDecl(const_tree);
+ GimpleWalkerFuncDecl(gimple*);
+ GimpleWalkerFuncDecl(gassign*);
+ GimpleWalkerFuncDecl(greturn*);
+ GimpleWalkerFuncDecl(gcond*);
+ GimpleWalkerFuncDecl(gcall*);
+ GimpleWalkerFuncDecl(glabel*);
+ GimpleWalkerFuncDecl(gswitch*);
+ GimpleWalkerFuncDecl(gphi*);
+};
+
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 6cc7e66059d..ea5e6100741 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -6397,6 +6397,23 @@ gimple_transaction_set_subcode (gtransaction *transaction_stmt,
transaction_stmt->subcode = subcode;
}
+
+/* Return the return value for GIMPLE_RETURN GS. */
+
+static inline tree
+gimple_return_retval (const greturn *gs)
+{
+ return gs->op[0];
+}
+
+static inline tree
+gimple_return_retval(const gimple *gs)
+{
+ GIMPLE_CHECK(gs, GIMPLE_RETURN);
+ const greturn *gr = dyn_cast<const greturn *> (gs);
+ return gimple_return_retval (gr);
+}
+
/* Return a pointer to the return value for GIMPLE_RETURN GS. */
static inline tree *
@@ -6405,15 +6422,14 @@ gimple_return_retval_ptr (greturn *gs)
return &gs->op[0];
}
-/* Return the return value for GIMPLE_RETURN GS. */
-
-static inline tree
-gimple_return_retval (const greturn *gs)
+static inline tree *
+gimple_return_retval_ptr (gimple *gs)
{
- return gs->op[0];
+ GIMPLE_CHECK(gs, GIMPLE_RETURN);
+ greturn *gr = dyn_cast<greturn *> (gs);
+ return gimple_return_retval_ptr (gr);
}
-
/* Set RETVAL to be the return value for GIMPLE_RETURN GS. */
static inline void
diff --git a/gcc/ipa-prototype.c b/gcc/ipa-prototype.c
new file mode 100644
index 00000000000..76d5b223900
--- /dev/null
+++ b/gcc/ipa-prototype.c
@@ -0,0 +1,330 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "ipa-prototype.h"
+#include "type-collector.hpp"
+#include "type-stringifier.hpp"
+#include <map>
+#include <vector>
+#include "type-escaper.hpp"
+#include "expr-escaper.hpp"
+#include "gimple-walker.hpp"
+#include "gimple-collector.hpp"
+#include "gimple-escaper.hpp"
+#include "type-structural-equality.hpp"
+#include "type-structural-main-variant.hpp"
+#include "type-incomplete-equality.hpp"
+
+//#define OPTIMIZED
+#define SANITY_CHECKS
+
+typedef std::set<const_tree> undefset;
+
+void
+Reason::print() const
+{
+ log("e=%d g=%d p=%d r=%d c=%d v=%d u=%d i=%d\n", this->is_escaping(), this->global_is_visible, this->parameter_is_visible, this->return_is_visible, this->type_is_casted, this->type_is_volatile, this->type_is_in_union, this->is_indirect);
+}
+
+Reason
+Reason::operator|(const Reason &other)
+{
+ Reason retval {};
+ retval.global_is_visible = this->global_is_visible | other.global_is_visible;
+ retval.parameter_is_visible = this->parameter_is_visible | other.parameter_is_visible;
+ retval.return_is_visible = this->return_is_visible | other.return_is_visible;
+ retval.type_is_casted = this->type_is_casted | other.type_is_casted;
+ retval.type_is_volatile = this->type_is_volatile | other.type_is_volatile;
+ retval.type_is_in_union = this->type_is_in_union | other.type_is_in_union;
+ retval.is_indirect = this->is_indirect | other.is_indirect;
+ return retval;
+}
+
+Reason&
+Reason::operator|=(const Reason &other)
+{
+ this->global_is_visible |= other.global_is_visible;
+ this->parameter_is_visible |= other.parameter_is_visible;
+ this->return_is_visible |= other.return_is_visible;
+ this->type_is_casted |= other.type_is_casted;
+ this->type_is_volatile |= other.type_is_volatile;
+ this->type_is_in_union |= other.type_is_in_union;
+ this->is_indirect |= other.is_indirect;
+ return *this;
+}
+
+
+
+static inline void
+assert_type_is_in_ptrset(const_tree type, ptrset_t &types)
+{
+#ifdef SANITY_CHECKS
+ gcc_assert(types.in_points_to_record(type));
+#endif
+}
+
+static inline void
+assert_type_is_in_universe(const_tree type, ptrset_t &types)
+{
+#ifdef SANITY_CHECKS
+ gcc_assert(types.in_universe(type));
+#endif
+}
+
+static bool
+is_variable_escaping(varpool_node *vnode)
+{
+ gcc_assert(vnode);
+ return vnode->externally_visible;
+}
+
+static void
+place_escaping_types_in_set(ptrset_t &types, typemap &calc)
+{
+ for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i)
+ {
+ const_tree type = i->first;
+ // We should have seen it before
+ assert_type_is_in_universe(type, types);
+
+ // We should only track interesting types
+ // Types which are not in points_to_record are the ones
+ // that are pointed to by records.
+ // I think it is possible to prune them ahead of time...
+ if (!types.in_points_to_record(type)) continue;
+
+ const Reason reason = i->second;
+ reason.is_escaping() ? types.escaping.insert(type) : types.non_escaping.insert(type);
+ }
+}
+
+static void
+sanity_check_escape_xor_not(ptrset_t &types)
+{
+ for (auto i = types.escaping.cbegin(), e = types.escaping.cend(); i != e; ++i)
+ {
+ for (auto j = types.non_escaping.cbegin(), f = types.non_escaping.cend(); j != f; ++j)
+ {
+ const_tree type_esc = *i;
+ gcc_assert(type_esc);
+ const_tree type_non = *j;
+ gcc_assert(type_non);
+ //const bool valid_sets = !eq_type_compare(type_esc, type_non);
+ //if (valid_sets) continue;
+ //log("comparing %s == %s\n", type_to_string(type_esc).c_str(), type_to_string(type_non).c_str());
+ //TODO: Remove this comment once we have restricted the "repairing" of sets a bit more.
+ //gcc_assert(valid_sets);
+ }
+ }
+}
+
+static void
+sanity_check_escape_union_not_equals_ptrset(ptrset_t &types)
+{
+ typeset _union;
+ for (auto i = types.escaping.cbegin(), e = types.escaping.cend(); i != e; ++i)
+ {
+ const_tree type = *i;
+ _union.insert(type);
+ }
+
+ for (auto i = types.non_escaping.cbegin(), e = types.non_escaping.cend(); i != e; ++i)
+ {
+ const_tree type = *i;
+ _union.insert(type);
+ }
+
+
+ for (auto i = types.points_to_record.cbegin(), e = types.points_to_record.cend(); i != e; ++i)
+ {
+ const_tree type = *i;
+ const bool in_union = _union.find(type) != _union.end();
+ if (in_union) continue;
+ //log("this type was not found in union %s\n", type_to_string(type).c_str());
+ //TODO: FIXME: This has to be enabled for the sanity check to work
+ //But at the moment there's one type which isn't working correctly :(
+ gcc_unreachable();
+ }
+
+}
+
+static void
+fix_escaping_types_in_set(ptrset_t &types)
+{
+ bool fixed_point_reached = false;
+ TypeIncompleteEquality structuralEquality;
+ TypeStringifier stringifier;
+ do {
+ std::vector<const_tree> fixes;
+ fixed_point_reached = true;
+ for (auto i = types.escaping.cbegin(), e = types.escaping.cend(); i != e; ++i)
+ {
+ for (auto j = types.non_escaping.cbegin(), f = types.non_escaping.cend(); j != f; ++j)
+ {
+ const_tree type_esc = *i;
+ gcc_assert(type_esc);
+ const_tree type_non = *j;
+ gcc_assert(type_non);
+ // There can be cases where incomplete types are marked as non-escaping
+ // and complete types counter parts are marked as escaping.
+ //const bool interesting_case = eq_type_compare(type_esc, type_non);
+ //TODO: We are going to need a different type comparison because this one
+ //fails to take into account the recursion...
+ TypeStringifier stringifier;
+ std::string type_esc_name = TypeStringifier::get_type_identifier(type_esc);
+ std::string type_non_name = TypeStringifier::get_type_identifier(type_non);
+ //std::string file("FILE");
+ //bool i_care = type_esc_name.compare(file) == 0;
+ //i_care &= type_non_name.compare(file) == 0;
+
+ type_esc_name = stringifier.stringify(type_esc);
+ type_non_name = stringifier.stringify(type_non);
+
+ const bool equal = structuralEquality.equal(type_esc, type_non);
+ if (!equal) continue;
+
+ log("recalulating %s == %s\n", type_esc_name.c_str(), type_non_name.c_str());
+ fixed_point_reached = false;
+ // Add incomplete to escaping
+ // delete incomplete from non_escaping
+ // We shouldn't do that inside our iteration loop.
+ fixes.push_back(type_non);
+ }
+ }
+
+ for (auto i = fixes.cbegin(), e = fixes.cend(); i != e; ++i)
+ {
+ const_tree escaping_type = *i;
+ types.escaping.insert(escaping_type);
+ types.non_escaping.erase(escaping_type);
+ }
+ } while (!fixed_point_reached);
+}
+
+static void
+print_escaping_types_in_set(ptrset_t &types)
+{
+ std::vector<const_tree> fixes;
+ for (auto i = types.non_escaping.cbegin(), e = types.non_escaping.cend(); i != e; ++i)
+ {
+ const_tree type_non = *i;
+ gcc_assert(type_non);
+ const enum tree_code code = TREE_CODE(type_non);
+ const bool is_function = FUNCTION_TYPE == code;
+ // I just don't want to print out functions.
+ if (is_function) continue;
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(type_non);
+ log("non_escaping: %s \n", name.c_str());
+ }
+
+}
+
+static void
+print_sequal_types(ptrset_t &types)
+{
+ std::vector<const_tree> fixes;
+ TypeStructuralEquality structuralEquality;
+ TypeStringifier stringifier;
+ for (auto i = types.universe.cbegin(), e = types.universe.cend(); i != e; ++i)
+ {
+ for (auto j = types.universe.cbegin(), e = types.universe.cend(); j != e; ++j)
+ {
+ const_tree t_i = *i;
+ const_tree t_j = *j;
+ const bool eq = structuralEquality.equal(t_i, t_j);
+ std::string n_i = stringifier.stringify(t_i);
+ std::string n_j = stringifier.stringify(t_j);
+ log("%s = %s == %s\n", eq ? "t" : "f", n_i.c_str(), n_j.c_str());
+ }
+ }
+}
+
+
+static unsigned int
+iphw_execute()
+{
+
+ GimpleTypeCollector collector;
+ collector.walk();
+ ptrset_t types = collector.get_pointer_set();
+
+ GimpleEscaper gimpleEscaper(types);
+ gimpleEscaper.walk();
+
+ typemap eacalc; // Escape Analysis Calculation
+ // Intermediate results
+ // Do not read escape analysis results from here
+ //calculate_escaping_types(types, eacalc);
+ //print_sequal_types(types);
+ place_escaping_types_in_set(types, gimpleEscaper.exprEscaper.typeEscaper.calc);
+ fix_escaping_types_in_set(types);
+ // -fipa-protytpe -fdump-ipa-prototype
+ print_escaping_types_in_set(types);
+ sanity_check_escape_xor_not(types);
+ sanity_check_escape_union_not_equals_ptrset(types);
+ gcc_unreachable();
+ return 0;
+}
+
+namespace {
+const pass_data pass_data_ipa_prototype =
+{
+ SIMPLE_IPA_PASS,
+ "prototype",
+ OPTGROUP_NONE,
+ TV_NONE,
+ (PROP_cfg | PROP_ssa),
+ 0,
+ 0,
+ 0,
+ 0,
+};
+
+class pass_ipa_prototype : public simple_ipa_opt_pass
+{
+public:
+ pass_ipa_prototype (gcc::context *ctx)
+ : simple_ipa_opt_pass(pass_data_ipa_prototype, ctx)
+ {}
+
+ virtual bool gate(function*) { return flag_ipa_prototype; }
+ virtual unsigned execute (function*) { return iphw_execute(); }
+};
+} // anon namespace
+
+simple_ipa_opt_pass*
+make_pass_ipa_prototype (gcc::context *ctx)
+{
+ return new pass_ipa_prototype (ctx);
+}
diff --git a/gcc/ipa-prototype.h b/gcc/ipa-prototype.h
new file mode 100644
index 00000000000..f77e0de3b32
--- /dev/null
+++ b/gcc/ipa-prototype.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include <map>
+
+struct Reason {
+ inline bool is_escaping() const {
+ return this->global_is_visible
+ || this->parameter_is_visible
+ || this->return_is_visible
+ || this->type_is_casted
+ || this->type_is_volatile
+ || this->type_is_in_union
+ || this->is_indirect;
+ }
+ bool global_is_visible : 1;
+ bool parameter_is_visible : 1;
+ bool return_is_visible : 1;
+ bool type_is_casted : 1;
+ bool type_is_volatile : 1;
+ bool type_is_in_union : 1;
+ bool is_indirect : 1;
+ Reason operator|(const Reason &);
+ Reason& operator|=(const Reason &);
+ void print() const;
+ Reason() : global_is_visible(0), parameter_is_visible(0), return_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0), is_indirect(0) {};
+};
+
+
+typedef std::map<const_tree, Reason> typemap;
+
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..f918974f719
--- /dev/null
+++ b/gcc/ipa-str-reorg-dead-field-eliminate.c
@@ -0,0 +1,2783 @@
+/* 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 "gimple-caster.hpp"
+
+#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;
+
+
+ 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;
+}
+
+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);
+ }
+ case GIMPLE_BINARY_RHS:
+ {
+ tree rhs2 = gimple_assign_rhs2 (stmt);
+ is_stmt_rewritten |= rewrite_expr (rhs2, type_map, 0);
+ }
+ 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;
+
+ 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();
+ 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 ();
+}
+
+*/
+
+#if USE_NEW_INTERFACE
+int
+str_reorg_dead_field_eliminate_qual (Info *info)
+{
+ GimpleCaster caster(info->sets);
+ caster.walk();
+ // sets here now holds the types that
+ // are casted...
+ // So, maybe we want to print them?
+ caster.print_reasons();
+ ptrset_t sets = caster.get_sets();
+ return 0;
+}
+int
+str_reorg_dead_field_eliminate_trans (Info *info)
+{
+ return 0;
+}
+#endif
+
+
diff --git a/gcc/ipa-str-reorg-field-reorder.c b/gcc/ipa-str-reorg-field-reorder.c
new file mode 100644
index 00000000000..67e2b147718
--- /dev/null
+++ b/gcc/ipa-str-reorg-field-reorder.c
@@ -0,0 +1,60 @@
+/* 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;
+}
+
+#if USE_NEW_INTERFACE
+int
+str_reorg_field_reorder_qual (Info *info)
+{
+ return 0;
+}
+int
+str_reorg_field_reorder_trans (Info *info)
+{
+ return 0;
+}
+#endif
diff --git a/gcc/ipa-str-reorg-instance-interleave.c b/gcc/ipa-str-reorg-instance-interleave.c
new file mode 100644
index 00000000000..1d0213f1427
--- /dev/null
+++ b/gcc/ipa-str-reorg-instance-interleave.c
@@ -0,0 +1,2536 @@
+/* Interprocedural structure reorganization
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <gary@amperecomputing.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 "tree-ssa.h"
+#include "tree-dfa.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"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "diagnostic-core.h"
+#include "ssa.h"
+#include "tree-ssanames.h"
+#include "cfghooks.h"
+#include "function.h"
+#include "cfgloop.h"
+#include "wide-int.h"
+
+static void wrangle_ssa_type( tree, Info_t*);
+//static bool print_internals (gimple *, void *);
+static void str_reorg_instance_interleave_qual_part ( Info *);
+static void str_reorg_instance_interleave_type_part ( Info *);
+static void header ( bool);
+static double cut_off_eq_single_pool( double);
+static double alignment_effect( unsigned HOST_WIDE_INT);
+static void create_new_types ( Info_t *);
+static void create_a_new_type ( Info_t *, tree);
+static unsigned int reorg_perf_qual ( Info *);
+static tree find_coresponding_field ( tree, tree);
+static void remove_default_def ( tree, struct function *);
+static void set_lhs_for ( gimple *, tree);
+static basic_block make_bb ( char *, basic_block);
+
+// These are local to this file by design
+#define REORG_SP_PTR_PREFIX "_reorg_SP_ptr_type_"
+#define REORG_SP_PREFIX "_reorg_base_type_"
+#define REORG_SP_BASE_PREFIX "_reorg_base_var_"
+
+// TBD Delete all this after sending a note on it
+// to the gcc mailing list.
+#define USE_BUILT_IN_FREE 1
+
+/*
+0000 ssa_verify error loc_3
+0001 tree_class_check err in interleave
+0010 ssa_verify error arr_46
+0011 ssa_verify error loc_3
+0100 ssa_verify error loc_3
+0101 ssa_verify error arr_46
+0110 ssa_verify error arr_46
+0111 ssa_verify error arr_46
+1000 ssa_verify error loc_3
+1001 bad failure: walk return bogus op
+1010 bad failure: walk return bogus op
+1011 bad failure: walk return bogus op
+1100 bad failure: walk return bogus op
+1101 bad failure: walk return bogus op
+1110 bad failure: walk return bogus op
+1111 bad failure: walk return bogus op
+*/
+
+// These are dummy values tha alway result the reorganization
+#define SINGLE_POOL_RAW_SKIP_IT 0.0
+#define SINGLE_POOL_RAW_DO_IT_ALWAYS 0.0
+#define SINGLE_POOL_ABS_SKIP_IT 0.0
+#define SINGLE_POOL_ABS_DO_IT_ALWAYS 0.0
+
+int
+str_reorg_instance_interleave_qual ( Info *info)
+{
+ // this is the qualification code for instance interleaving
+ //
+ str_reorg_instance_interleave_qual_part ( info);
+
+ // this modifiies the qualified types.
+ //
+ str_reorg_instance_interleave_type_part ( info);
+ return 0;
+}
+
+int
+str_reorg_instance_interleave_trans ( Info *info)
+{
+ if ( info->show_all_reorg_cands )
+ {
+ fprintf ( info->reorg_dump_file, "Start of str_reorg_instance_interleave_trans:\n");
+ print_program ( info->reorg_dump_file, PRINT_FORMAT, 4, info);
+ }
+
+ DEBUG ("INTERNALS PRINT\n");
+ DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info);
+
+ struct cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ // Ulgy GCC idiom with global pointer to current function.
+ push_cfun ( func);
+ if ( info->show_transforms )
+ {
+ fprintf( info->reorg_dump_file, "Function \"%s\":\n",
+ //IDENTIFIER_POINTER( DECL_NAME( func)));
+ //IDENTIFIER_POINTER( DECL_NAME( func->decl)));
+ lang_hooks.decl_printable_name ( node->decl, 2));
+ }
+
+ basic_block bb;
+ FOR_EACH_BB_FN ( bb, func)
+ {
+
+ if( info->show_transforms )
+ {
+ fprintf( info->reorg_dump_file, " Transforming BB%i:\n",
+ bb->index);
+ }
+
+ gimple_stmt_iterator outer_gsi;
+ gimple_stmt_iterator next_gsi;
+ for ( outer_gsi = gsi_start_bb ( bb); !gsi_end_p ( outer_gsi); outer_gsi = next_gsi )
+ {
+ next_gsi = outer_gsi;
+ gsi_next ( &next_gsi);
+ // Every statement that uses a reorg type needs to
+ // be examined. Some are harmless and are skipped
+ // whereas others are transformed. However, anything
+ // else is an error.
+ gimple *stmt = gsi_stmt ( outer_gsi);
+ ReorgType_t *ri = contains_a_reorgtype( stmt, info);
+ if ( ri == NULL )
+ {
+ //DEBUG_L("No Transfrom on: ");
+ //DEBUG_F( print_gimple_stmt, stderr, stmt, 4, TDF_SLIM);
+ }
+ else
+ {
+ //DEBUG_F( print_reorg_with_msg, stderr, ri, 0,
+ // "reorg from str_reorg_instance_interleave_trans");
+
+ enum ReorgTransformation trans =
+ reorg_recognize ( stmt, node, info);
+ // print out trans and stmt if dumping
+ if ( info->show_transforms )
+ {
+ print_gimple_stmt( info->reorg_dump_file, stmt, 0);
+ }
+
+ switch ( trans)
+ {
+ case ReorgT_StrAssign:
+ DEBUG_L("ReorgT_StrAssign\n");
+ // TBD
+ /*
+ tree lhs = gimple_assign_lhs( stmt);
+ tree rhs = gimple_assign_rhs( stmt);
+ ReorgOpTrans lope = recognize_op( lhs, info);
+ ReorgOpTrans rope = recognize_op( rhs, info);
+ for each field in ri {
+ // lhs: ReorgT_Array & rhs ReorgT_Struct, ReorgT_Deref, ReorgT_Array
+ // lhs: ReorgT_Struct & rhs ReorgT_Deref, ReorgT_Array
+ // lhs ReorgT_Deref & rhs ReorgT_Struct, ReorgT_Array, ReorgT_Deref
+ A is new ssa
+ // Gimple for loading this element
+ // Question? What if the element is large? Answer is it's OK.
+ switch( rope) {
+ // Not implemented in single pool
+ //case ReorgT_Array:
+ case ReorgT_Struct:
+ generate A <- rhs.field
+ break;
+ case ReorgT_Deref:
+ B,C is new SSA
+ // Note simplification with type_name( rhs)
+ generate B <- concat( REORG_SP_PREFIX, type_name( rhs))
+ and insert before stmt
+ generate C <- B->"f"
+ and insert before stmt
+ generate A <- C[rhs]
+ and insert before stmt
+ break
+ default:
+ internal_error(
+ "Reached operand default in RHS enum ReorgOpTrans");
+ }
+ // Gimple for storing this element
+ switch( lope)
+ // Not implemented in single pool
+ //case ReorgT_Array:
+ case ReorgT_Deref:
+ B,C is new SSA
+ // Note simplification with type_name( lhs)
+ generate B <- concat( REORG_SP_PREFIX, type_name( lhs))
+ and insert before stmt
+ generate C <- B->"f"
+ and insert before stmt
+ // lhs here is a simplification
+ generate A <- C[lhs]
+ and insert before stmt
+ break;
+ case ReorgT_Struct:
+ generate lhs.field <- A
+ break;
+ default:
+ internal_error(
+ "Reached operand default in LHS enum ReorgOpTrans");
+ }
+ }
+ */
+ break;
+ case ReorgT_ElemAssign:
+ {
+ //break;
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+
+ DEBUG_L("ReorgT_ElemAssign: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+ INDENT(2);
+ // Needed for helloworld
+ tree lhs = gimple_assign_lhs( stmt);
+ tree rhs = gimple_assign_rhs1( stmt);
+
+ bool ro_on_left = tree_contains_a_reorgtype_p ( lhs, info);
+
+ tree ro_side = ro_on_left ? lhs : rhs;
+ tree nonro_side = ro_on_left ? rhs : lhs;
+
+ switch ( recognize_op ( ro_side, info) ) // "a->f"
+ {
+ case ReorgOpT_Indirect:
+ {
+ tree orig_field = TREE_OPERAND( ro_side, 1);
+ tree field_type = TREE_TYPE( orig_field);
+ tree base = ri->instance_interleave.base;
+
+ tree base_field =
+ find_coresponding_field ( base, orig_field);
+
+ tree base_field_type = TREE_TYPE( base_field);
+
+ gcc_assert ( field_type);
+ tree field_val_temp =
+ make_temp_ssa_name( field_type, NULL, "field_val_temp");
+
+ tree inner_op = TREE_OPERAND( ro_side, 0);
+ inner_op = TREE_OPERAND( inner_op, 0);
+ //DEBUG_L("inner_op: ");
+ //DEBUG_F( print_generic_expr, stderr, inner_op, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ // For either case generate common code:
+
+ // field_array = _base.f
+ gcc_assert ( base_field_type);
+ tree field_arry_addr =
+ make_temp_ssa_name( base_field_type, NULL, "field_arry_addr");
+
+ tree rhs_faa = build3 ( COMPONENT_REF,
+ // ???
+ base_field_type,
+ //ptr_type_node, // This seems bogus
+ base,
+ base_field,
+ // This almost certainly is bogus
+ // If this "works" the the types
+ // of fields are messed up.
+ //orig_field,
+ NULL_TREE);
+
+ // Use this to access the array of element.
+ gimple *get_field_arry_addr =
+ gimple_build_assign( field_arry_addr, rhs_faa);
+ SSA_NAME_DEF_STMT ( field_arry_addr) = get_field_arry_addr;
+
+ // index = a
+ gcc_assert ( sizetype);
+ tree index =
+ make_temp_ssa_name( sizetype, NULL, "index");
+ gimple *get_index =
+ gimple_build_assign( index, CONVERT_EXPR, inner_op);
+ SSA_NAME_DEF_STMT ( index) = get_index;
+
+ gimple *temp_set;
+ gimple *final_set;
+
+ // offset = index * size_of_field
+ tree size_of_field = TYPE_SIZE_UNIT ( base_field_type);
+ gcc_assert ( sizetype);
+ tree offset = make_temp_ssa_name( sizetype, NULL, "offset");
+
+ gimple *get_offset = gimple_build_assign ( offset, MULT_EXPR, index, size_of_field);
+ SSA_NAME_DEF_STMT ( offset) = get_offset;
+
+ // field_addr = field_array + offset
+ gcc_assert ( base_field_type);
+ tree field_addr =
+ make_temp_ssa_name( base_field_type, NULL, "field_addr");
+
+ gimple *get_field_addr =
+ gimple_build_assign ( field_addr, POINTER_PLUS_EXPR, field_arry_addr, offset);
+ SSA_NAME_DEF_STMT ( field_addr) = get_field_addr;
+
+ if ( ro_on_left )
+ {
+ // With: a->f = rhs
+ // Generate:
+
+ // temp = rhs
+ temp_set = gimple_build_assign( field_val_temp, rhs);
+ SSA_NAME_DEF_STMT ( field_val_temp) = temp_set;
+
+ //// field_array[index] = temp
+ //tree elem_to_set =
+ // build4 ( ARRAY_REF, field_type, field_arry_addr, index,
+ // NULL_TREE, NULL_TREE);
+ //final_set =
+ // gimple_build_assign( elem_to_set, field_val_temp);
+
+ // *field_addr = temp
+ tree lhs_ref = build2 ( MEM_REF, field_type, field_addr,
+ build_int_cst (ptr_type_node, 0));
+
+ final_set =
+ gimple_build_assign( lhs_ref, field_val_temp);
+ }
+ else
+ {
+ // With: lhs = a->f
+ // Generate:
+
+ // Tried other idioms here (tricky)
+ tree rhs_ref = build2 ( MEM_REF, field_type, field_addr,
+ build_int_cst (ptr_type_node, 0));
+
+
+ // If these will actually print then things are likely sane
+ //DEBUG_L("rhs_ref: ");
+ //DEBUG_F(print_generic_expr, stderr, rhs_ref, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ tree op0 = TREE_OPERAND ( rhs_ref, 0);
+ tree op1 = TREE_OPERAND ( rhs_ref, 1);
+ tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
+ tree op1type_type = TREE_TYPE ( op1type);
+
+ temp_set =
+ gimple_build_assign( field_val_temp, rhs_ref);
+ SSA_NAME_DEF_STMT ( field_val_temp) = temp_set;
+
+ // lhs = temp
+ final_set = gimple_build_assign( lhs, field_val_temp);
+ SSA_NAME_DEF_STMT ( lhs) = final_set;
+ }
+
+ //DEBUG_L("get_field_arry_addr: ");
+ //DEBUG_F( print_gimple_stmt, stderr, get_field_arry_addr, 0);
+ //DEBUG("\n");
+
+ //DEBUG_L("get_index: ");
+ //DEBUG_F( print_gimple_stmt, stderr, get_index, 0);
+ //DEBUG("\n");
+
+ //DEBUG_L("get_offset: ");
+ //DEBUG_F( print_gimple_stmt, stderr, get_offset, 0);
+ //DEBUG("\n");
+
+ //DEBUG_L("get_field_addr: ");
+ //DEBUG_F( print_gimple_stmt, stderr, get_field_addr, 0);
+ //DEBUG("\n");
+
+ //DEBUG_L("temp_set: ");
+ //DEBUG_F( print_gimple_stmt, stderr, temp_set, 0);
+ //DEBUG("\n");
+
+ //DEBUG_L("final_set: ");
+ //DEBUG_F( print_gimple_stmt, stderr, final_set, 0);
+ //DEBUG("\n");
+
+ gsi_insert_before( &gsi, get_field_arry_addr, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, get_index, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, get_offset, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, get_field_addr, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, temp_set, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, final_set, GSI_SAME_STMT);
+
+
+ //delete stmt
+ gsi_remove ( &gsi, true);
+ } // end ReorgOpT_Indirect case
+ break;
+ case ReorgOpT_AryDir: // "x[i].f"
+ // Not implemented in single pool
+ internal_error ( "ReorgOpT_AryDir not possible");
+ default:
+ internal_error (
+ "Reached operand default for ReorgOpT_Indirect");
+
+ } // end recognize_op ( rhs, info) switch
+
+ INDENT(-2);
+ } // end ReorgT_ElemAssign case
+ break;
+ case ReorgT_If_Null:
+ case ReorgT_If_NotNull:
+ {
+ DEBUG_L("ReorgT_If_(Not)Null: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+ /*
+ gimple_cond_set_rhs( stmt,
+ TYPE_MAX_VALUE( pointer_sized_int_node));
+ */
+ // TYPE_MAX_VALUE ( TREE_TYPE ( fail_val)
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+ ReorgType_t *ri = contains_a_reorgtype( stmt, info);
+ //tree null_val =
+ // make_temp_ssa_name ( ri->pointer_rep, NULL, "if_cond_null");
+ gcond *cond_stmt = as_a <gcond *> (stmt);
+
+ //tree max = TYPE_MAX_VALUE ( TREE_TYPE ( ri->pointer_rep));
+ tree max = TYPE_MAX_VALUE ( ri->pointer_rep);
+
+ DEBUG_L("max: ");
+ DEBUG_F(print_generic_expr, stderr, max, (dump_flags_t)0);
+ DEBUG("\n");
+
+ gimple_cond_set_rhs( cond_stmt, max);
+
+ DEBUG_L("after: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+ }
+ break;
+ case ReorgT_IfPtrEQ:
+ case ReorgT_IfPtrNE:
+ case ReorgT_IfPtrLT:
+ case ReorgT_IfPtrGT:
+ case ReorgT_IfPtrLE:
+ case ReorgT_IfPtrGE:
+ DEBUG_L("ReorgT_IfPtr*\n");
+ // Not needed for single pool. TBD test this
+ break;
+ case ReorgT_PtrPlusInt: // "a = b + i"
+ {
+ DEBUG_L("ReorgT_PtrPlusInt: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+ // Needed for hellowotrld
+
+ // Does the type of stmt need to be adjusted? I assume so.
+ // The ReorgType contains the type of the pointer
+ // if so that should probably be used. Note, the variables
+ // should all be of the correct type (but maybe that's
+ // not reflected here. Punting and assigning the types to
+ // the type of pointer_sized_int_node is probably not correct
+ // even though that's the representation.
+
+ tree PPI_orig_lhs = gimple_assign_lhs ( stmt);
+
+ //tree offset_type = TREE_TYPE ( TYPE_SIZE_UNIT (ri->gcc_type)); // not needed
+ tree type = ri->pointer_rep;
+
+ tree str_siz =
+ build_int_cst ( type, int_cst_value ( TYPE_SIZE_UNIT (ri->gcc_type)));
+
+ tree rhs1 = gimple_assign_rhs1( stmt);
+ tree rhs2 = gimple_assign_rhs2( stmt);
+
+ gcc_assert ( type);
+ tree PPI_rhs1_cast = make_temp_ssa_name( type, NULL, "PPI_rhs1_cast");
+ gimple *gPPI_rhs1_cast = gimple_build_assign ( PPI_rhs1_cast, CONVERT_EXPR, rhs1);
+ SSA_NAME_DEF_STMT ( PPI_rhs1_cast) = gPPI_rhs1_cast;
+
+ tree PPI_rhs2_cast = make_temp_ssa_name( type, NULL, "PPI_rhs2_cast");
+ gimple *gPPI_rhs2_cast = gimple_build_assign ( PPI_rhs2_cast, CONVERT_EXPR, rhs2);
+ SSA_NAME_DEF_STMT ( PPI_rhs2_cast) = gPPI_rhs2_cast;
+
+ tree PPI_adj = make_temp_ssa_name( type, NULL, "PtrPlusInt_Adj");
+ gimple *gPPI_adj =
+ gimple_build_assign ( PPI_adj, TRUNC_DIV_EXPR, PPI_rhs2_cast, str_siz);
+ SSA_NAME_DEF_STMT ( PPI_adj) = gPPI_adj;
+
+ tree ptrplusint = make_temp_ssa_name( type, NULL, "PtrPlusInt");
+ gimple *gPPI =
+ gimple_build_assign ( ptrplusint, PLUS_EXPR, PPI_rhs1_cast, PPI_adj);
+ SSA_NAME_DEF_STMT ( ptrplusint) = gPPI;
+
+ gimple *gPPI_cast =
+ gimple_build_assign ( PPI_orig_lhs, CONVERT_EXPR, ptrplusint);
+ SSA_NAME_DEF_STMT ( PPI_orig_lhs) = gPPI_cast;
+
+ //gimple_set_op( stmt, 2, tmp);
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+ gsi_insert_before( &gsi, gPPI_rhs1_cast, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPPI_rhs2_cast, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPPI_adj, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPPI, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPPI_cast, GSI_SAME_STMT);
+
+ gsi_remove ( &gsi, true);
+
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPPI_rhs2_cast, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPPI_adj, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPPI, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPPI_cast, 0);
+ }
+ break;
+ case ReorgT_Ptr2Zero: // "a = 0"
+ DEBUG_L("ReorgT_Ptr2Zero\n");
+ /*
+ // TBD
+ // Note, this is way too simple... just saying.
+ gimple_set_op( stmt, 1,
+ TYPE_MIN_VALUE( pointer_sized_int_node));
+ */
+ break;
+ case ReorgT_PtrDiff: // "i = a - b"
+ {
+ DEBUG_L("ReorgT_PtrDiff\n");
+ // We basically need to modify the gimple code
+ // but that also means adding converts.
+ tree type = ri->pointer_rep;
+ tree str_siz =
+ build_int_cst ( type, int_cst_value ( TYPE_SIZE_UNIT (ri->gcc_type)));
+ tree rhs1 = gimple_assign_rhs1( stmt);
+ tree rhs2 = gimple_assign_rhs2( stmt);
+ tree PD_orig_lhs = gimple_assign_lhs ( stmt);
+
+ tree PD_rhs1_cast = make_temp_ssa_name( type, NULL, "PD_rhs1_cast");
+ gimple *gPD_rhs1_cast = gimple_build_assign ( PD_rhs1_cast, CONVERT_EXPR, rhs1);
+ SSA_NAME_DEF_STMT ( PD_rhs1_cast) = gPD_rhs1_cast;
+
+ tree PD_rhs2_cast = make_temp_ssa_name( type, NULL, "PD_rhs2_cast");
+ gimple *gPD_rhs2_cast = gimple_build_assign ( PD_rhs2_cast, CONVERT_EXPR, rhs2);
+ SSA_NAME_DEF_STMT ( PD_rhs2_cast) = gPD_rhs2_cast;
+
+ tree ptrdiff = make_temp_ssa_name( type, NULL, "PtrDiff");
+ gimple *gPD =
+ gimple_build_assign ( ptrdiff, MINUS_EXPR, PD_rhs1_cast, PD_rhs2_cast);
+ SSA_NAME_DEF_STMT ( ptrdiff) = gPD;
+
+ tree PD_adjust = make_temp_ssa_name( type, NULL, "PD_adjust");
+ gimple *gPD_adjust =
+ gimple_build_assign ( PD_adjust, MULT_EXPR, ptrdiff, str_siz);
+
+ gimple *gPD_cast =
+ gimple_build_assign ( PD_orig_lhs, CONVERT_EXPR, PD_adjust);
+ SSA_NAME_DEF_STMT ( PD_orig_lhs) = gPD_cast;
+
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+ gsi_insert_before( &gsi, gPD_rhs1_cast, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPD_rhs2_cast, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPD, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPD_adjust, GSI_SAME_STMT);
+ gsi_insert_before( &gsi, gPD_cast, GSI_SAME_STMT);
+
+ gsi_remove ( &gsi, true);
+
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPD_rhs1_cast, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPD_rhs2_cast, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPD, 0);
+ DEBUG_L("");
+ DEBUG_F( print_gimple_stmt, stderr, gPD_cast, 0);
+ }
+ break;
+ case ReorgT_Adr2Ptr: // "a = &x[i]"
+ DEBUG_L("ReorgT_Adr2Ptr\n");
+ // TBD
+ /*
+ tree *add_stmt =
+ gimple_build_assign(
+ gimple_assign_lhs( stmt);,
+ PLUS_EXPR,
+ gimple_assign_rhs1( stmt),
+ gimple_assign_rhs2( stmt),
+ NULL_TREE, NULL_TREE);
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+ gsi_insert_before( gsi, add_stmt, GSI_SAME_STMT);
+ // delete stmt
+ gsi_remove( gsi, true);
+ */
+ break;
+ case ReorgT_PtrNull: // "x = a == 0"
+ case ReorgT_PtrNotNull: // "x = a != 0"
+ DEBUG_L("ReorgT_Ptr(Not)Null\n");\
+ // TBD
+ /*
+ gimple_set_op( stmt, 2,
+ TYPE_MIN_VALUE( pointer_sized_int_node));
+ */
+ break;
+ case ReorgT_PtrEQ: // "i = a == b"
+ case ReorgT_PtrNE: // "i = a != b"
+ case ReorgT_PtrLT: // "i = a < b"
+ case ReorgT_PtrLE: // "i = a <= b"
+ case ReorgT_PtrGT: // "i = a > b"
+ case ReorgT_PtrGE: // "i = a >= b"
+ DEBUG_L("ReorgT_Ptr*\n");
+ // Not needed for single pool. TBD test this
+ break;
+ case ReorgT_Malloc:
+ {
+ DEBUG_L("Transform ReorgT_Malloc\n");
+ INDENT(2);
+
+ // We need to use the user malloc function
+ // declaration rather than the builtin!!!
+ tree fndecl_malloc = gimple_call_fndecl ( stmt);
+
+ // We need to synthesize the free function
+ //
+ tree param_type_list = NULL;
+ tree void_pointer_type_node = build_pointer_type ( void_type_node);
+ param_type_list =
+ tree_cons ( NULL_TREE, void_pointer_type_node, param_type_list);
+ //DEBUG_L("param_type_list: ");
+ //DEBUG_F(print_generic_expr, stderr, param_type_list, (dump_flags_t)0);
+ //DEBUG("\n");
+ #if !USE_BUILT_IN_FREE
+ tree free_return_type = void_type_node;
+ #endif
+ //DEBUG_L("free_return_type: ");
+ //DEBUG_F(print_generic_expr, stderr, free_return_type, (dump_flags_t)0);
+ //DEBUG("\n")
+ #if USE_BUILT_IN_FREE
+ tree fndecl_free = builtin_decl_implicit ( BUILT_IN_FREE);
+ #else
+ tree fntype = build_function_type ( free_return_type, param_type_list);
+ tree fnname = get_identifier ( "free");
+ tree fndecl_free = build_decl ( input_location, FUNCTION_DECL, fnname, fntype);
+ #endif
+ // Note, add it to the call graph at each call site
+
+ // Note, unlike other simpler transformations,
+ // this must build new basic blocks to add new
+ // gimple to and use a phi for the final result.
+ // See appendix on malloc transformation for
+ // each comment starting with "FROM."
+ ReorgType_t *ri = contains_a_reorgtype( stmt, info);
+ // FROM len = val/size
+ tree arg = gimple_call_arg( stmt, 0);
+ // TBD: len is new SSA
+ tree val = gimple_call_lhs( stmt);
+ //DEBUG_L("val is: ");
+ //DEBUG_F( print_generic_expr, stderr, val, (dump_flags_t)-1);
+ //DEBUG(", tree code type: %s\n", code_str(TREE_CODE(TREE_TYPE(val))));
+ //gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF);
+ gcc_assert( TREE_CODE( TREE_TYPE(val)) == POINTER_TYPE);
+ tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val)));
+ // FROM len = val/size (insert before stmt) <== maybe arg/size
+ //tree len = make_temp_ssa_name( sizetype, NULL, "fail_val");
+ // The above segfaulted ??? note, it's not an idiom seen in gcc
+ tree int_ptrsize_type = signed_type_for ( ptr_type_node);
+ //DEBUG_L("int_ptrsize_type = %p\n", TREE_TYPE ( size));
+ gcc_assert ( TREE_TYPE ( size));
+ tree len = make_temp_ssa_name ( TREE_TYPE ( size), NULL, "malloc_len");
+ gimple_stmt_iterator gsi = gsi_for_stmt( stmt);
+ //gimple *glen =
+ // gimple_build_assign ( len, TRUNC_DIV_EXPR, val, size);
+
+ // Cast arg to compatible type
+ gcc_assert( TREE_TYPE ( size));
+ TREE_TYPE (arg) = TREE_TYPE ( size);
+ tree cast_arg =
+ make_temp_ssa_name( TREE_TYPE ( size), NULL, "cast_arg");
+ gimple *gcast_arg = gimple_build_assign ( cast_arg, CONVERT_EXPR, arg);
+ SSA_NAME_DEF_STMT ( cast_arg) = gcast_arg;
+ gsi_insert_before( &gsi, gcast_arg, GSI_SAME_STMT);
+
+ gimple *glen =
+ gimple_build_assign ( len, TRUNC_DIV_EXPR, cast_arg, size);
+ SSA_NAME_DEF_STMT ( len) = glen;
+
+ gsi_insert_before( &gsi, glen, GSI_SAME_STMT);
+ // Note in other places in this doc this would
+ // be "insert glen before stmt" instead of this but
+ // here we need to create new basic blocks.
+ edge new_edge = split_block ( bb, stmt);
+ // FROM before_bb = edge->src // same as this bb
+ basic_block before_bb = new_edge->src; //
+ basic_block after_bb = new_edge->dest;
+ remove_edge ( new_edge);
+ basic_block prev_bb = before_bb;
+
+ // FROM failure_bb = create_empty_block(prev_bb)
+ basic_block failure_bb = make_bb ( "failure_bb", prev_bb);
+ // I need to set the count to zero and there doesn't
+ // seem to be direct way of doing this...
+ failure_bb->count = prev_bb->count - prev_bb->count;
+
+ // set edge probability and flags
+ edge fail_to_after_e = make_edge ( failure_bb,
+ after_bb, EDGE_FALLTHRU);
+ fail_to_after_e->probability = profile_probability::very_unlikely ();
+ fail_to_after_e->count () = failure_bb->count;
+
+ // Note, this should remove this call from the call graph
+ cgraph_update_edges_for_call_stmt ( stmt, gimple_call_fndecl ( stmt), NULL);
+ // Now it's safe to remove it!
+ gsi_remove ( &gsi, true);
+
+ tree field;
+ tree reorg_type = ri->gcc_type; // is this useful here?
+ tree reorg_pointer_type = ri->pointer_rep;
+ //tree base = ri->reorg_ver_type; //nopers
+ tree base = ri->instance_interleave.base;
+
+ // ??? We are faking the malloc so the following seemed dubious
+ //tree malloc_return_type = TREE_TYPE ( arg);
+ //tree fail_val =
+ // make_temp_ssa_name ( malloc_return_type, NULL, "malloc_fail_val");
+ gcc_assert ( reorg_pointer_type);
+ tree fail_val =
+ make_temp_ssa_name ( reorg_pointer_type, NULL, "malloc_fail_val");
+
+ // loop setup trickery for gimple idioms
+ //
+ // FROM prev_order = failure_bb
+ basic_block prev_order = failure_bb;
+ // FROM prev_bb = before_bb
+ prev_bb = before_bb;
+ int edge_flags = EDGE_FALLTHRU;
+
+ // Generate all the real allocation code
+ //
+ // Note, I think there are ramifications of built in malloc (and free)
+ // so I'm going try and use the malloc in the call transformed!!!
+ // Actually, I ended up using the built in free and it was
+ // the way to go.
+ //
+
+ //tree fndecl_malloc = builtin_decl_explicit( BUILT_IN_MALLOC);
+
+ // This, after the following loop, will hold the start of the
+ // field related code.
+ tree new_ok_field_L;
+
+ // FROM (for fields) {
+ bool first = true;
+ for( field = TYPE_FIELDS( reorg_type);
+ field;
+ field = DECL_CHAIN( field))
+ {
+ basic_block new_bb = make_bb ( "new_bb", prev_order);
+ new_bb->count = prev_order->count;
+ // Nope! Don't do this.
+ //set_immediate_dominator ( CDI_DOMINATORS, new_bb, prev_bb);
+ //if ( first )
+ // {
+ // first = false;
+ // set_immediate_dominator ( CDI_DOMINATORS, failure_bb, new_bb);
+ // set_immediate_dominator ( CDI_DOMINATORS, after_bb, new_bb);
+ // }
+
+ tree base_field =
+ find_coresponding_field ( base, field);
+
+ //DEBUG_L("base_field: %p\n", base_field);
+ //DEBUG_A(" : ");
+ //DEBUG_F(print_generic_expr, stderr, base_field, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ tree base_field_type = TREE_TYPE( base_field);
+ //DEBUG_L("base_field_type: %p\n", base_field_type);
+ //DEBUG_A(" : ");
+ //DEBUG_F(print_generic_expr, stderr, base_field_type, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ gimple_stmt_iterator gsi = gsi_start_bb ( new_bb);
+ // Note, switching the order of edge creation and
+ // setting dominator seems to make no difference
+
+ // set edge probability and flags
+
+ // edge_flags depends on whether or not the predecessor
+ // block was created in this loop.
+ edge ok_edge = make_edge ( prev_bb, new_bb, edge_flags);
+ edge_flags = EDGE_TRUE_VALUE;
+
+ ok_edge->probability = profile_probability::very_likely ();
+ ok_edge->count () = prev_bb->count;
+ add_bb_to_loop ( new_bb, before_bb->loop_father);
+
+ // Don't mess with the dominators.
+ //set_immediate_dominator ( CDI_DOMINATORS, new_bb, prev_bb);
+
+ // create edge and set edge probability and flags
+ edge fail_edge = make_edge ( new_bb, failure_bb, EDGE_FALSE_VALUE);
+ fail_edge->probability = profile_probability::very_unlikely ();
+ fail_edge->count () = new_bb->count - new_bb->count;
+
+ //tree lhs_ass =
+ // build3( COMPONENT_REF, ptr_type_node, base, field, NULL_TREE);
+ tree lhs_ass = build3( COMPONENT_REF,
+ base_field_type,
+ base,
+ base_field, NULL_TREE);
+
+ //DEBUG_L("base: %p\n", base);
+ //DEBUG_A(" base: ");
+ //DEBUG_F(print_generic_expr, stderr, base, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ //DEBUG_L("field: %p\n", field);
+ //DEBUG_A(" : ");
+ //DEBUG_F(print_generic_expr, stderr, field, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ tree field_type = TREE_TYPE( field);
+ //DEBUG_L("field_type: %p\n", field_type);
+ //DEBUG_A(" : ");
+ //DEBUG_F(print_generic_expr, stderr, field_type, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ //DEBUG_L("lhs_ass: %p\n", lhs_ass);
+ //DEBUG_A(" lhs_ass: ");
+ //DEBUG_F(print_generic_expr, stderr, lhs_ass, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ tree lhs_ass_type = TREE_TYPE ( lhs_ass);
+ //DEBUG_L("lhs_ass_type: %p\n", lhs_ass_type);
+ //DEBUG_A(" lhs_ass_type: ");
+ //DEBUG_F(print_generic_expr, stderr, lhs_ass_type, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ gcc_assert ( sizetype);
+ tree mem_size =
+ make_temp_ssa_name( sizetype, NULL, "malloc_mem_size");
+
+ // We need field_size to be of the correct type so
+ // we type cast.
+ gcc_assert ( TREE_TYPE ( mem_size));
+ tree field_size =
+ make_temp_ssa_name( TREE_TYPE ( mem_size), NULL, "field_size");
+
+ // Move gprev_ok_field here
+
+ // Move gfield_size here
+ gimple *gfield_size =
+ gimple_build_assign ( field_size,
+ CONVERT_EXPR,
+ TYPE_SIZE ( TREE_TYPE ( field)));
+ SSA_NAME_DEF_STMT ( field_size) = gfield_size;
+
+ // Move gsize here
+ gimple *gsize =
+ gimple_build_assign ( mem_size,
+ MULT_EXPR,
+ field_size,
+ len);
+ SSA_NAME_DEF_STMT ( mem_size) = gsize;
+
+ gcc_assert ( ptr_type_node);
+ tree res =
+ make_temp_ssa_name ( ptr_type_node, NULL, "res");
+
+ gcc_assert ( TREE_TYPE ( base_field));
+ tree cast_res =
+ make_temp_ssa_name ( TREE_TYPE ( base_field), NULL, "cast_res");
+
+ tree res_type = TREE_TYPE( res);
+ //DEBUG_L("res_type: %p\n", res_type);
+ //DEBUG_A(" : ");
+ //DEBUG_F(print_generic_expr, stderr, res_type, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ // Move malloc_call here
+ gcall *malloc_call = gimple_build_call( fndecl_malloc, 1, mem_size);
+ gimple_call_set_lhs( malloc_call, res);
+ SSA_NAME_DEF_STMT ( res) = malloc_call;
+
+ cgraph_node::get ( cfun->decl)->
+ create_edge ( cgraph_node::get_create ( fndecl_malloc),
+ malloc_call,
+ // Nah... lets do this a bit differently
+ //gimple_bb ( free_call)->count
+ new_bb->count
+ );
+
+ gimple *gcast_res =
+ gimple_build_assign ( cast_res, CONVERT_EXPR, res);
+ SSA_NAME_DEF_STMT ( cast_res) = gcast_res;
+
+ // Move gset_field here
+ gimple *gset_field = gimple_build_assign ( lhs_ass, cast_res);
+
+ // Move gcond here
+ gimple *gcond =
+ gimple_build_cond ( NE_EXPR, res, null_pointer_node,
+ NULL, NULL
+ );
+
+ // In execution order
+ gsi_insert_after ( &gsi, gfield_size, GSI_NEW_STMT);
+ gsi_insert_after ( &gsi, gsize, GSI_CONTINUE_LINKING);
+ gsi_insert_after ( &gsi, malloc_call, GSI_CONTINUE_LINKING);
+ gsi_insert_after ( &gsi, gcast_res, GSI_CONTINUE_LINKING);
+ gsi_insert_after ( &gsi, gset_field, GSI_CONTINUE_LINKING);
+ gsi_insert_after ( &gsi, gcond, GSI_CONTINUE_LINKING);
+
+ prev_bb = new_bb;
+ prev_order = new_bb;
+ }
+
+ // Loop cleaup fo failure code bb here. There is loop state
+ // overhead having nothing to do with the transformation
+ // that never the less must be updated.
+ add_bb_to_loop ( failure_bb, before_bb->loop_father);
+
+ // create basic block for success
+ //
+ // FROM success_bb = create_empty_block(prev_bb_order);
+ basic_block success_bb = make_bb ( "succ_bb", prev_bb);
+ success_bb->count = prev_bb->count;
+
+ // NOTE, it seems I shouldn't be attempting
+ // to diddle the dominator information on the fly.
+ // set_immediate_dominator ( CDI_DOMINATORS, success_bb, prev_bb);
+
+ edge success_e = make_edge ( prev_bb, success_bb, EDGE_TRUE_VALUE );
+ edge succ_to_after_e = make_edge ( success_bb, after_bb, EDGE_FALLTHRU);
+ success_e->probability = profile_probability::very_likely ();
+ succ_to_after_e->probability = profile_probability::always ();
+ success_e->count () = prev_bb->count;
+ succ_to_after_e->count () = prev_bb->count;
+ add_bb_to_loop ( success_bb, before_bb->loop_father);
+
+ // code in success_bb
+ //
+ gcc_assert ( reorg_pointer_type);
+ tree success_val =
+ make_temp_ssa_name( reorg_pointer_type, NULL, "malloc_success_val");
+
+ gsi = gsi_start_bb ( success_bb); // used to be failure_bb
+
+ gimple *set_succ =
+ gimple_build_assign ( success_val,
+ build_int_cst ( reorg_pointer_type, 0));
+ SSA_NAME_DEF_STMT ( success_val) = set_succ;
+
+ gsi_insert_after( &gsi, set_succ, GSI_NEW_STMT);
+
+ // FROM gsi_insert_after( &gsi, new_ok_field )
+ //gimple *gnew_ok_field = gimple_build_label ( new_ok_field_L);
+ //gsi_insert_after ( &gsi, gnew_ok_field, GSI_SAME_STMT);
+
+ // add code to after_bb
+ //
+ // FROM gsi = gsi_start_bb( after_bb)
+ // Reuse gsi
+ //gimple_stmt_iterator gsi = gsi_start_bb( after_bb);
+ gsi = gsi_start_bb( after_bb);
+
+ // FROM gsi_insert_after( &gsi, "lhs = "phi(success_val, fail_val)
+
+ // Note, BBs have a sequence of phis which create_phi_node takes care of
+ // adding this phi too.
+ gcc_assert ( TREE_TYPE ( success_val));
+ tree m_phi_val =
+ make_temp_ssa_name ( TREE_TYPE ( success_val), NULL, "m_phi_val");
+ gphi *der_phi = create_phi_node( m_phi_val, after_bb);
+ add_phi_arg( der_phi, success_val, succ_to_after_e, UNKNOWN_LOCATION);
+ add_phi_arg( der_phi, fail_val, fail_to_after_e, UNKNOWN_LOCATION);
+
+ gimple *gm_cast_phi_val =
+ gimple_build_assign ( val, CONVERT_EXPR, m_phi_val);
+ SSA_NAME_DEF_STMT ( val) = gm_cast_phi_val;
+
+ //gsi_insert_after( &gsi, gm_cast_phi_val, GSI_NEW_STMT);
+ // TBD What does GSI_NEW_STMT do if the block isn't emply?
+ gsi_insert_before( &gsi, gm_cast_phi_val, GSI_NEW_STMT);
+
+ //// FROM gsi_insert_after( &gsi, after_label)
+ //gimple *gafter_label = gimple_build_label( after_label_L);
+ //gsi_insert_after( &gsi, gafter_label, GSI_SAME_STMT);
+
+
+ // failure_bb code here
+
+ //
+ // FROM fail_val is new SSA
+ //tree return_type = TREE_TYPE ( arg);
+ //tree fail_val =
+ // make_temp_ssa_name ( return_type, NULL, "fail_val");
+ // FROM gsi = gsi_start_bb ( failure_bb)
+ gsi = gsi_start_bb ( failure_bb);
+
+ // FROM gsi_insert_after( &gsi, "fail_val = minint")
+ gimple *gretnull =
+ gimple_build_assign ( fail_val, CONVERT_EXPR,
+ TYPE_MAX_VALUE ( TREE_TYPE ( fail_val)));
+ SSA_NAME_DEF_STMT ( fail_val) = gretnull;
+
+ gsi_insert_after( &gsi, gretnull, GSI_NEW_STMT);
+
+ for( field = TYPE_FIELDS( reorg_type);
+ field;
+ field = DECL_CHAIN( field)) {
+
+ tree base_field =
+ find_coresponding_field ( base, field);
+ tree base_field_type = TREE_TYPE( base_field);
+
+ gcc_assert ( base_field_type);
+ tree m_to_free =
+ make_temp_ssa_name( base_field_type, NULL, "malloc_to_free");
+
+ tree rhs_ass = build3( COMPONENT_REF,
+ base_field_type,
+ base,
+ base_field, NULL_TREE);
+
+ gimple *gaddr2free = gimple_build_assign( m_to_free, rhs_ass);
+ SSA_NAME_DEF_STMT ( m_to_free) = gaddr2free;
+
+ gsi_insert_after( &gsi, gaddr2free, GSI_CONTINUE_LINKING);
+
+ gcc_assert ( ptr_type_node);
+ tree m_cast2free =
+ make_temp_ssa_name( ptr_type_node, NULL, "m_cast2free");
+
+ gimple *gm_cast2free =
+ gimple_build_assign( m_cast2free, CONVERT_EXPR, m_to_free);
+ SSA_NAME_DEF_STMT ( m_cast2free) = gm_cast2free;
+
+ gsi_insert_after( &gsi, gm_cast2free, GSI_CONTINUE_LINKING);
+
+ gcall *free_call = gimple_build_call( fndecl_free, 1, m_cast2free);
+ gsi_insert_after( &gsi, free_call, GSI_CONTINUE_LINKING);
+
+ cgraph_node::get ( cfun->decl)->
+ create_edge ( cgraph_node::get_create ( fndecl_free),
+ free_call,
+ failure_bb->count
+ );
+
+ tree lhs_ass = build3( COMPONENT_REF,
+ base_field_type,
+ base,
+ base_field, NULL_TREE);
+
+ gimple *gzero = gimple_build_assign( lhs_ass, null_pointer_node);
+ gsi_insert_after( &gsi, gzero, GSI_CONTINUE_LINKING);
+ }
+
+ //// FROM gsi_insert_after( &gsi, bad_field )
+
+ //DEBUG_L("End of malloc:\n");
+ //DEBUG_F( print_program, PRINT_FORMAT, stderr, 4);
+ }
+ INDENT(-2);
+ break;
+ case ReorgT_Calloc:
+ // TBD
+ DEBUG_L("ReorgT_Calloc\n");
+ /*
+ // This used to be almost a clone of the old version of
+ // the malloc code above and needs to transformed just like
+ // what was done above to malloc.
+ tree arg = gimple_call_arg( stmt, 0);
+ len is new SSA
+ tree val = gimple_call_lhs( stmt);
+ gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF);
+ tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val)));
+ gimple *glen =
+ gimple_build_assign(
+ len,
+ TRUNC_DIV_EXPR,
+ val,
+ size,
+ NULL_TREE, NULL_TREE);
+ //insert glen before stmt
+ gimple_stmt_iterator stmt_gsi = gsi_for_stmt ( stmt);
+ gsi_link_before( stmt_gsi, glen, GSI_SAME_STMT);
+ tree lfial = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *gfail = gimple_build_label( lfail);
+ tree lnotfial = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *gnotfail = gimple_build_label( lnotfail);
+ tree base = ri->reorg_ver_type;
+ for (each element of base) // TBD <==
+ {
+ // call malloc
+ tree lok = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *glok = gimple_build_label( lok);
+ tree *fndecl = builtin_decl_explicit( BUILT_IN_MALLOC);
+ mem_size is new SSA
+ gimple *gsize =
+ gimple_build_assign(
+ mem_size,
+ MULT_EXPR,
+ TYPE_SIZE(element),
+ len,
+ NULL_TREE, NULL_TREE);
+ insert gsize before stmt
+ gcall *call = gimple_build_call( fndecl, 1, mem_size);
+ mres is new SSA
+ gimple_call_set_lhs( call, mres)
+ insert call before stmt
+ // Set element to return value of malloc.
+ // Note, the devil is in the details here.
+ gen concat( REORG_SP_PREFIX,
+ type_name( lhs) ).element <- mres
+ and insert before stmt
+ // gen test of return
+ gimple *gcond =
+ gimple_build_cond( EQ_EXPR, mres,
+ null_pointer_node, lfail, lok);
+ insert gcond before stmt
+ insert glok before stmt
+ // call memset
+ fndecl = builtin_decl_explicit( BUILT_IN_MEMSET);
+ call =
+ gimple_build_call( fndecl, 3, mres, int_node_zero, mem_size);
+ insert call before stmt
+ }
+
+ // fake return value of zero
+ gimple *gretzero =
+ gimple_build_assign( lhs,
+ build_int_cst(
+ TYPE_MIN_VALUE( TREE_TYPE(lhs)), 0));
+ insert gretzero before stmt
+ gimple *ggoto = gimple_build_goto( lnotfail);
+ insert ggoto before stmt
+ insert glab1 before stmt
+ for each element of base {
+ tree fndecl = builtin_decl_explicit( BUILT_IN_FREE);
+ gcall *call = gimple_build_call( fndecl, 1, element);
+ insert call before stmt
+ set element to null
+ }
+ // fake return value of null
+ gimple *gretnull =
+ gimple_build_assign( lhs,
+ build_int_cst(
+ TYPE_MIN_VALUE( TREE_TYPE(lhs))));
+ insert gretnull before stmt
+ insert gnotfail before stmt
+ delete stmt
+ */
+ break;
+ case ReorgT_Realloc:
+ // TBD
+ DEBUG_L("ReorgT_Realloc\n");
+ /*
+ // This used to be closely related to the old version of
+ // the malloc code above and needs to transformed just like
+ // what was done above to malloc.
+ tree arg = gimple_call_arg( stmt, 0);
+ len is new SSA
+ tree val = gimple_call_lhs( stmt);
+ gcc_assert( TREE_CODE( TREE_TYPE(val)) == INDIRECT_REF);
+ tree size = TYPE_SIZE_UNIT( TREE_TYPE( TREE_TYPE( val)));
+ gimple *glen =
+ gimple_build_assign(
+ len,
+ TRUNC_DIV_EXPR,
+ val,
+ size,
+ NULL_TREE, NULL_TREE);
+ insert glen before stmt
+ tree lfial = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *gfail = gimple_build_label( lfail);
+ tree lnotfial = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *gnotfail = gimple_build_label( lnotfail);
+ for each field of base {
+ // call malloc
+ tree lok = create_artificial_label( UNKNOWN_LOCATION);
+ gimple *gok = gimple_build_label( lok);
+ tree fndecl = builtin_decl_explicit( BUILT_IN_REALLOC);
+ // but first compute how much to malloc
+ mem_size, var, ptr are new SSA
+ gimple *gsize =
+ gimple_build_assign(
+ mem_size,
+ MULT_EXPR,
+ TYPE_SIZE(field),
+ len,
+ NULL_TREE, NULL_TREE);
+ insert gsize before stmt
+ generate ptr = base.field & insert before stmt
+ gcall *call
+ = gimple_build_call( fndecl, 3, ptr,
+ len, TYPE_SIZE( field));
+ gimple_call_set_lhs( call, var);
+ insert call before stmt
+ // gen test of return
+ gimple *gcond =
+ gimple_build_cond( EQ_EXPR, var,
+ null_pointer_node, lfail, lok);
+ insert gcond before stmt
+ insert gok before stmt
+ generate base.field = var & insert before stmt
+ }
+ // fake return value of starting address (an index of zero)
+ gimple *gretzero =
+ gimple_build_assign( lhs, //
+ build_int_cst(
+ TYPE_MIN_VALUE( TREE_TYPE(lhs)), 0));
+ insert gretzero before stmt
+ gimple *ggoto = gimple_build_goto( lnotfail);
+ insert ggoto before stmt
+ insert glab1 before stmt
+ for each element of base {
+ tree fndecl = builtin_decl_explicit( BUILT_IN_FREE);
+ gcall *call = gimple_build_call( fndecl, 1, element);
+ insert call before stmt
+ set element to null
+ }
+ // fake return value of null (minimum value under this scheme)
+ gimple *gretnull =
+ gimple_build_assign( lhs,
+ build_int_cst(
+ TYPE_MIN_VALUE( TREE_TYPE(lhs))));
+ insert gretnull before stmt
+ insert gnotfail before stmt
+ delete stmt
+ */
+ break;
+ case ReorgT_Free:
+ // TBD
+ DEBUG_L("ReorgT_Free\n");
+ // We won't free the base because it a global.
+ /*
+ for each element of base {
+ tree fndecl = builtin_decl_explicit( BUILT_IN_FREE);
+ gcall *call = gimple_build_call( fndecl, 1, element);
+ insert call before stmt
+ }
+ delete stmt
+ */
+ break;
+ case ReorgT_UserFunc:
+ {
+ DEBUG_L("ReorgT_UserFunc: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+ // Needed for helloworld.
+ // The type must be adjusted, but not here.
+
+ // Note, what is done is there is a case (for
+ // GIMPLE_CALL) in the mini-pass to adjust a
+ // call's "dangling" SSA temp. I mean dangling
+ // in the sense that there are pointers to a
+ // reorg type on the left hand side of
+ // statements and they haven't been modified to
+ // use the correct reorg pointer
+ // represenatation, even though the right hand
+ // side has been.
+ }
+ break;
+ case ReorgT_Convert:
+ // Ignore type casting because another
+ // mini-pass sweeps up any ugly dangling types.
+ // TBD test this
+ DEBUG_L("ReorgT_Convert\n");
+ break;
+ case ReorgT_Return:
+ // TBD This case probably is unnecessary.
+ DEBUG_L("ReorgT_Return\n");
+ break;
+ default:
+ internal_error( "Invalid transformation");
+ }
+ }
+ }
+ // Iterate over the PHIs and for any PHI that is a reorgtype,
+ // transform any constant zero into it's new repersentation.
+ // OR MAYBE... use FOR_EACH_PHI_ARG for the iterator...
+
+ DEBUG_L("Phis with constant operands:\n");
+ INDENT(4);
+ gphi_iterator pi;
+ for ( pi = gsi_start_phis (bb); !gsi_end_p (pi); gsi_next (&pi))
+ {
+ //gimple_stmt_iterator gsi = as_a <gimple_stmt_iterator> pi;
+ gphi *phi = pi.phi ();
+ gimple *stmt = static_cast <gimple *> (phi);
+
+ DEBUG_A("phi: ");
+ DEBUG_F( print_gimple_stmt, stderr, stmt, 0);
+
+ ReorgType_t *ri = contains_a_reorgtype( stmt, info);
+ if ( ri != NULL && number_of_levels ( TREE_TYPE ( PHI_RESULT ( stmt))) == 1 )
+ {
+ for (int i = 0; i < gimple_phi_num_args (phi); i++)
+ {
+ tree *arg = gimple_phi_arg_def_ptr (phi, i);
+ DEBUG_A("arg[%d] = ",i);
+ DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0);
+ bool int_cst = TREE_CODE ( *arg) == INTEGER_CST;
+ DEBUG_A("is %sinteger constant\n", int_cst ? "" : "not ");
+ if ( int_cst && integer_zerop ( *arg) )
+ {
+ *arg = TYPE_MAX_VALUE ( ri->pointer_rep);
+ DEBUG_L("arg after = ");
+ DEBUG_F(flexible_print, stderr, *arg, 1, (dump_flags_t)0);
+ }
+ }
+ }
+ }
+ INDENT(-4);
+ }
+ pop_cfun ();
+ }
+
+ DEBUG_L("after bulk of transformations\n");
+
+ DEBUG_F( print_program, info->reorg_dump_file, PRINT_FORMAT, 4, info);
+
+ DEBUG ("INTERNALS PRINT\n");
+ DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info);
+
+ // A mini-pass to fixup dangling SSA temps.
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func);
+
+ std::vector <tree> ssa_to_delete;
+
+ DEBUG_L("Mini-Pass on Function %s:\n", lang_hooks.decl_printable_name ( func->decl, 2));
+
+ //DEBUG_L("\n");
+ //DEBUG_F( wolf_fence, info);
+
+ // We need a map of old ssa_name to new ssa_name. Not currently used.
+ std::map <tree,tree> ssa_map;
+
+ // Walk function decl.
+ // Modify declaractions modifies the formal parameter types.
+ // TBD That needs to be moved here
+ // Never the less we need to associate new default defs with them.
+ // At the end of find_decls_and_types adds parameter decls.
+ // We'll use get_or_create_ssa_default_def on the ssa name and
+ // create a new decl for the decls that are pointers to
+ // reorg types.
+ //
+ // Then walk the gimple looking for dangling types. When we find
+ // one on the right hand side check to see if it's on the
+ // map. If not we create a ssa name and add it to the map. We
+ // subsitute it into operand. For the left hand side we also
+ // set the statement definition.
+
+ // Default defs case first
+
+ // For parameters
+
+ // Note, we don't do anything unless it's necessary and it's
+ // not necessay if it's been done before. Hence the possibility
+ // of many functions mapping onto one declaration (which I
+ // even doubt is possible in thi case) can't be a problem.
+
+ DEBUG_L("Dangling Types for Function Params (default defs).\n");
+ INDENT(4);
+ tree parm;
+ for ( parm = DECL_ARGUMENTS ( func->decl);
+ parm;
+ parm = DECL_CHAIN ( parm) )
+ {
+ DEBUG_A("param: ");
+ DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0);
+ DEBUG("\n");
+ INDENT(2);
+ tree old_default_def = ssa_default_def ( func, parm);
+ DEBUG_A("old_default_def: ");
+ DEBUG_F( print_generic_expr, stderr, old_default_def, (dump_flags_t)0);
+ DEBUG("\n");
+ tree new_default_def;
+
+ // Modify prameter and do the default def stuff
+
+ // Need to create a new decl rather than modify the existing
+ // one.
+
+ if ( modify_decl_core ( &parm, info) )
+ {
+ DEBUG_A("double check new param: ");
+ DEBUG_F( print_generic_decl, stderr, parm, (dump_flags_t)0);
+ DEBUG("\n");
+
+ // New default def here
+
+ // If the variable of the decl is initialized
+ // then it shouldn't be associated with a default def.
+ if ( old_default_def )
+ {
+ // We must delete the old one or tranversing ssa names of
+ // the function will stumple across an SSA name associated
+ // with nothing, causing grief.
+ //
+ // We do it at the bottom of this code using a
+ // something I had to write (there was no existing
+ // mechanism.)
+
+ // Create new default def here.
+ // NOTE parm looks correct here but type of new_default_def
+ // is that of old_default_def so this might just look up
+ // old_default_def!
+ //new_default_def = get_or_create_ssa_default_def ( func, parm);
+ // ??? try this (in conjunction with the above) to fix things... NOPE
+ //set_ssa_default_def ( func, parm, new_default_def);
+ // ??? these instead
+ new_default_def = make_ssa_name_fn ( func, parm, gimple_build_nop ());
+ set_ssa_default_def ( func, parm, new_default_def);
+
+ DEBUG_A("new_default_def: ");
+ DEBUG_F(print_generic_expr, stderr, new_default_def, (dump_flags_t)0);
+ DEBUG(", TYPE: ");
+ DEBUG_F(print_generic_expr, stderr, TREE_TYPE(new_default_def), (dump_flags_t)0);
+ DEBUG("\n");
+
+ // TBD REMOVE DUPLICATE!
+ // Replace old one (not really totally hence the
+ // remove_default_def below.)
+ set_ssa_default_def ( func, parm, new_default_def);
+
+ imm_use_iterator iter;
+ gimple *stmt;
+ use_operand_p use;
+ // Modify stmts using old default def to use
+ // new default def
+ FOR_EACH_IMM_USE_STMT ( stmt, iter, old_default_def) // <== use other form??? Not
+ {
+ DEBUG_A("before: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ use_operand_p use_p;
+ ssa_op_iter ssa_iter;
+ // The F_E_S_U_O macro was blowing up on a phi
+ //FOR_EACH_SSA_USE_OPERAND( use_p, stmt, ssa_iter, SSA_OP_USE )
+ FOR_EACH_PHI_OR_STMT_USE ( use_p, stmt, ssa_iter, SSA_OP_USE )
+ {
+ if ( use_p == NULL ) continue;
+ tree use = USE_FROM_PTR (use_p);
+ DEBUG_A("use to replace: ");
+ DEBUG_F( print_generic_expr, stderr, use, (dump_flags_t)0);
+ DEBUG("\n");
+ if (use == old_default_def)
+ SET_USE ( use_p, new_default_def);
+ }
+ DEBUG_A("after: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ }
+ // Get rid of the old default def because it confuses
+ //
+ //remove_default_def ( old_default_def, func);
+ ssa_to_delete.push_back ( old_default_def);
+ release_ssa_name_fn ( func, old_default_def);
+ }
+ }
+ INDENT(-2);
+ }
+ INDENT(-4);
+
+ DEBUG_L("Dangling Types for Function Local (default defs).\n");
+ INDENT(4);
+ //DEBUG_L("\n");
+ //DEBUG_F( wolf_fence, info);
+
+ // For locals
+ //
+ // Note, the code below looks half baked and might simply not
+ // encountered anything that breaks it (see the code for the
+ // parameters above how it might need to look.)
+ //
+
+ unsigned i;
+ tree decl;
+ FOR_EACH_LOCAL_DECL ( func, i, decl)
+ {
+ DEBUG_A("local: ");
+ DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)0);
+ DEBUG("\n");
+ tree old_default_def = ssa_default_def ( func, decl);
+ tree new_default_def;
+
+ // Modify prameter and do the default def stuff
+
+ // Again we'll need to create a new decl rather than modify
+ // the existing one.
+
+ if ( modify_decl_core ( &decl, info) )
+ {
+ // New default def here
+
+ // If the variable of the decl is initialized
+ // then it shouldn't be associated with a default def.
+ if ( old_default_def )
+ {
+ // TBD Do we delete the old one and if so,
+ // do we do it here and how do we do it?
+
+ // Create new default def here.
+ new_default_def = get_or_create_ssa_default_def ( func, decl);
+
+ imm_use_iterator iter;
+ gimple *stmt;
+ use_operand_p use;
+ // Modify stmts using old default def to use
+ // new default def
+ FOR_EACH_IMM_USE_STMT ( stmt, iter, old_default_def)
+ {
+ FOR_EACH_IMM_USE_ON_STMT ( use, iter)
+ {
+ SET_USE ( use, new_default_def);
+ }
+ // Possibly do this???
+ //update_stmt ( stmt);
+ }
+ }
+ }
+ }
+ INDENT(-4);
+
+ // Normal ssa name case
+ DEBUG_L("Dangling Types for Normal SSA Names:\n");
+ //DEBUG_L("\n");
+ //DEBUG_F( wolf_fence, info);
+
+ INDENT(4);
+ // We use len instead of using func->length() in the for loop test
+ // because new ssa names are created in the loop body and we
+ // shouldn't process them.
+ unsigned int len = SSANAMES ( func)->length ();
+ DEBUG_L("len = %d\n",len);
+ for ( unsigned int i = 0; i < len; i++)
+ {
+ DEBUG_L("SSANAMES(func)[%d]\n",i);
+
+ tree ssa_name = (*SSANAMES ( func))[i];
+
+ if( ssa_name == NULL )
+ {
+ DEBUG_L("Skip, ssa_name == NULL\n");
+ continue;
+ }
+
+ bool a_default_def = SSA_NAME_IS_DEFAULT_DEF ( ssa_name);
+ gimple *defining_stmt = SSA_NAME_DEF_STMT ( ssa_name);;
+ bool no_defining_stmt = defining_stmt == NULL;
+ bool defined_by_nop = defining_stmt && gimple_code ( defining_stmt) == GIMPLE_NOP;
+ tree type = TREE_TYPE ( ssa_name);
+ tree bottom_type = base_type_of ( type);
+ ReorgType_t *ri = get_reorgtype_info ( bottom_type, info);
+ DEBUG_L("ssa_name = ");
+ DEBUG_F(print_generic_expr, stderr, ssa_name, (dump_flags_t)0);
+ DEBUG(" %s", a_default_def ? "is default_def" : "");
+ DEBUG(" %s", no_defining_stmt ? "has no defining stmt" : "");
+ DEBUG(" %s", defined_by_nop ? "defined by a nop" : "");
+ DEBUG(", type = ");
+ DEBUG_F(print_generic_expr, stderr, type, (dump_flags_t)0);
+ DEBUG(", bottom_type = ");
+ DEBUG_F(print_generic_expr, stderr, bottom_type, (dump_flags_t)0);
+ DEBUG(", ri = %p\n",ri);
+
+ // If it's not a dangling type we don't care
+ if ( ri == NULL )
+ {
+ DEBUG_L("Skip, ri == NULL\n");
+ continue;
+ }
+
+ // A default def is processed seperately
+ if ( a_default_def )
+ {
+ DEBUG_L("Skip default_def\n");
+ continue;
+ }
+
+ gcc_assert ( !no_defining_stmt);
+ gcc_assert ( !defined_by_nop);
+
+ DEBUG_L("Defining stmt: ");
+ DEBUG_F ( print_gimple_stmt, stderr, defining_stmt, 0);
+
+ tree new_type = ri->pointer_rep;
+ tree new_ssa_name = make_temp_ssa_name( new_type, NULL, "dedangled");
+ DEBUG_L("new_ssa_name = ");
+ DEBUG_F(print_generic_expr, stderr, new_ssa_name, (dump_flags_t)0);
+ DEBUG("\n");
+ #if DEBUGGING
+ for ( unsigned int j = 0; j < SSANAMES ( func)->length (); j++)
+ {
+ if ( (*SSANAMES ( func))[j] == new_ssa_name )
+ {
+ DEBUG_L("new name at j = %d\n",j);
+ break;
+ }
+ }
+ #endif
+
+ gimple *use_stmt;
+ imm_use_iterator iter;
+ FOR_EACH_IMM_USE_STMT ( use_stmt, iter, ssa_name)
+ {
+ DEBUG_L("use_stmt before: ");
+ DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0);
+
+ // Deal with the uses
+ use_operand_p use_p;
+ ssa_op_iter ssa_iter;
+ // The F_E_S_U_O macro was blowing up on a phi
+ //FOR_EACH_SSA_USE_OPERAND( use_p, use_stmt, ssa_iter, SSA_OP_USE )
+ FOR_EACH_PHI_OR_STMT_USE ( use_p, use_stmt, ssa_iter, SSA_OP_USE )
+ {
+ DEBUG_L("use_p = %p\n",use_p);
+ if ( use_p == NULL ) continue;
+ tree use = USE_FROM_PTR (use_p);
+ if (use == ssa_name)
+ SET_USE ( use_p, new_ssa_name);
+ }
+ DEBUG_L("use_stmt after: ");
+ DEBUG_F ( print_gimple_stmt, stderr, use_stmt, 0);
+
+ // Should update_stmt be called here?
+ // It does not seem either harm or help so I'll
+ // leave it in.
+ update_stmt ( use_stmt);
+ }
+ // Modify the LHS too
+ // TBD This code needs to be more general.
+ DEBUG_L("What is ssa_name? ");
+ DEBUG_F(flexible_print, stderr, ssa_name, 1, (dump_flags_t)0);
+ gimple *def = SSA_NAME_DEF_STMT ( ssa_name);
+
+ DEBUG_L("def: ");
+ DEBUG_F ( print_gimple_stmt, stderr, def, 0);
+
+ set_lhs_for ( def, new_ssa_name);
+
+ update_stmt ( def);
+
+ // This is where we know that ssa_name needs to be replaced
+ release_ssa_name_fn ( func, ssa_name);
+
+ }
+ INDENT(-4);
+
+ // Might be a bad idea.
+ #if 0
+ for ( auto iter = ssa_to_delete.begin ();iter != ssa_to_delete.end (); iter++ )
+ {
+ remove_default_def ( *iter, func);
+ }
+ #endif
+
+ pop_cfun ();
+ }
+
+ DEBUG_L("after mini-passes\n");
+
+ if ( info->show_all_reorg_cands )
+ {
+ fprintf ( info->reorg_dump_file, "End of str_reorg_instance_interleave_trans:\n");
+ print_program ( info->reorg_dump_file, PRINT_FORMAT, 4, info);
+ }
+
+ // TBD Should this be a diagnostic or not?
+ DEBUG ("INTERNALS PRINT\n");
+ DEBUG_F (apply_to_all_gimple, print_internals, true, (void *)info);
+}
+
+// Note, the following code might be a bit overly simplistic.
+static void
+set_lhs_for ( gimple *stmt, tree ssa_name)
+{
+ switch ( gimple_code ( stmt))
+ {
+ case GIMPLE_ASSIGN:
+ gimple_assign_set_lhs ( stmt, ssa_name);
+ break;
+ case GIMPLE_CALL:
+ gimple_call_set_lhs ( stmt, ssa_name);
+ break;
+ case GIMPLE_PHI:
+ {
+ gphi *phi_stmt = as_a <gphi *> ( stmt);
+ gimple_phi_set_result ( phi_stmt, ssa_name);
+ }
+ break;
+ default:
+ fprintf ( stderr, "error: unprecidented gimple for set_lhs_for\n ");
+ print_gimple_stmt( stderr, stmt, 0);
+ gcc_assert ( 0);
+ }
+}
+
+// TBD no longer used... preserve it for a bit, then remove it.
+static void
+wrangle_ssa_type( tree side, Info_t *info )
+{
+ tree side_type = TREE_TYPE ( side);
+ tree bottom_type = base_type_of ( side_type);
+ //DEBUG_L("op: ");
+ //DEBUG_F(print_generic_expr, stderr, side, (dump_flags_t)0);
+ //DEBUG("\n");
+ //DEBUG_L("bottom_type: ");
+ //DEBUG_F(print_generic_expr, stderr, bottom_type, (dump_flags_t)0);
+ //DEBUG("\n");
+
+ // Maybe we sould pass in ri as an argument???
+ ReorgType_t *ri = get_reorgtype_info ( bottom_type, info);
+ tree prev_type = side_type;
+ tree type = TREE_TYPE ( prev_type);
+ //DEBUG_L( "prev_type: %p, type: %p\n", prev_type, type);
+ int levels;
+ for ( levels = 0; TREE_CODE ( type) == POINTER_TYPE; levels++ )
+ {
+ prev_type = type;
+ type = TREE_TYPE ( prev_type);
+ //DEBUG_L( "prev_type: %p, type: %p\n", prev_type, type);
+ }
+
+ // I thought about doing this:
+ // Modify type of ssa temp (dicey!)
+ // This changes every instance of * reorg_type to the
+ // new pointre rep in one fell swoop.
+ // I sweat just thinking how crazy this is....
+ //
+ // TREE_TYPE ( prev_type) = ri->pointer_rep;
+
+ // TBD might use build_pointer_type to build new type for *(N)reorg_type
+ // to *(N-1)ri->pointer_rep
+ // Fakes this for levels == 1
+ if ( levels == 0)
+ {
+ //DEBUG_L( "LEVELS ZERO\n");
+ modify_ssa_name_type ( side, ri->pointer_rep);
+ //DEBUG_L("after modify_ssa_name_type\n");
+ }
+ else
+ {
+ //DEBUG_L( "LEVELS > ZERO\n");
+ gcc_assert(0);
+ }
+}
+
+void
+print_internal_op ( tree op)
+{
+ tree type = TREE_TYPE ( op);
+ print_generic_expr ( stderr, op, (dump_flags_t)0);
+ fprintf( stderr, " TYPE: ");
+ print_generic_expr ( stderr, type, (dump_flags_t)0);
+ fprintf( stderr, " MAIN_TYPE: ");
+ print_generic_expr ( stderr, TYPE_MAIN_VARIANT ( type), (dump_flags_t)0);
+ fprintf( stderr, "\n");
+}
+
+bool
+print_internals (gimple *stmt, void *data)
+{
+ Info_t *info = (Info_t*)data;
+
+ print_gimple_stmt ( stderr, stmt, TDF_SLIM);
+
+ if ( gimple_code ( stmt) == GIMPLE_ASSIGN )
+ {
+ tree lhs = gimple_assign_lhs( stmt);
+ tree rhs1 = gimple_assign_rhs1( stmt);
+ tree rhs2 = gimple_assign_rhs2( stmt);
+ tree rhs3 = gimple_assign_rhs3( stmt);
+ gcc_assert ( lhs);
+ gcc_assert ( rhs1);
+
+ bool lhs_reorg = tree_contains_a_reorgtype_p ( lhs, info);
+ //DEBUG_L("rhs1 = ");
+ //DEBUG_F(flexible_print, stderr, rhs1, 1, (dump_flags_t)0);
+ bool rhs1_reorg = tree_contains_a_reorgtype_p ( rhs1, info);
+ bool rhs2_reorg = tree_contains_a_reorgtype_p ( rhs2, info);
+ bool rhs3_reorg = tree_contains_a_reorgtype_p ( rhs3, info);
+
+ bool lhs_ssa = lhs_reorg && TREE_CODE(lhs) == SSA_NAME;
+ bool rhs1_ssa = rhs1_reorg && TREE_CODE(rhs1) == SSA_NAME;
+ bool rhs2_ssa = rhs2_reorg && TREE_CODE(rhs2) == SSA_NAME;
+ bool rhs3_ssa = rhs3_reorg && TREE_CODE(rhs3) == SSA_NAME;
+
+ fprintf( stderr, " LHS%s: ", lhs_ssa ? "*" : "");
+ print_generic_expr ( stderr, TREE_TYPE ( lhs), (dump_flags_t)0);
+
+ fprintf( stderr, ", RHS1%s: ", rhs1_ssa ? "*" : "");
+ print_generic_expr ( stderr, TREE_TYPE ( rhs1), (dump_flags_t)0);
+
+ if ( rhs2 )
+ {
+ fprintf( stderr, ", RHS2%s: ", rhs2_ssa ? "*" : "");
+ print_internal_op ( rhs2);
+ }
+
+ if ( rhs3 )
+ {
+ fprintf( stderr, ", RHS3%s: ", rhs3_ssa ? "*" : "");
+ print_internal_op ( rhs3);
+ }
+ fprintf ( stderr, "\n");
+ } else
+ if ( gimple_code ( stmt) == GIMPLE_PHI )
+ {
+ use_operand_p phi_op;
+ ssa_op_iter iter;
+ gphi *phi_stmt = dyn_cast <gphi *> ( stmt);
+
+ tree def = PHI_RESULT ( phi_stmt);
+ fprintf( stderr, " OP: ");
+ print_internal_op ( def);
+
+ FOR_EACH_PHI_ARG ( phi_op, phi_stmt, iter, SSA_OP_ALL_OPERANDS)
+ {
+ tree op = USE_FROM_PTR ( phi_op);
+ fprintf( stderr, " OP: ");
+ print_internal_op ( op);
+ }
+ }
+ else
+ {
+ ssa_op_iter iter;
+ tree op_def;
+ use_operand_p opu;
+ FOR_EACH_SSA_TREE_OPERAND ( op_def, stmt, iter, SSA_OP_ALL_DEFS)
+ {
+ fprintf( stderr, " DEF OP: ");
+ print_internal_op ( op_def);
+ }
+ FOR_EACH_SSA_USE_OPERAND ( opu, stmt, iter, SSA_OP_ALL_USES)
+ {
+ tree use_op = USE_FROM_PTR ( opu);
+ fprintf( stderr, " USE OP: ");
+ print_internal_op ( use_op);
+ }
+ }
+
+ return false;
+}
+
+static void
+str_reorg_instance_interleave_qual_part ( Info *info)
+{
+ // TBD save the return value so we can bypass further
+ // instance interleaving if none of it is profitable.
+ reorg_perf_qual ( info);
+}
+
+static void
+str_reorg_instance_interleave_type_part ( Info *info)
+{
+ create_new_types ( info);
+}
+
+// Typse for performance qualification
+
+typedef struct reorg_bb_info reorg_bb_info_t;
+struct reorg_bb_info {
+ basic_block *bb;
+};
+
+typedef struct perf_bb_info perf_bb_info_t;
+typedef struct acc_info acc_info_t;
+typedef struct var_info var_info_t;
+
+struct var_info {
+ varpool_node *var;
+ sbitmap *bits;
+ double count;
+};
+
+struct acc_info {
+ varpool_node *v;
+ int field_num;
+};
+
+struct perf_loop_info {
+ std::vector <var_info_t*> *vari;
+ class loop *gcc_loop;
+};
+
+static void account_for_use( tree, std::vector <acc_info_t> *);
+static bool is_array_access( tree);
+
+static unsigned int
+reorg_perf_qual ( Info *info)
+{
+ DEBUG_L("reorg_perf_qual:\n");
+ #if 1
+ // TBD use design in doc but mark ReorgTypes
+ // (do_instance_interleave) that qualify instead of deleting them
+ // unless both dead field elimination and field reorderig are not
+ // viable (use do_dead_field_elim and do_field_reorder in
+ // Reorg_type_t.)
+
+ // For the mean time assume if a ReorgType made it here then it's qualified.
+ for ( int i = 0; i < info->reorg_type->size (); i++ )
+ {
+ (*(info->reorg_type))[i].do_instance_interleave = true;
+ }
+ #else
+ // We are doing a quick and dirty version of performance
+ // qualification for testing purposes and possibly the
+ // initial version of for the main branch.
+ auto reorg_types = info->reorg_type;
+
+ // These are floating point numbers because of the fractional
+ // accesses associated the probabilistic approach taken
+ // below. By taken below I refer to full algorithm and the
+ // quick and dirty initial version.
+
+ // reorg was not possible for these
+ double cache_accesses = 0.0;
+
+ // reorg possible for these. This doesn't mean it is
+ // profitable or even legal for all the types lumped
+ // in together here. However, the sum of this and
+ // cache_accesses should account for all the array
+ // accesses in the program.
+ double cache_accesses_noreorg = 0.0;
+
+ // Perf Analysis
+ struct cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ // Ulgy GCC idiom with global pointer to current function.
+ // However, the dominace calculations other things need it.
+ push_cfun ( func);
+
+ if ( dom_info_available_p ( CDI_DOMINATORS) )
+ {
+ free_dominance_info ( CDI_DOMINATORS);
+ }
+ calculate_dominance_info (CDI_DOMINATORS);
+
+ // TBD
+ std::vector<perf_loop_info> loop_perf;
+ loop_perf.reserve ( number_of_loops ( func));
+ class loop *loop;
+ FOR_EACH_LOOP_FN ( func, loop, LI_ONLY_INNERMOST )
+ {
+ loop_perf [ loop->num ].vari = new std::vector<var_info_t*>; // ???
+ loop_perf [ loop->num ].gcc_loop = loop;
+ size_t num_bbs = loop->num_nodes;
+ basic_block *bbs = get_loop_body ( loop);
+
+ // TBD Stuff here
+ for ( unsigned i = 0; i < loop->num_nodes; i++)
+ {
+ basic_block bb = bbs [i];
+ for ( auto gsi = gsi_start_bb ( bb); !gsi_end_p ( gsi); gsi_next ( &gsi) )
+ {
+ gimple *stmt = gsi_stmt ( gsi);
+ if ( contains_a_reorgtype ( stmt, info) != NULL )
+ {
+ DEBUG_A("examine: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ INDENT(4);
+ unsigned n_ops = gimple_num_ops( stmt);
+ tree op;
+ unsigned ith_op;
+ for ( ith_op = 0; i < n_ops; i++ )
+ {
+ op = gimple_op ( stmt, ith_op);
+ ReorgType_t *tri = tree_contains_a_reorgtype (op, info);
+ if ( tri != NULL )
+ {
+ DEBUG_A("");
+ DEBUG_F(print_reorg, stderr, 0, tri);
+ DEBUG(", ");
+ DEBUG_F(flexible_print, stderr, op, 1, (dump_flags_t)0);
+ }
+ }
+ INDENT(-4);
+
+ }
+ }
+ }continue; // Testing above here
+
+ // Obtain loop count by looking at all the block counts.
+ unsigned max_count = 0;
+ for ( unsigned i = 0; i < loop->num_nodes; i++)
+ {
+ basic_block bb = bbs [i];
+ max_count = MAX( max_count, bb->count.value ());
+ }
+ DEBUG_L("max_count = %d, nb_iterations_estimate = %ld\n",
+ max_count, loop->nb_iterations_estimate);
+
+ // Originally this was done per bb but now it has to be per
+ // loop. TBD But perf_bb is per loop so we need something similar
+ // per loop.
+
+ std::vector <var_info_t*> *pv = loop_perf [ loop->num].vari;
+ for ( auto pvi = pv->begin (); pvi != pv->end (); pvi++ )
+ { // 676
+ tree base_type = base_type_of( ( *pvi)->var->decl);
+ ReorgType_t *ri = get_reorgtype_info ( base_type, info);
+ // Reorg accounting
+ if( ri != NULL )
+ {
+ double reorg_nca = 0.0;
+ int fi;
+ tree field;
+ for( field = TYPE_FIELDS ( ri->gcc_type), fi = 0;
+ field;
+ field = DECL_CHAIN ( field), fi++ ) // 684
+ {
+ if ( bitmap_bit_p ( *(*pvi)->bits, fi) )
+ {
+ unsigned HOST_WIDE_INT fld_width =
+ tree_to_uhwi ( DECL_SIZE ( field));
+ reorg_nca += max_count * alignment_effect ( fld_width);
+ }
+ }
+ ri->instance_interleave.reorg_perf += reorg_nca;
+ } // 699
+
+ // regular accounting
+ double regular_nca = 0.0;
+ sbitmap cache_model = sbitmap_alloc(1);
+ // TBD NOTE, pv steps on the pv above.
+ std::vector <var_info_t*> *pv2 = loop_perf[ loop->num].vari;
+ for( auto pv2i = pv2->begin (); pv2i != pv2->end (); pv2i++ ) { // 704
+ tree base_type = base_type_of ( (*pv2i)->var->decl);
+ // create a tiny model of the cache big
+ // enough for this record.
+ unsigned HOST_WIDE_INT len =
+ (( tree_to_uhwi ( DECL_SIZE ( base_type))
+ +
+ param_l1_cache_line_size -1)
+ /
+ param_l1_cache_line_size)
+ +
+ 1;
+ cache_model = sbitmap_resize( cache_model, (unsigned) len, 0);
+ double accum = 0.0;
+ int nrbo = 0;
+ for ( auto field_ex = TYPE_FIELDS ( base_type);
+ field_ex;
+ field_ex = DECL_CHAIN ( field_ex) )
+ {
+ nrbo++;
+ unsigned HOST_WIDE_INT base_offset =
+ tree_to_uhwi ( DECL_FIELD_OFFSET( field_ex));
+ // Access accounting
+ int fi = 0;
+ for ( auto field = TYPE_FIELDS ( base_type);
+ field;
+ field = DECL_CHAIN ( field), fi++)
+ {
+ if ( bitmap_bit_p ( *(*pv2i)->bits, fi) )
+ {
+ unsigned HOST_WIDE_INT fld_width, fld_offset;
+ fld_width = tree_to_uhwi ( DECL_SIZE ( field));
+ fld_offset = tree_to_uhwi ( DECL_FIELD_OFFSET ( field));
+ int chari;
+ for ( chari = 0; chari < fld_width; chari++ )
+ {
+ int loc = (chari + fld_offset + base_offset)
+ /
+ param_l1_cache_line_size;
+ bitmap_set_bit ( cache_model, loc);
+ }
+ }
+ }
+ accum += bitmap_count_bits ( cache_model);
+ bitmap_clear ( cache_model);
+ }
+ regular_nca += accum / nrbo;
+
+ } // 739
+ sbitmap_free ( cache_model);
+
+ if( ri != NULL ) {
+ ri->instance_interleave.regular_perf += regular_nca;
+ cache_accesses_noreorg += regular_nca;
+ } else {
+ cache_accesses += regular_nca;
+ }
+ } // end for each prop_var 748
+
+
+ } //
+ pop_cfun ();
+ }
+
+ // TBD Somebody somewhere needs to compute:
+ // reorg_perf
+ // regular_perf
+ // cache_accesses
+ // cache_accesses_noreorg
+
+ double total_cache_accesses =
+ cache_accesses + cache_accesses_noreorg;
+
+ info->total_cache_accesses = total_cache_accesses;
+
+ //
+ // Decide which reorgTypes fail performance qualification
+ //
+
+ // We have the total accesses per type. Use that to see
+ // if the type qualifies.
+ for ( auto reorgi = reorg_types->begin ();
+ reorgi != reorg_types->end (); reorgi++ )
+ {
+ double with_opt = reorgi->instance_interleave.reorg_perf;
+ double wihtout_opt = reorgi->instance_interleave.regular_perf;
+ double raw_effect = with_opt/wihtout_opt;
+ double absolute_effect =
+ (wihtout_opt - with_opt) / total_cache_accesses;
+
+ // Note, there would need to be a multi-pool case here if
+ // that is every done.
+
+ // If the relative effect is small enough don't bother.
+ if ( raw_effect < SINGLE_POOL_RAW_SKIP_IT )
+ {
+ reorgi->do_instance_interleave = false;
+ continue;
+ }
+ // the relative effect is big enough do it anyway
+ // otherwise look at the absolute effect.
+ if ( raw_effect >= SINGLE_POOL_RAW_DO_IT_ALWAYS )
+ {
+ reorgi->do_instance_interleave = true;
+ continue;
+ }
+ if ( absolute_effect < SINGLE_POOL_ABS_SKIP_IT )
+ {
+ reorgi->do_instance_interleave = false;
+ continue;
+ }
+ if ( absolute_effect >= SINGLE_POOL_ABS_DO_IT_ALWAYS )
+ {
+ reorgi->do_instance_interleave = true;
+ continue;
+ }
+
+ // We fitted a linear equation to the corners of the
+ // effects above and use it to determine when
+ // to disqualify a type
+ double cut_off = cut_off_eq_single_pool ( absolute_effect);
+ if ( raw_effect < cut_off )
+ {
+ reorgi->do_instance_interleave = false;
+ }
+ }
+
+ free_dominance_info ( CDI_DOMINATORS);
+
+ #endif
+}
+
+#define SINGLE_POOL_SLOPE \
+ ((SINGLE_POOL_RAW_DO_IT_ALWAYS - SINGLE_POOL_RAW_SKIP_IT) \
+ / \
+ (SINGLE_POOL_ABS_DO_IT_ALWAYS - SINGLE_POOL_ABS_SKIP_IT))
+
+#define SINGLE_POOL_INTERSECT \
+ (SINGLE_POOL_RAW_SKIP_IT \
+ - \
+ SINGLE_POOL_SLOPE * SINGLE_POOL_ABS_SKIP_IT)
+
+static double
+cut_off_eq_single_pool( double x)
+{
+ return SINGLE_POOL_SLOPE * x + SINGLE_POOL_INTERSECT;
+}
+
+static double
+alignment_effect( unsigned HOST_WIDE_INT width )
+{
+ unsigned HOST_WIDE_INT times = param_l1_cache_line_size / width; // ??
+ unsigned HOST_WIDE_INT rem = param_l1_cache_line_size % width;
+ if( rem == 0 ) {
+ return 1.0;
+ }
+ unsigned HOST_WIDE_INT m, n, g;
+ g = gcd( param_l1_cache_line_size, width);
+ m = param_l1_cache_line_size / g;
+ n = width / g;
+ return 1.0 + (n - 1.0)/m;
+}
+
+static void
+header ( bool initialize )
+{
+ static bool emit_header;
+ if ( initialize )
+ {
+ emit_header = true;
+ }
+ else
+ {
+ if ( emit_header )
+ {
+ emit_header = false;
+ fprintf( stderr, "SANITY CHECKING FAILURE:\n");
+ }
+ }
+}
+
+// TBD I have doubts that this what is really needed
+bool
+is_array_access( tree acc)
+{
+ tree type = TREE_TYPE ( acc);
+ if( TREE_CODE( type) == ARRAY_TYPE )
+ return true;
+ while( POINTER_TYPE_P( type) ) {
+ type = TREE_TYPE( type);
+ if( TREE_CODE( type) == ARRAY_TYPE )
+ return true;
+ }
+ return false;
+}
+
+static void
+account_for_use( tree acc, std::vector <acc_info_t> *acc_info)
+{
+ // determine element of access
+ // find field access number i
+ // find var v
+ varpool_node *v;
+ int i;
+ // TBD
+ acc_info_t ai = { v, i};
+ acc_info->push_back( ai);
+}
+
+
+// create_new_types has to crawl "all" the
+// types, create new types and transform
+// other types that must be changed.
+// A type will change when it's a
+// a pointer to a ReorgType or it contains
+// an interior pointer to one.
+static void
+create_new_types ( Info_t *info)
+{
+ std::map < tree, BoolPair_t>::iterator tmi;
+ for( tmi = info->struct_types->begin ();
+ tmi != info->struct_types->end ();
+ tmi++ ) {
+ if ( !tmi->second.processed ) create_a_new_type ( info, tmi->first);
+ }
+}
+
+static void
+create_a_new_type ( Info_t *info, tree type)
+{
+ bool layout_changed = false;
+ // skip if already processed
+ if ( ( *( info->struct_types))[type].processed ) return;
+
+ // Implementation note: Check this for infinite recursion.
+ // I don't think it's possible in a sane universe but
+ // pointers to reorganized types can occur, so does that
+ // an issue (not necessarily here.)
+ // Also, is this even necessary? Singletons don't expand
+ // and static arrays are not allowed "yet."
+ tree field;
+ tree new_fields = NULL;
+ for ( field = TYPE_FIELDS ( type); // ??? I speced reorg_type_prime here???
+ field;
+ field = DECL_CHAIN ( field))
+ {
+ // make sure all the interior types are processed
+ // before processing this type
+ if ( TREE_CODE ( field) == RECORD_TYPE )
+ {
+ create_a_new_type ( info, field);
+ }
+ }
+
+ ReorgType_t *ri = get_reorgtype_info ( type, info);
+ if ( ri != NULL ) {
+ // Create the new record type of the reorg type
+ tree reorg_type_prime = lang_hooks.types.make_type (RECORD_TYPE);
+
+ ri->reorg_ver_type = reorg_type_prime;
+ //DEBUG_L("TYPE_SIZE(reorg_type_prime): %p, ", TYPE_SIZE(reorg_type_prime));
+ //DEBUG_F( print_generic_expr, stderr, TYPE_SIZE(reorg_type_prime), (dump_flags_t)-1);
+ //DEBUG("\n");
+
+ /* Multi-pool only
+ // Create pointer_rep
+ // this will be a long and a pointer to the
+ // reorg_type_prime
+ tree pointer_rep =
+ lang_hooks.types.make_type( RECORD_TYPE);
+
+ tree index_name = get_identifier("index");
+ tree index_field = build_decl( BUILTINS_LOCATION,
+ FIELD_DECL,
+ index_name,
+ long_integer_type_node);
+ tree base_name = get_identifier("base");
+ tree base_field = build_decl( BUILTINS_LOCATION,
+ FIELD_DECL,
+ base_name,
+ reorg_type_prime);
+ insert_field_into_struct( pointer_rep, index_field);
+ insert_field_into_struct( pointer_rep, base);
+
+ reorg_type->pointer_rep = pointer_rep;
+ */
+
+ tree pointer_rep = make_signed_type ( TYPE_PRECISION ( pointer_sized_int_node));
+ TYPE_MAIN_VARIANT ( pointer_rep) = TYPE_MAIN_VARIANT ( pointer_sized_int_node);
+ //DEBUG("Issue with gcc_ of reorg\n");
+ //DEBUG_F(print_reorg, stderr, 2, ri);
+ const char *gcc_name =
+ identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type)));
+ size_t len =
+ strlen ( REORG_SP_PTR_PREFIX) + strlen ( gcc_name);
+ char *name = ( char *)alloca(len + 1);
+ strcpy ( name, REORG_SP_PTR_PREFIX);
+ strcat ( name, gcc_name);
+ TYPE_NAME ( pointer_rep) = get_identifier ( name);
+ ri->pointer_rep = pointer_rep;
+ //DEBUG_L("pointer_rep = ");
+ //DEBUG_F( print_generic_expr, stderr, pointer_rep, (dump_flags_t)-1);
+ //DEBUG("\n");
+ //DEBUG_A("TYPE_MAIN_VARIANT ( pointer_rep) = ");
+ //DEBUG_F( print_generic_expr, stderr, TYPE_MAIN_VARIANT ( pointer_rep), (dump_flags_t)-1);
+ //DEBUG("\n");
+
+ // Note, we also declare a base type variable (globally.)
+ // This variable also belong in the ReorgType.
+
+ // Set name of reorg_type_prime
+ const char *base_type_name =
+ identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type)));
+ len = strlen ( REORG_SP_PREFIX) + strlen ( base_type_name);
+ char *rec_name = ( char*)alloca ( len + 1);
+ strcpy ( rec_name, REORG_SP_PREFIX);
+ strcat ( rec_name, base_type_name);
+
+ //DEBUG_L("TYPE_SIZE(reorg_type_prime): %p\n", TYPE_SIZE(reorg_type_prime));
+
+ // Build the new pointer type fields
+ TYPE_NAME ( reorg_type_prime) = get_identifier ( rec_name);
+ tree field;
+ tree new_fields = NULL;
+ for ( field = TYPE_FIELDS ( type); field; field = DECL_CHAIN ( field))
+ {
+ //DEBUG_F( print_generic_decl, stderr, field, TDF_DETAILS); // example
+ tree tree_type = TREE_TYPE ( field);
+ tree new_fld_type = build_pointer_type ( tree_type);
+ tree new_decl =
+ build_decl ( DECL_SOURCE_LOCATION (field),
+ FIELD_DECL, DECL_NAME (field), new_fld_type);
+ DECL_CONTEXT ( new_decl) = reorg_type_prime;
+ layout_decl ( new_decl, 0);
+
+ // We might be missing a bunch of attributes (see
+ // tree-nested.c:899) But we seem without without them!
+
+ DECL_CHAIN ( new_decl) = new_fields; // <- bug: need decl, not type
+ new_fields = new_decl;
+ //DEBUG( "built new pointer type field:");
+ //DEBUG_F( print_generic_decl, stderr, new_decl, TDF_DETAILS);
+ //DEBUG( "\n");
+ }
+
+ //DEBUG_L("TYPE_SIZE(reorg_type_prime): %p\n", TYPE_SIZE(reorg_type_prime));
+
+ // store reversed fields into reorg_type_prime
+ TYPE_FIELDS ( reorg_type_prime) = NULL;
+ tree next_fld;
+ for ( field = new_fields;
+ field;
+ field = next_fld )
+ {
+ next_fld = DECL_CHAIN ( field);
+ DECL_CHAIN ( field) = TYPE_FIELDS ( reorg_type_prime);
+ TYPE_FIELDS ( reorg_type_prime) = field;
+ }
+ //DEBUG_L("TYPE_SIZE(reorg_type_prime): %p\n", TYPE_SIZE(reorg_type_prime));
+ // Fix-up the layout
+ layout_type ( reorg_type_prime);
+
+ // HERE
+ // Create the base element for a reorg type. This is for the single
+ // pool case only.
+ tree base_var =
+ build_decl ( UNKNOWN_LOCATION, VAR_DECL, NULL_TREE, ri->reorg_ver_type);
+ // We don't want to manually set DECL_INITIAL here!
+
+ const char *type_name =
+ identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( ri->gcc_type)));
+ size_t tlen = strlen ( REORG_SP_BASE_PREFIX) + strlen ( type_name);
+ char *base_name = ( char*)alloca ( tlen + 1);
+ strcpy ( base_name, REORG_SP_BASE_PREFIX);
+ //DECL_NAME ( base_var) = get_identifier ( base_name);
+
+ strcat ( base_name, type_name);
+
+ DECL_NAME ( base_var) = get_identifier ( base_name); // wrong spot above???
+
+ TREE_STATIC ( base_var) = 1;
+ TREE_ADDRESSABLE ( base_var) = 1;
+ DECL_NONALIASED ( base_var) = 1;
+ SET_DECL_ALIGN ( base_var, TYPE_ALIGN ( ri->reorg_ver_type));
+
+ varpool_node::finalize_decl ( base_var);
+
+ relayout_decl ( base_var);
+
+ ri->instance_interleave.base = base_var;
+ }
+
+ // Mess with the original type too because it might
+ // have base_type_fldinterior elements that are modified.
+ for ( field = TYPE_FIELDS ( type);
+ field;
+ field = DECL_CHAIN ( field))
+ {
+ if ( TREE_CODE ( field) == RECORD_TYPE )
+ {
+ layout_changed =
+ layout_changed || ( *( info->struct_types)) [ field].layout_changed;
+ }
+ else
+ {
+ // process pointers to reorg types
+ if ( POINTER_TYPE_P ( field) )
+ {
+ tree field_type = TREE_TYPE ( field);
+ if ( is_reorg_type ( field_type, info) )
+ {
+ // Change field type.
+
+ // If multi-pool then set layout_changed to true.
+
+ // The type pointed to changes for single-pool.
+ ReorgType_t *ri =
+ get_reorgtype_info ( field_type, info);
+ gcc_assert ( ri->pointer_rep);
+ TREE_TYPE ( field) = ri->pointer_rep;
+ }
+ tree base = base_type_of ( field);
+ if ( is_reorg_type ( base, info) )
+ {
+ // strip off a layer of pointers
+ gcc_assert ( TREE_TYPE ( TREE_TYPE( field)));
+ TREE_TYPE ( field) = TREE_TYPE ( TREE_TYPE( field));
+ }
+ }
+ }
+ }
+
+ // Mark the type as processed
+ ( *( info->struct_types)) [ type] = { true, layout_changed};
+}
+
+static tree
+find_coresponding_field ( tree base_decl, tree field)
+{
+ tree reorg_field;
+ for ( reorg_field = TYPE_FIELDS ( TREE_TYPE ( base_decl));
+ reorg_field;
+ reorg_field = DECL_CHAIN ( reorg_field))
+ {
+ const char *reorg_field_name =
+ lang_hooks.decl_printable_name ( reorg_field, 2);
+ const char *field_name =
+ lang_hooks.decl_printable_name ( field, 2);
+ //DEBUG_L("LOOK %s, %s\n", reorg_field_name, field_name);
+
+ if ( strcmp ( reorg_field_name, field_name) == 0 )
+ {
+ gcc_assert ( TREE_TYPE( field) == TREE_TYPE( TREE_TYPE(reorg_field)));
+ return reorg_field;
+ }
+ }
+ internal_error ( "find_coresponding_field: found no field");
+}
+
+static void
+remove_default_def ( tree default_def, struct function *func)
+{
+ size_t i;
+ tree ssa_name;
+ FOR_EACH_SSA_NAME ( i, ssa_name, func)
+ {
+ if ( default_def == ssa_name )
+ {
+ SSANAMES ( func)->unordered_remove ( i);
+ return;
+ }
+ }
+}
+
+static basic_block
+make_bb ( char *msg, basic_block prev_bb )
+{
+ basic_block ret = create_empty_bb ( prev_bb);
+ DEBUG_A( "make_bb ( %s, <bb %d>/%p ): <bb %d>/%p, prev: <bb %d>/%p, next: <bb %d>/%p\n",
+ msg, prev_bb->index, prev_bb,
+ ret->index, ret,
+ ret->prev_bb->index, ret->prev_bb,
+ ret->next_bb->index, ret->next_bb);
+ return ret;
+}
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..98b81acb565
--- /dev/null
+++ b/gcc/ipa-str-reorg-utils.h
@@ -0,0 +1,39 @@
+#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>
+
+#include "types-inlines.h"
+
+
+#endif
diff --git a/gcc/ipa-structure-reorg.c b/gcc/ipa-structure-reorg.c
new file mode 100644
index 00000000000..639a1e876f3
--- /dev/null
+++ b/gcc/ipa-structure-reorg.c
@@ -0,0 +1,2851 @@
+/* Interprocedural structure reorganization
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <gary@amperecomputing.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 "tree-ssa.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "gimple-collector.hpp"
+#include "gimple-escaper.hpp"
+#include "tree-pass.h"
+#include "tree-cfg.h"
+#include "cgraph.h"
+#include "dumpfile.h"
+#include "pretty-print.h"
+#include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
+#include "langhooks.h"
+#include "collect-types.h"
+#include "stor-layout.h"
+#include "tree-dfa.h"
+#include <vector>
+#include <map>
+#include <set>
+#include "ipa-structure-reorg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+
+
+static void setup_debug_flags ( Info *);
+static void initial_debug_info ( Info *);
+static void final_debug_info ( Info *);
+static unsigned int reorg_analysis ( Info *);
+static void reorg_analysis_debug ( Info *, ReorgType *);
+static bool find_decls_and_types ( Info *);
+#if USE_REORG_TYPES
+static void add_reorg_type( tree, Info *);
+#endif
+static void disqualify_struct_in_struct_or_union ( Info *);
+static void initial_reorg_debug ( 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 *);
+static unsigned int reorg_qualification ( Info *);
+static bool transformation_legality ( Info *);
+static void transformation_legality_debug ( Info *, ReorgType *);
+static bool reorg_legality ( Info *);
+static void reorg_common_middle_code ( Info *);
+static void modify_declarations ( Info *);
+static bool modify_func_decl_core ( struct function *, Info *);
+static void disqualify_all_reorgtypes_of ( gimple *, int, Info *);
+static void adjust_result_decl ( struct function *);
+static tree modify_func_type ( struct function *, Info *);
+static bool needs_modification_p ( struct function *, Info *);
+//static int number_of_levels ( tree);
+//static void modify_decl_core ( tree *, Info *);
+static void reorg_forbidden ( gimple *, Info *);
+// Name changed and moved to its own file
+//static void reorg_transformation ( Info *);
+// made extern
+//static void delete_reorgtype ( ReorgType_t *, Info *);
+//static void undelete_reorgtype ( ReorgType_t *, Info *);
+//static void remove_deleted_types ( Info *, ReorgFn);
+//static enum ReorgOpTrans recognize_op ( tree, Info *);
+//static ReorgTransformation reorg_recognize ( gimple *, Info *);
+//static bool is_reorg_type ( tree, Info *);
+//static tree base_type_of ( tree);
+static bool is_user_function ( gimple *, cgraph_node *, Info *);
+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, 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_detailed_reorgs ( FILE *, int, Info *);
+//static void print_reorg ( FILE *, int, ReorgType_t *);
+static void print_progdecls ( FILE *, int, Info *);
+static void print_progdecl ( FILE *, int, ProgDecl_t *);
+//static void print_program ( FILE *, bool, int);
+static void print_function ( FILE *, int, function *);
+static ReorgType_t *get_reorgtype( gimple *stmt, Info *, int);
+static int num_reorgtypes( gimple *, Info *);
+static bool uses_field_of_reorgtypes( gimple *, Info *);
+
+//-- debugging only --
+#if DEBUGGING
+//static const char *code_str( enum tree_code);
+static const char *type_name_to_str( tree);
+//static void handle_debug_indenting( int);
+int debug_indenting = 0;
+#endif
+//---------------- 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_L( "Running ipa_structure_reorg\n");
+ //INDENT(2);
+
+ // TBD we must have run the IPA points-to analysis and
+ // be running in a single LTRANS partition. Sanity check
+ // these here.
+
+ // TODO:
+ // Why not make this a class and avoid having all these parameters
+ // to initialize?
+ // Also, all functions should be references and not pointers...
+ Info info(&Reorg_Type, &Saved_Reorg_Type, &Prog_Decl, &StructTypes);
+ //DEBUG_L("At init dum_deleted %d\n",info.num_deleted);
+
+ cgraph_node* node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) node->get_untransformed_body ();
+
+ DEBUG_F( ssa_check, stderr, Show_everything, Do_not_fail, false, true);
+
+ setup_debug_flags ( &info);
+ initial_debug_info ( &info);
+
+ //DEBUG_L("");
+ //DEBUG_F( wolf_fence, &info);
+
+ if ( !reorg_analysis ( &info) )
+ {
+ return true;
+ }
+
+ DEBUG_L("after reorg_analysis\n");
+
+ bool qualified = reorg_qualification(&info);
+ DEBUG_L("after reorg_qualification\n");
+ //DEBUG_L("");
+ //DEBUG_F(wolf_fence, &info);
+
+
+ if ( qualified )
+ {
+ if ( flag_ipa_structure_reorg || flag_ipa_dead_field_eliminate )
+ {
+ log("before str_reorg_dead_field_eliminate_qual \n");
+ str_reorg_dead_field_eliminate_qual ( &info);
+ // Because I just want to do this now...
+ #if KLUDGE
+ return true;
+ #endif
+ }
+ if ( flag_ipa_structure_reorg || flag_ipa_field_reorder )
+ {
+ str_reorg_field_reorder_qual ( &info);
+ }
+ if ( flag_ipa_structure_reorg || flag_ipa_instance_interleave )
+ {
+ //DEBUG_L("before str_reorg_instance_interleave_qual\n");
+ str_reorg_instance_interleave_qual ( &info);
+ //DEBUG_L("after str_reorg_instance_interleave_qual\n");
+ //DEBUG_L("");
+ //DEBUG_F(wolf_fence, &info);
+
+ }
+
+ if ( info.show_all_reorg_cands_in_detail )
+ {
+ fprintf ( info.reorg_dump_file, "Qualified the following types:\n");
+ print_detailed_reorgs ( info.reorg_dump_file, 2, &info);
+ }
+
+ reorg_common_middle_code( &info); // ??? might not amount to anything
+ DEBUG_L("after reorg_common_middle_code\n");
+ //DEBUG_L("");
+ //DEBUG_F(wolf_fence, &info);
+
+ if ( flag_ipa_structure_reorg || flag_ipa_dead_field_eliminate )
+ {
+ str_reorg_dead_field_eliminate_trans ( &info);
+ }
+ if ( flag_ipa_structure_reorg || flag_ipa_field_reorder )
+ {
+ str_reorg_field_reorder_trans ( &info);
+ }
+ if ( flag_ipa_structure_reorg || flag_ipa_instance_interleave )
+ {
+ str_reorg_instance_interleave_trans ( &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_prog_decls = true;
+ 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;
+ info->reorg_dump_file = dump_file;
+ #if DEBUGGING
+ info->reorg_dump_file = stderr;
+ #endif
+ }
+}
+
+static void
+initial_debug_info ( Info *info)
+{
+ if ( info->reorg_dump_file )
+ {
+ print_program ( info->reorg_dump_file, PRINT_FORMAT, 0, info);
+ }
+}
+
+static void
+final_debug_info ( Info *info)
+{
+ if ( info->reorg_dump_file )
+ {
+ print_program ( info->reorg_dump_file, PRINT_FORMAT, 0, info);
+ }
+}
+
+static unsigned int
+reorg_analysis ( Info *info)
+{
+ // TODO:
+ // Gary, this main "analysis" method seems to have a lot of
+ // instance interleave specific code. Shouldn't this method
+ // concretely be just the escape analysis?
+
+
+ // TODO:
+ // Gary, this is me adding a way to run the escape analysis...
+ // It is only triggered when flag_ipa_structure_reorg is
+ // specified since I am not sure what this function should
+ // concretely do.
+ // Eric this is not really helping me... ;-)
+ DEBUG_L("reorg_analysis: entered\n");
+ #if INTEGRATION_FUNCTIONAL
+ const bool run_escape_analysis = flag_ipa_dead_field_eliminate && !flag_ipa_instance_interleave && !flag_ipa_field_reorder;
+ if (run_escape_analysis)
+ {
+ GimpleTypeCollector collector;
+ collector.walk();
+ ptrset_t types = collector.get_pointer_set();
+ GimpleEscaper gimpleEscaper(types);
+ gimpleEscaper.walk();
+ info->sets = gimpleEscaper.get_sets();
+ info->sets.print_in_points_to_record();
+ return true;
+ }
+ #endif
+ 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 )
+ {
+ //DEBUG_L(" tripped work around\n");
+ continue;
+ }
+ //DEBUG_L(" bypassed work around\n");
+
+ // Note,there is a major design issue with the design of this code.
+ // This can stand as is for now but it must be fixed relatively soon.
+ 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_L ( "");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ INDENT(2);
+ if ( is_gimple_call ( stmt) )
+ {
+ // next line has issues but the mechanism is sound
+ tree t = *gimple_call_lhs_ptr ( stmt);
+ DEBUG_A( "t %p\n", t);
+ // Calls to a function returning void are skipped.
+ if ( t != NULL )
+ {
+ DEBUG_A( "t: ");
+ DEBUG_F( flexible_print, stderr, t, 1, (dump_flags_t)0);
+ tree type = TREE_TYPE( t);
+ DEBUG_A( "type: ");
+ DEBUG_F( flexible_print, stderr, type, 1, (dump_flags_t)0);
+ //tree bt = base_type_of ( t);
+ tree bt = base_type_of ( type);
+ if ( TREE_CODE( bt) != RECORD_TYPE && TREE_CODE( bt) != VOID_TYPE)
+ {
+ DEBUG_A( "TREE_CODE( bt) == %s\n", code_str( TREE_CODE ( bt)));
+ DEBUG_A("");
+ DEBUG_F(flexible_print, stderr, bt, 1, (dump_flags_t)0);
+ INDENT(-2);
+ continue;
+ }
+ if ( TREE_CODE( bt) == VOID_TYPE )
+ {
+ // find the use of lhs. If is an assign
+ // get use the base type of it's lhs.
+ // Otherwise never mind.
+ gimple *use_stmt;
+ use_operand_p immuse;
+ bool yup_a_use = single_imm_use ( t, &immuse, &use_stmt);
+ DEBUG_A("VOID case: %sa single imm use, ", yup_a_use ? "" : "not ");
+ DEBUG("%san assign\n",
+ yup_a_use && is_gimple_assign ( use_stmt) ? "" : "not ");
+ if ( TREE_CODE ( t) == SSA_NAME
+ && yup_a_use
+ && is_gimple_assign ( use_stmt) )
+ {
+ tree use_lhs = gimple_assign_lhs ( use_stmt);
+ bt = base_type_of ( TREE_TYPE ( use_lhs));
+ }
+ else
+ 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) )
+ {
+ DEBUG_L( "Found allocaion: \n");
+ DEBUG_A( " Reorg: ");
+ DEBUG_F( print_reorg, stderr, 0, ri);
+ DEBUG("\n");
+ // TBD this needs to increment with the execution count
+ // instead of one. I hope the build-in block count estimation
+ // will work or a DIY solution might be called for.
+ ri->instance_interleave.numbOfDynmAllocs++;
+ }
+ }
+ }
+ INDENT(-2);
+ }
+ }
+ }
+
+ DEBUG_L( "possible deletes:\n");
+ INDENT(2);
+ // It's LOT more clear to use an iterator here TBD
+ for ( int i = 0; i < info->reorg_type->size (); i++ )
+ {
+ int n = (*(info->reorg_type))[i].instance_interleave.numbOfGlobalArrays
+ + (*(info->reorg_type))[i].instance_interleave.numbOfLocalArrays
+ + (*(info->reorg_type))[i].instance_interleave.numbOfDynmAllocs;
+ if ( n > 1 )
+ {
+ (*(info->reorg_type))[i].instance_interleave.multi_pool = true;
+ }
+ // Note when multi-pools are enabled the test should be
+ // "n == 0" but until then...
+ DEBUG_A("%d pools\n",n)
+ if ( n != 1 )
+ {
+ delete_reorgtype ( &(*(info->reorg_type))[i], info);
+ }
+ }
+ INDENT(-2);
+
+ //DEBUG_L("after reorg_analysis\n");
+ remove_deleted_types ( info, &reorg_analysis_debug);
+
+ if ( info->show_all_reorg_cands )
+ {
+ fprintf ( info->reorg_dump_file, "All Reorg Analysis ReorgTypes:\n");
+ print_reorgs ( info->reorg_dump_file, 2, info);
+ }
+
+ return !info->reorg_type->empty ();
+}
+
+void
+reorg_analysis_debug ( Info *info, ReorgType *reorg )
+{
+ if ( info->show_delete )
+ {
+ print_reorg_with_msg ( info->reorg_dump_file, reorg, 2,
+ "Was not allocated");
+ }
+}
+
+static bool
+find_decls_and_types ( Info *info)
+{
+ //DEBUG_L("find_decls_and_types: entered\n");
+
+ // 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( "Consider var->decl\n");
+ //DEBUG_L( "");
+ //DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)-1);
+ tree base = base_type_of ( decl);
+ //DEBUG( "\n");
+ //DEBUG_A("Base\n");
+ //DEBUG_A( "TREE_CODE = %s, ", 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_L( " not found\n");
+ continue;
+ } else {
+ //DEBUG_L( " found\n")
+ ;
+ }
+
+ #if USE_REORG_TYPES
+ add_reorg_type ( base, info);
+ #endif
+ typeset.insert ( base); // ???
+ }
+ }
+
+ // NOTE, the scheme above leaves out local variables so
+ // I'll repeat the for the local variable of functions.
+
+ 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. Note, not a bug...
+ //DEBUG_L( " function name = %s\n", lang_hooks.decl_printable_name ( node->decl, 2));
+ if ( fn == NULL )
+ {
+ //DEBUG_L( " EMPTY\n");
+ continue;
+ }
+
+ //INDENT(2);
+ FOR_EACH_LOCAL_DECL ( fn, i, decl)
+ {
+ tree base = base_type_of ( decl);
+ // enable this to see error in test_1_8. Note, not a bug...
+ //DEBUG_L( "Consider local var decl\n");
+ //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 () )
+ {
+ //INDENT(-2)
+ continue;
+ }
+
+ #if USE_REORG_TYPES
+ add_reorg_type ( base, info);
+ #endif
+ typeset.insert ( base); // ???
+ }
+ }
+ //INDENT(-2);
+ }
+
+ // 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 ( info->reorg_dump_file, "All possible candidates:\n");
+ print_reorgs ( info->reorg_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...
+
+ //DEBUG_L( "Scan all global decls for pointers to ReorgTypes (possible deletes)\n");
+ //INDENT(2);
+
+ FOR_EACH_VARIABLE ( var)
+ {
+ tree decl = var->decl;
+
+ //DEBUG_A( "look at each global var for undelete: ");
+ //DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)-1);
+ //DEBUG( "\n");
+
+ tree type = TREE_TYPE ( decl);
+ ReorgType_t *rtype = find_struct_type_ptr_to_struct ( type, info);
+ if ( rtype != NULL )
+ {
+ undelete_reorgtype ( rtype, info);
+ }
+ }
+ //INDENT(-2);
+
+ 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_L( "fn %p\n", fn);
+ //DEBUG_A("");
+ //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;
+ }
+
+ //DEBUG_L( "possible deletes:\n");
+ //INDENT(2);
+ FOR_EACH_LOCAL_DECL ( fn, i, decl)
+ {
+ // Does this work... see tree.c:6132
+ tree type = TREE_TYPE ( decl);
+ ReorgType_t *rtype = find_struct_type_ptr_to_struct ( type, info);
+ if ( rtype != NULL )
+ {
+ undelete_reorgtype ( rtype, info);
+ }
+ }
+ //INDENT(-2);
+ }
+
+ if ( info->show_all_reorg_cands )
+ {
+ fprintf ( info->reorg_dump_file, "All preliminary ReorgTypes:\n");
+ print_reorgs ( info->reorg_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.
+ //DEBUG_L( "Examine imbedded pointers\n");
+ //INDENT(2);
+ for ( std::vector<ReorgType_t>::iterator ri = info->reorg_type->begin ();
+ ri != info->reorg_type->end ();
+ ri++ )
+ {
+ //DEBUG_A("");
+ //DEBUG_F( dump_reorg, &(*ri));
+ //DEBUG("\n");
+ //INDENT(2);
+ for ( tree fld = TYPE_FIELDS ( ri->gcc_type);
+ fld;
+ fld = DECL_CHAIN ( fld) )
+ {
+ tree field_type = TREE_TYPE( fld);
+ ReorgType_t *rtype =
+ find_struct_type_ptr_to_struct ( field_type, info);
+ if ( rtype != NULL )
+ {
+ undelete_reorgtype ( rtype, info);
+ }
+ }
+ //INDENT(-2);
+ }
+ //INDENT(-2);
+ //DEBUG_L( "after Scan all types in ReorgTypes for structure fields\n");
+ 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 ( info->reorg_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...
+ //DEBUG_L( "ProgDecl global declarations:\n");
+ 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);
+ //DEBUG_A("");
+ //DEBUG_F( print_progdecl, stderr, 2, &decl_info);
+ }
+ }
+
+ if ( info->show_all_reorg_cands_in_detail )
+ {
+ fprintf ( info->reorg_dump_file, "find_decls_and_types: Found the following types:\n");
+ print_reorgs ( info->reorg_dump_file, 2, info);
+ }
+
+ if ( info->show_prog_decls )
+ {
+ fprintf ( info->reorg_dump_file, "ProgDecls:\n");
+ print_progdecls ( info->reorg_dump_file, 2, info);
+ }
+
+ return true;
+}
+
+#if USE_REORG_TYPES
+static void
+add_reorg_type ( tree base, Info *info)
+{
+ ReorgType_t rt =
+ { 0, true, base, NULL, NULL, false, false, false,
+ { 0}, { 0}, { 0, 0, 0, NULL, 0.0, 0.0, false}};
+
+ //DEBUG_L("add_reorg_type: ");
+ //DEBUG_F(print_generic_expr, base, (dump_flags_t)0);
+ //DEBUG("\n");
+ info->reorg_type->push_back ( rt);
+ // Remember the intial assumption is the type added will be deleted
+ // and is marked to be deleted.
+ info->num_deleted++;
+}
+#endif
+
+void
+disqualify_struct_in_struct_or_union ( Info *info)
+{
+ varpool_node *var;
+ std::set<tree> typeset;
+
+ //DEBUG_L( "In disqualify_struct_in_struct_or_union\n");
+ //INDENT(2);
+
+ FOR_EACH_VARIABLE ( var)
+ {
+ tree decl = var->decl;
+
+ //DEBUG( "type %s\n", TYPE_NAME( TREE_TYPE( 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);
+ }
+ }
+ //INDENT(-2);
+
+ // Repeating the above for local variables
+ 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);
+ //DEBUG_L( "function name = %s\n",
+ // lang_hooks.decl_printable_name ( node->decl, 2));
+ if ( fn == NULL )
+ {
+ continue;
+ }
+
+ //INDENT(2);
+ FOR_EACH_LOCAL_DECL ( fn, i, decl)
+ {
+ tree base = base_type_of ( decl);
+
+ //DEBUG_L( "local var decl: ");
+ //DEBUG_F( print_generic_decl, stderr, decl, (dump_flags_t)-1);
+ //DEBUG( "TREE_CODE( base) = %s\n", code_str( TREE_CODE ( base)));
+
+ if ( TREE_CODE ( base) == RECORD_TYPE
+ || TREE_CODE ( base) == UNION_TYPE )
+ {
+ disq_str_in_str_or_union_helper ( base, &typeset, info);
+ typeset.insert ( base);
+ }
+ }
+ //INDENT(-2);
+ }
+ //DEBUG_L("after disqualify_struct_in_struct_or_union\n");
+ 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 ( info->reorg_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 ( info->reorg_dump_file, reorg, 2,
+ "Interior Struct or Union");
+ }
+}
+
+
+static void
+disq_str_in_str_or_union_helper ( tree type,
+ std::set<tree> *typeset,
+ Info *info )
+{
+ //DEBUG_L( "In disq_str_in_str_or_union_helper (possibele deletes)\n");
+ //INDENT(2);
+
+ if ( typeset->find ( type) != typeset->end ()) return;
+ tree fld;
+ for ( tree fld = TYPE_FIELDS( type); fld; fld = DECL_CHAIN ( fld) )
+ {
+ //DEBUG_A( ": ", DECL_NAME( fld));
+ //DEBUG_F( print_generic_decl, stderr, fld, (dump_flags_t)-1);
+ //DEBUG_F( print_generic_decl, stderr, fld, (dump_flags_t)-1);
+ //DEBUG( " -- ");
+ //INDENT(2);
+
+ // If we go to the base we end up disqualifying pointer to reorganizable
+ // structure. That's not what we want!
+ tree field_type = TREE_TYPE( fld);
+ //tree base = base_type_of ( field_type);
+ if ( TREE_CODE ( field_type) == RECORD_TYPE ) // base to field type
+ {
+ DEBUG( "RECORD\n");
+
+ ReorgType_t *rinfo = get_reorgtype_info ( field_type, info); // base to field type
+ if ( rinfo != NULL )
+ {
+ delete_reorgtype ( rinfo, info);
+ } else {
+ disq_str_in_str_or_union_helper ( field_type, typeset, info ); // base to field type
+ typeset->insert ( field_type); // might be bug here -- base to field type
+ }
+ } else {
+ if ( TREE_CODE ( field_type) == UNION_TYPE ) { // base to field type
+ //DEBUG( "UNION\n");
+
+ disq_str_in_str_or_union_helper ( field_type, typeset, info ); // base to field type
+ typeset->insert ( field_type); // might be bug here -- base to field type
+ } else {
+ //DEBUG( "%s\n", code_str( TREE_CODE ( field_type)) ); // base to field type
+ }
+ }
+ //INDENT(-2);
+ }
+ //INDENT(-2);
+
+ return;
+}
+
+static unsigned int
+reorg_qualification ( Info *info)
+{
+ // TBD
+ // This only does a generic legality qualification and each
+ // subpass does its own performance qualification.
+ log("before reorg_leaglity...\n");
+ unsigned int retval = reorg_legality( info);
+ log("after reorg_leaglity...\n");
+ return retval;
+
+}
+
+// Return false if nothing qualified
+bool
+reorg_legality( Info *info) {
+ log("before transformation leagality...\n");
+ bool retval = transformation_legality( info);
+ log("after transformation leagality...\n");
+ return retval;
+}
+
+bool
+Info::is_non_escaping_set_empty()
+{
+ bool retval = this->sets.non_escaping.empty();
+ return retval;
+}
+
+// Return false if nothing qualified
+// TODO:
+// What exactly is the difference between legality and
+// non_escaping?
+bool
+transformation_legality ( Info *info)
+{
+ //TODO: Gary, for my purposes, I need to start running the
+ // code related to dead field eliminate. So, I'll add this bit
+ //
+ // TODO:
+ // * Legality must include type-casting
+ // * Legality must include address ??
+ // * What about memmove?
+ //
+ // struct astruct_s { _Bool a; _Bool b; _Bool c; };
+ // struct astruct_s astruct_1;
+ // struct astruct_s astruct_2;
+ // GIMPLE_IL sizeof tree expr
+ // memmove(&astruct_1, &astruct_2, sizeof(struct astruct_s));
+ // memmove(&astruct_1.b, &astruct_2.b, 2*sizeof(_Bool));
+ const bool run_escape_analysis = flag_ipa_dead_field_eliminate && !flag_ipa_instance_interleave && !flag_ipa_field_reorder;
+ if (run_escape_analysis)
+ {
+ bool retval = !info->is_non_escaping_set_empty();
+ return retval;
+ }
+
+ cgraph_node* node;
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ basic_block bb;
+
+ 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);
+ int num = num_reorgtypes ( stmt, info);
+ if ( num != 0 )
+ {
+ ReorgTransformation trans = reorg_recognize( stmt, node, info);
+ switch ( trans )
+ {
+ case Not_Supported:
+ //DEBUG_L("deleting %d reorgs for unsuported stmt: ", num);
+ //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ disqualify_all_reorgtypes_of ( stmt, num, info);
+ case ReorgT_UserFunc:
+ // TBD ReorgT_Ptr2Zero does not catch all cases of
+ // setting a reorg pointer to zero. One that I
+ // discoivered in a dump is phis can hold constanst.
+ break;
+ case ReorgT_Return:
+ // TBD ReorgT_Ptr2Zero does not catch all cases of
+ // setting a reorg pointer to zero. One that I
+ // discoivered in a dump is phis can hold constanst.
+ break;
+ case ReorgT_Convert:
+ // TBD Note, any conversion of an integer type to a
+ // reorg pointer type can obsure the zero transformation
+ // and needs to disqualify the type.
+ break;
+ default:
+ // No problem.
+ ;
+ }
+ }
+ if ( uses_field_of_reorgtypes( stmt, info) )
+ {
+ // This will mark types to be deleted if need be.
+ reorg_forbidden ( stmt, info );
+ }
+ }
+ }
+
+ // TBD Walk the PHIs looking for reorg type PHIs with a
+ // nonzero constant. Disqualify any typeas this happens with.
+ }
+
+ //DEBUG_L("after transformation_legality\n");
+ remove_deleted_types ( info, &transformation_legality_debug);
+
+ return !info->reorg_type->empty ();
+}
+
+void
+transformation_legality_debug ( Info *info, ReorgType *reorg )
+{
+ if ( info->show_delete )
+ {
+ print_reorg_with_msg ( info->reorg_dump_file, reorg, 2,
+ "Unallowed transformation");
+ }
+}
+
+static void
+reorg_common_middle_code ( Info *info)
+{
+ modify_declarations( info);
+}
+
+static void
+modify_declarations ( Info *info)
+{
+ // For the moment we ignore initializations assuming
+ // all potential reorg types that had initialized
+ // arrays were disqualified. Note, it's the way
+ // to go until statically allocated arrays are optimized
+ // Once we attempt statically allocated arrays problems
+ // crop up because some initializations aren't preserved
+ // until LTRANS time and even those that are don't necessarily
+ // lend themselves to any necessary reorg transformation.
+ // Note, it's possible to preserve them, if that makes sense,
+ // in remove_unreferenced_decls.
+ std::vector<ProgDecl_t>::iterator pv;
+ for ( pv = info->prog_decl->begin ();
+ pv != info->prog_decl->end (); pv++ )
+ {
+ modify_decl_core ( &( pv->gcc_decl), info);
+ }
+
+ // NOTE, Call modufy_decl_core breaks hello world!
+
+ // Modify the declaration of the function type itself.
+ // Note, create a new declaration if necessary. If this
+ // loop already created and the function is seen a second
+ // time reuse the previous one created.
+
+ // Note, most of the function type stuff can use memoization but
+ // it's not worth doing unless it proves to be a significant
+ // performance issue. This is what fncache is all about. But it's
+ // used not to save time but to guarantee that if two functions have
+ // the same type before this exercise, their new types will be
+ // equal afterwards.
+ std::map <tree,tree> fncache;
+
+ struct cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func); // Is this necessary?
+ tree curr_func_type = TREE_TYPE ( func->decl);
+
+ #if 0
+ modify_func_decl_core ( func, info);
+ #else
+
+ // TBD Check cached function type. If the decl's type
+ // has been modified use the cached new type.
+ auto location = fncache.find ( curr_func_type);
+ tree old_ret_type = TREE_TYPE ( TREE_TYPE ( func->decl));
+ if ( location != fncache.end () )
+ {
+ TREE_TYPE ( func->decl) = location->second;
+
+ // The function type can be cached but this must be created
+ // anew for any function who's return type has changed
+ if ( old_ret_type != TREE_TYPE ( TREE_TYPE ( func->decl)) )
+ {
+ adjust_result_decl ( func);
+ }
+
+ pop_cfun ();
+ continue;
+ }
+
+ // check if funtion type needs modification.
+ if ( needs_modification_p ( func, info) )
+ {
+ // Create new type and set the decl's type to it.
+ tree new_func_type = modify_func_type ( func, info);
+
+ if ( old_ret_type != TREE_TYPE ( new_func_type))
+ {
+ adjust_result_decl ( func);
+ }
+
+ // Add the type to the cache.
+ fncache [ curr_func_type] = new_func_type;
+ }
+ #endif
+ pop_cfun ();
+ }
+
+ // Note, do not relayout functions decls....
+}
+
+static void
+disqualify_all_reorgtypes_of ( gimple *stmt, int num, Info *info)
+{
+ DEBUG_L("disqualify %d reorgtypes of: ", num);
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ int i;
+ for ( i = 0; i < num; i++ )
+ {
+ ReorgType_t *reorg_type =
+ get_reorgtype ( stmt, info, i);
+ delete_reorgtype ( reorg_type, info);
+ }
+}
+
+static void
+adjust_result_decl ( struct function *func)
+{
+ tree func_decl = func->decl;
+ tree ret_type = TREE_TYPE ( TREE_TYPE ( func_decl));
+ tree decl_result;
+
+ decl_result =
+ build_decl ( DECL_SOURCE_LOCATION ( func_decl),
+ RESULT_DECL, NULL_TREE, ret_type);
+ DECL_RESULT ( func_decl) = decl_result;
+ DECL_CONTEXT ( decl_result) = func_decl;
+}
+
+
+static tree
+modify_func_type ( struct function *func, Info *info )
+{
+ tree func_type = TREE_TYPE ( func->decl);
+ DEBUG_L("old func_type = ");
+ DEBUG_F( flexible_print, stderr, func_type, 1, (dump_flags_t)0);
+ INDENT(4);
+ tree new_type;
+ tree func_ret_type = TREE_TYPE ( func_type);
+ tree base = base_type_of ( func_ret_type);
+
+ ReorgType_t *ri = get_reorgtype_info ( base, info);
+ if ( ri != NULL )
+ {
+ // TBD Do level based stuff here
+ if ( number_of_levels ( func_ret_type ) == 1 )
+ {
+ func_ret_type = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+ else
+ {
+ gcc_assert(0);
+ }
+ }
+ tree arg;
+ tree new_args = NULL_TREE;
+ //DEBUG_A("old arg = ");
+ //DEBUG_F( flexible_print, stderr, arg, 1, (dump_flags_t)0);
+ for ( arg = TYPE_ARG_TYPES ( func_type);
+ arg != NULL && arg != void_list_node;
+ arg = TREE_CHAIN ( arg))
+ {
+ //DEBUG_L("arg: ");
+ //DEBUG_F( flexible_print, stderr, arg, 1, (dump_flags_t)0);
+
+ tree type_of_arg = TREE_VALUE (arg);
+ //DEBUG_L("type_of_arg: ");
+ //DEBUG_F( flexible_print, stderr, type_of_arg, 1, (dump_flags_t)0);
+ base = base_type_of ( type_of_arg);
+ //DEBUG_L("base: ");
+ //DEBUG_F( flexible_print, stderr, base, 1, (dump_flags_t)0);
+
+ tree new_arg_type;
+ ri = get_reorgtype_info ( base, info);
+ if ( ri != NULL )
+ {
+ if ( number_of_levels ( type_of_arg ) == 1 )
+ {
+ new_arg_type = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+ else
+ {
+ gcc_assert(0);
+ }
+ }
+ else
+ {
+ new_arg_type = type_of_arg;
+ }
+ new_args = tree_cons ( NULL_TREE, new_arg_type, new_args);
+ //DEBUG_A("interim new_args = ");
+ //DEBUG_F( flexible_print, stderr, new_args, 1, (dump_flags_t)0);
+ }
+ //DEBUG_A("before reverse new_args = ");
+ //DEBUG_F( flexible_print, stderr, new_args, 1, (dump_flags_t)0);
+ tree last = new_args;
+ new_args = nreverse ( new_args);
+ TREE_CHAIN ( last) = void_list_node;
+
+ DEBUG_A("new args = ");
+ DEBUG_F( flexible_print, stderr, new_args, 1, (dump_flags_t)0);
+ INDENT(-4);
+
+ new_type = build_function_type ( func_ret_type, new_args);
+ DEBUG_L("new_type (func) = ");
+ DEBUG_F( flexible_print, stderr, new_type, 1, (dump_flags_t)0);
+ TREE_TYPE ( func->decl) = new_type;
+ return new_type;
+}
+
+static bool
+needs_modification_p ( struct function *func, Info *info )
+{
+ tree func_type = TREE_TYPE ( func->decl);
+ tree ret_type = TREE_TYPE ( func_type);
+ tree base = base_type_of ( ret_type);
+ if ( get_reorgtype_info ( base, info) != NULL ) return true;
+
+ tree arg;
+ for ( arg = TYPE_ARG_TYPES ( func_type); arg != NULL; arg = TREE_CHAIN ( arg))
+ {
+ base = base_type_of ( ret_type);
+ if ( get_reorgtype_info ( base, info) != NULL ) return true;
+ }
+
+ return false;
+}
+
+int
+number_of_levels ( tree type)
+{
+tree prev_type;
+ int levels = 0;
+ for ( ; TREE_CODE ( type) == POINTER_TYPE; levels++ )
+ {
+ prev_type = type;
+ type = TREE_TYPE ( prev_type);
+ //DEBUG_A( "prev_type: %p, type: %p\n", prev_type, type);
+ }
+ //DEBUG_A("number_of_levels = %d\n", levels);
+ return levels;
+}
+
+static bool
+modify_func_decl_core ( struct function *func, Info *info)
+{
+ //DEBUG_L("BEFORE modify_func_decl_core:\n");
+ //INDENT(4);
+ //DEBUG_A("func->decl = %p, ", func->decl);
+ //DEBUG_F( flexible_print, stderr, func->decl, 1, (dump_flags_t)0);
+ //DEBUG_A("TREE_TYPE (func->decl) = %p, ", TREE_TYPE (func->decl));
+ //DEBUG_F( flexible_print, stderr, TREE_TYPE (func->decl), 1, (dump_flags_t)0);
+ //DEBUG_A("TREE_TYPE(TREE_TYPE (func->decl)) = %p, ", TREE_TYPE(TREE_TYPE (func->decl)));
+ //DEBUG_F( flexible_print, stderr, TREE_TYPE(TREE_TYPE (func->decl)), 1, (dump_flags_t)0);
+ // TBD Implement
+ tree *func_type_loc = &(TREE_TYPE(TREE_TYPE (func->decl)));
+ tree func_type = *func_type_loc;
+ tree base = base_type_of ( func_type);
+
+ ReorgType_t *ri = get_reorgtype_info ( base, info);
+ if ( ri == NULL )
+ {
+ //DEBUG_A("Return as not a reorg type.\n");
+ //INDENT(-4);
+ return false;
+ }
+ //DEBUG_A("pointer_rep = ");
+ //DEBUG_F( flexible_print, stderr, ri->pointer_rep, 1, (dump_flags_t)0);
+ //DEBUG_A("TYPE_MAIN_VARIANT( pointer_rep) = ");
+ //DEBUG_F( flexible_print, stderr, TYPE_MAIN_VARIANT( ri->pointer_rep), 1, (dump_flags_t)0);
+
+ int levels = number_of_levels ( func_type);
+
+ // TBD This code must in the near future handle an
+ // abritary number of levels!
+ if ( levels == 1 )
+ {
+ //DEBUG_A( "levels == 1\n");
+ // Why type main variant pointer_rep ???
+ // We created it!
+ gcc_assert ( TYPE_MAIN_VARIANT ( ri->pointer_rep));
+ //TREE_TYPE( *func_type_loc) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ //*func_type_loc = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ TREE_TYPE ( TREE_TYPE ( func->decl)) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+ else
+ {
+ //DEBUG_A( "levels != 1\n");
+ gcc_assert(0);
+ }
+
+ //DEBUG_L("AFTER modify_func_decl_core:\n");
+ //DEBUG_A("func->decl = %p, ", func->decl);
+ //DEBUG_F( flexible_print, stderr, func->decl, 1, (dump_flags_t)0);
+ //DEBUG_A("TREE_TYPE (func->decl) = %p, ", TREE_TYPE (func->decl));
+ //DEBUG_F( flexible_print, stderr, TREE_TYPE (func->decl), 1, (dump_flags_t)0);
+ //DEBUG_A("TREE_TYPE(TREE_TYPE (func->decl)) = %p, ", TREE_TYPE(TREE_TYPE (func->decl)));
+ //DEBUG_F( flexible_print, stderr, TREE_TYPE(TREE_TYPE (func->decl)), 1, (dump_flags_t)0);
+
+ //INDENT(-4);
+ return true;
+}
+
+// Returns true if a modification occurred
+#if 1
+// Dubious version
+bool
+modify_decl_core ( tree *location, Info *info)
+{
+ //DEBUG_L("before modify_decl_core: ");
+ //DEBUG_F( flexible_print, stderr, *location, 1, (dump_flags_t)0);
+ tree type = *location;
+ //DEBUG_A("type = ");
+ //DEBUG_F( flexible_print, stderr, type, 0, (dump_flags_t)0);
+ tree base = base_type_of ( type);
+ //DEBUG_A(", base = ");
+ //DEBUG_F( flexible_print, stderr, base, 1, (dump_flags_t)0);
+ ReorgType_t *ri = get_reorgtype_info ( base, info);
+ if ( ri == NULL )
+ {
+ return false;
+ }
+
+ // array case -- not doing non-dynamically
+ // allocated arrays yet so this case won't
+ // currently occur
+
+ // borrowed from wrangle_ssa_type
+ tree prev_type;
+ int levels;
+ for ( levels = 0; TREE_CODE ( type) == POINTER_TYPE; levels++ )
+ {
+ prev_type = type;
+ type = TREE_TYPE ( prev_type);
+ //DEBUG_L( "prev_type: %p, type: %p\n", prev_type, type);
+ }
+ // TBD might use build_pointer_type to build new type for *(N)reorg_type
+ // to *(N-1)ri->pointer_rep
+ // Fakes this for levels == 1
+ if ( levels == 0) // How did this test ever work???? It didn't
+ //if ( levels == 1)
+ {
+ //DEBUG_L( "LEVEL ONE\n");
+ //modify_ssa_name_type ( side, ri->pointer_rep);
+ gcc_assert ( TYPE_MAIN_VARIANT ( ri->pointer_rep));
+ //TREE_TYPE ( *location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ TREE_TYPE(*location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+ else
+ {
+ //DEBUG_L( "LEVEL > ONE\n");
+ gcc_assert(0);
+ }
+
+ if ( DECL_INITIAL ( *location) != NULL )
+ {
+ // Note this assumes the levels code above is not general
+ DECL_INITIAL ( *location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+
+ relayout_decl ( *location);
+
+ //DEBUG_L(" after modify_decl_core");
+ //DEBUG_F( print_generic_decl, stderr, *location, (dump_flags_t)0);
+ //DEBUG("\n");
+ return true;
+}
+#else
+// Nodubious version
+bool
+modify_decl_core ( tree *location, Info *info)
+{
+ //DEBUG_L("before modify_decl_core: ");
+ //DEBUG_F( flexible_print, stderr, *location, 1, (dump_flags_t)0);
+ tree type = *location;
+ //DEBUG_A("type = ");
+ //DEBUG_F( flexible_print, stderr, type, 0, (dump_flags_t)0);
+ tree base = base_type_of ( type);
+ //DEBUG_A(", base = ");
+ //DEBUG_F( flexible_print, stderr, base, 1, (dump_flags_t)0);
+ ReorgType_t *ri = get_reorgtype_info ( base, info);
+ if ( ri == NULL )
+ {
+ return false;
+ }
+
+ // array case -- not doing non-dynamically
+ // allocated arrays yet so this case won't
+ // currently occur
+
+ // borrowed from wrangle_ssa_type
+ tree prev_type;
+ int levels;
+ for ( levels = 0; TREE_CODE ( type) == POINTER_TYPE; levels++ )
+ {
+ prev_type = type;
+ type = TREE_TYPE ( prev_type);
+ //DEBUG_L( "prev_type: %p, type: %p\n", prev_type, type);
+ }
+ // TBD might use build_pointer_type to build new type for *(N)reorg_type
+ // to *(N-1)ri->pointer_rep
+ // Fakes this for levels == 1
+ if ( levels == 0) // How did this test ever work???? It didn't
+ //if ( levels == 1)
+ {
+ //DEBUG_L( "LEVEL ONE\n");
+ //modify_ssa_name_type ( side, ri->pointer_rep);
+ gcc_assert ( TYPE_MAIN_VARIANT ( ri->pointer_rep));
+ //TREE_TYPE ( *location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ TREE_TYPE(*location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+ else
+ {
+ //DEBUG_L( "LEVEL > ONE\n");
+ gcc_assert(0);
+ }
+
+ if ( DECL_INITIAL ( *location) != NULL )
+ {
+ // Note this assumes the levels code above is not general
+ DECL_INITIAL ( *location) = TYPE_MAIN_VARIANT ( ri->pointer_rep);
+ }
+
+ relayout_decl ( *location);
+
+ //DEBUG_L(" after modify_decl_core");
+ //DEBUG_F( print_generic_decl, stderr, *location, (dump_flags_t)0);
+ //DEBUG("\n");
+ return true;
+}
+#endif
+
+void
+delete_reorgtype ( ReorgType_t *rt, Info *info )
+{
+ DEBUG_L( "delete_reorgtype( %s ):", type_name_to_str( TYPE_NAME( rt->gcc_type)));
+ if ( !rt->delete_me )
+ {
+ DEBUG( "TO DELETE\n");
+ info->num_deleted++;
+ rt->delete_me = true;
+ } else {
+ DEBUG( "SKIP\n");
+ }
+}
+
+void
+undelete_reorgtype ( ReorgType_t *rt, Info *info )
+{
+ //DEBUG_L( "undelete_reorgtype( %s ): ", type_name_to_str( TYPE_NAME( rt->gcc_type)));
+ if ( rt->delete_me )
+ {
+ //DEBUG( "UNDELETE\n");
+ info->num_deleted--;
+ rt->delete_me = false;
+ } else {
+ //DEBUG( "SKIP\n");
+ }
+}
+
+ReorgTransformation
+reorg_recognize ( gimple *stmt, cgraph_node* node, Info_t *info )
+{
+ DEBUG_L ( "ReorgTransformation reorg_recognize for: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ INDENT(2);
+ switch ( gimple_code( stmt) )
+ {
+ case GIMPLE_ASSIGN:
+ {
+ DEBUG_L("GIMPLE_ASSIGN:\n");
+ tree lhs = gimple_assign_lhs ( stmt);
+ enum tree_code rhs_code = gimple_assign_rhs_code ( stmt);
+
+ if ( gimple_assign_single_p ( stmt) )
+ {
+ DEBUG_L("gimple_assign_single_p() = true\n");
+ INDENT(2);
+ tree rhs = gimple_assign_rhs1 ( stmt);
+ enum ReorgOpTrans lhs_op = recognize_op ( lhs, info);
+ switch ( lhs_op )
+ {
+ case ReorgOpT_Pointer: // "a"
+ DEBUG_L("case ReorgOpT_Pointer\n");
+ INDENT(-4);
+ switch ( recognize_op ( rhs, info) )
+ {
+ case ReorgOpT_Scalar:
+ if ( integer_zerop ( rhs) )
+ {
+ return ReorgT_Ptr2Zero;
+ }
+ // If we get here this is clearly really odd code
+ // so we need to bail out.
+ return Not_Supported;
+ case ReorgOpT_Temp: // t
+ return ReorgT_ElemAssign;
+ case ReorgOpT_Address: // "&x[i]"
+ return ReorgT_Adr2Ptr;
+ default:
+ return Not_Supported;
+ }
+ case ReorgOpT_Struct: // "s"
+ DEBUG_L("case ReorgOpT_Struct\n");
+ INDENT(-4);
+ switch ( recognize_op ( rhs, info) )
+ {
+ case ReorgOpT_Deref: // "*a"
+ case ReorgOpT_Array: // "x[i]"
+ // Technically with a struct on both sides
+ // this could be ignored but it's
+ // better to do this at transform time.
+ // With the case commented out test_09_23
+ // exposes a bug.
+ case ReorgOpT_Struct: // "s"
+ return ReorgT_StrAssign;
+ default:
+ return Not_Supported;
+ }
+ case ReorgOpT_Deref: // "*a"
+ DEBUG_L("case ReorgOpT_Deref\n");
+ INDENT(-4);
+ switch ( recognize_op ( rhs, info) )
+ {
+ case ReorgOpT_Deref: // "*a"
+ case ReorgOpT_Struct: // "s"
+ case ReorgOpT_Array: // "x[i]"
+ return ReorgT_StrAssign;
+ default:
+ return Not_Supported;
+ }
+ case ReorgOpT_Array: // "x[i]"
+ DEBUG_L("case ReorgOpT_Array\n");
+ INDENT(-4);
+ switch ( recognize_op ( rhs, info) )
+ {
+ case ReorgOpT_Struct: // "s"
+ case ReorgOpT_Deref: // "*a"
+ case ReorgOpT_Array: // "x[i]"
+ return ReorgT_StrAssign;
+ default:
+ return Not_Supported;
+ }
+ case ReorgOpT_Temp: // t
+ case ReorgOpT_Scalar: // "z"
+ DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Temp ? "Temp" : "Scalar");
+ INDENT(-4);
+ switch ( recognize_op( rhs, info) )
+ {
+ case ReorgOpT_Scalar: // "z"
+ case ReorgOpT_Temp: // "t"
+ case ReorgOpT_Indirect: // "a->f"
+ case ReorgOpT_AryDir: // "x[i].f"
+ return ReorgT_ElemAssign;
+ default:
+ return Not_Supported;
+ }
+ case ReorgOpT_Indirect: // "a->f"
+ case ReorgOpT_AryDir: // "x[i].f"
+ DEBUG_L("case ReorgOpT_%s\n", lhs_op == ReorgOpT_Indirect ? "Indirect" : "AryDir");
+ INDENT(-4);
+ switch ( recognize_op ( rhs, info) )
+ {
+ case ReorgOpT_Temp: // t
+ case ReorgOpT_Scalar: // "z"
+ case ReorgOpT_Indirect: // "a->f"
+ case ReorgOpT_AryDir: // "x[i].f"
+ return ReorgT_ElemAssign;
+ default:
+ return Not_Supported;
+ }
+ default:
+ INDENT(-4);
+ return Not_Supported;
+ } // switch ( recognize_op ( lhs, info) )
+ } else {
+ DEBUG_L("gimple_assign_single_p() = false\n");
+ INDENT(2);
+ tree op1 = gimple_assign_rhs1 ( stmt);
+ tree op2 = gimple_assign_rhs2 ( stmt);
+ DEBUG_L("op1 = %p, op2 = %p\n", op1, op2);
+ DEBUG_A("");
+ DEBUG_F( print_generic_expr, stderr, op1, (dump_flags_t)-1);
+ DEBUG("\n");
+
+ if ( CONVERT_EXPR_CODE_P ( gimple_assign_rhs_code ( stmt)))
+ {
+ DEBUG_L("CONVERT_EXPR_CODE_P (...)\n");
+ INDENT(-4);
+ return ReorgT_Convert;
+ }
+
+ if ( gimple_assign_rhs3 ( stmt) != NULL )
+ {
+ DEBUG_L("gimple_assign_rhs3 ( stmt) != NULL\n");
+ INDENT(-4);
+ return Not_Supported;
+ }
+
+ // TBD The parenthesis where a disaster here in the HL Design so
+ // double check this!
+ bool zero_case =
+ ( (POINTER_TYPE_P ( TREE_TYPE( op1)) && integer_zerop ( op2))
+ || (POINTER_TYPE_P ( TREE_TYPE( op2)) && integer_zerop ( op1)))
+ && ( integer_zerop ( op1) || integer_zerop ( op2) );
+ DEBUG_L("zero_case = %s\n", zero_case ? "true" : "false" );
+ INDENT(-4);
+ switch ( rhs_code )
+ {
+ case POINTER_PLUS_EXPR:
+ return ReorgT_PtrPlusInt;
+ case POINTER_DIFF_EXPR:
+ return ReorgT_PtrDiff;
+ case EQ_EXPR:
+ return zero_case ? ReorgT_PtrNull : ReorgT_PtrEQ;
+ case NE_EXPR:
+ return zero_case ? ReorgT_PtrNotNull : ReorgT_PtrNE;
+ case LE_EXPR:
+ return ReorgT_PtrLE;
+ case LT_EXPR:
+ return ReorgT_PtrLT;
+ case GE_EXPR:
+ return ReorgT_PtrGE;
+ case GT_EXPR:
+ return ReorgT_PtrGT;
+ default:
+ return Not_Supported;
+ }
+ } // } else {
+ }
+ case GIMPLE_COND: // Similar to assign cases
+ {
+ //DEBUG_L("GIMPLE_COND:\n");
+ //INDENT(-2);
+ //tree op1 = gimple_assign_rhs1 ( stmt);
+ //tree op2 = gimple_assign_rhs2( stmt);
+ tree op1 = gimple_cond_lhs ( stmt);
+ tree op2 = gimple_cond_rhs ( stmt);
+ enum tree_code cond_code = gimple_cond_code (stmt);
+ // TBD The parenthesis were a disaster here in the HL Design so
+ // double check this!
+ bool zero_case =
+ ( POINTER_TYPE_P ( TREE_TYPE ( op1)) && integer_zerop ( op2))
+ || ( POINTER_TYPE_P ( TREE_TYPE ( op2)) && integer_zerop ( op1));
+ switch ( cond_code )
+ {
+ case EQ_EXPR:
+ return zero_case ? ReorgT_If_Null : ReorgT_IfPtrEQ;
+ case NE_EXPR:
+ return zero_case ? ReorgT_If_NotNull : ReorgT_IfPtrNE;
+ case LE_EXPR:
+ return ReorgT_IfPtrLE;
+ case LT_EXPR:
+ return ReorgT_IfPtrLT;
+ case GE_EXPR:
+ return ReorgT_IfPtrGE;
+ case GT_EXPR:
+ return ReorgT_IfPtrGT;
+ default:
+ return Not_Supported;
+ }
+ }
+ case GIMPLE_CALL:
+ {
+ DEBUG_L("GIMPLE_CALL:\n");
+ struct cgraph_edge *edge = node->get_edge ( stmt);
+ gcc_assert( edge);
+ DEBUG_L("called function %s gimple_body\n",
+ edge->callee->has_gimple_body_p() ? "has a" : "has no");
+ INDENT(-2);
+ if ( gimple_call_builtin_p( stmt, BUILT_IN_CALLOC ) ) return ReorgT_Calloc;
+ if ( gimple_call_builtin_p( stmt, BUILT_IN_MALLOC ) ) return ReorgT_Malloc;
+ if ( gimple_call_builtin_p( stmt, BUILT_IN_REALLOC) ) return ReorgT_Realloc;
+ if ( gimple_call_builtin_p( stmt, BUILT_IN_FREE ) ) return ReorgT_Free;
+
+ // Instead of just returning Not_Supported we need to
+ // determine if it's a user defined function in which case the
+ // transformation is meaningless but the type still needs to be
+ // adjusted (does transform really do this?)
+
+ if ( is_user_function ( stmt, node, info) )
+ {
+ return ReorgT_UserFunc;
+ }
+
+ return Not_Supported;
+ }
+ break;
+ case GIMPLE_RETURN:
+ DEBUG_L("GIMPLE_RETURN:\n");
+ INDENT(-2);
+ return ReorgT_Return;
+ break;
+ default:
+ DEBUG_L ( "didn't support: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ DEBUG( "\n");
+ INDENT(-2);
+ return Not_Supported;
+ }
+}
+
+static bool
+is_user_function ( gimple *call_stmt, cgraph_node* node, Info *info)
+{
+ // I'm not 100% sure this is a great idea but it means that
+ // if we know nothing about the contents of a function
+ // then it shouldn't be considered a user written function
+ // that is part of our program.
+ struct cgraph_edge *ce;
+ ce = node->get_edge ( call_stmt);
+ return ce->callee->has_gimple_body_p();
+}
+
+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 ();
+ }
+}
+
+// This routine disqualifies any and all reorg
+// types in it that deserve disqualification.
+// There are bizarre circumstances that could disqualify
+// many types in a single statement.
+void
+reorg_forbidden ( gimple *stmt, Info *info )
+{
+ // The recognition of forbidden patterns must include casting a
+ // pointer (i.e. a pointer into a Reorg field) to something of a
+ // larger size (e.g. ints to longs) or doing arithmetic with them
+ // (e.g. bar->foo + k) since the later assumes the structure
+ // layout has not changed.
+#if 0
+ // TBD
+ switch( gimple_code( stmt) ) {
+ case :
+ }
+#endif
+}
+
+void
+remove_deleted_types ( Info *info, ReorgFn reorg_fn)
+{
+ //DEBUG_L( "remove_deleted_types: %d to delete of %d types\n", info->num_deleted, info->reorg_type->size ());
+ if ( info->show_delete )
+ {
+ fprintf ( info->reorg_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;
+ //INDENT(2);
+ for ( int from = 0; from < n; from++ )
+ {
+ //DEBUG_L( "%s ", type_name_to_str( TYPE_NAME( (*(info->reorg_type))[from].gcc_type)));
+ //DEBUG( "< from %d, to %d > - ", from, to);
+
+ if ( !(*(info->reorg_type))[from].delete_me )
+ {
+ //DEBUG( "NOT DELETED %d\n", from);
+
+ // 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];
+ //DEBUG_A( " move from -> to\n");
+ }
+
+ to++;
+ } else {
+ //DEBUG( "DELETE %d\n", from);
+ }
+ }
+ //INDENT(-2);
+ info->reorg_type->resize ( n - info->num_deleted);
+ info->num_deleted = 0;
+ }
+}
+
+enum ReorgOpTrans
+recognize_op ( tree op, Info *info)
+{
+ DEBUG_L("recognize_op: ");
+ DEBUG_F( flexible_print, stderr, op, 1, TDF_DETAILS);
+ enum tree_code op_code = TREE_CODE ( op);
+ DEBUG_A("opcode = %s\n", code_str( op_code));
+ if ( op_code == SSA_NAME )
+ {
+ // We tried returning ReorgOpT_Scalar.
+ // It caused an assertion failue because
+ // it was incorrectly triggering the ReorgT_Ptr2Zero
+ // case with a bogus RHS.
+ DEBUG_L(" returns: ReorgOpT_Temp\n");
+ return ReorgOpT_Temp;
+ }
+ tree type = TREE_TYPE ( op);
+ if ( type != NULL && POINTER_TYPE_P (type) )
+ {
+ DEBUG_L("POINTER_TYPE_P (type) = true\n");
+ if ( is_reorg_type ( type, info) )
+ {
+ DEBUG_L(" returns: ReorgOpT_Pointer\n");
+ return ReorgOpT_Pointer;
+ } else {
+ // This would be for when
+ // the field of a struct element
+ // is a pointer that's not a reorg
+ // point. I.e. ReorgT_ElemAssign.
+ DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ }
+ // This might not occur in practice
+ if ( op_code == RECORD_TYPE )
+ {
+ // The assumption here is that this
+ // is a reorg type.
+ DEBUG_L(" returns: ReorgOpT_Struct\n");
+ return ReorgOpT_Struct;
+ }
+ if ( op_code == VAR_DECL )
+ {
+ tree type = TREE_TYPE ( op);
+ DEBUG_L(" recursing on type :");
+ DEBUG_F( flexible_print, stderr, type, 1, TDF_DETAILS);
+ return recognize_op ( type, info);
+ }
+ tree inner_op = TREE_OPERAND( op, 0);
+ tree inner_type = TREE_TYPE ( inner_op);
+ enum tree_code inner_op_code = TREE_CODE ( inner_op);
+ //DEBUG_L("inner_op = ");
+ //DEBUG_F( print_generic_expr, stderr, inner_op, TDF_DETAILS);
+ //DEBUG(", TREE_CODE = %s\n", code_str( TREE_CODE(inner_op)));
+ if ( op_code == ADDR_EXPR )
+ {
+ //DEBUG_L("op_code == ADDR_EXPR\n");
+ if ( inner_op_code == ARRAY_REF
+ && is_reorg_type ( inner_op, info) )
+ {
+ //DEBUG_L(" returns: ReorgOpT_Address\n");
+ return ReorgOpT_Address;
+ }
+ }
+ if ( op_code == COMPONENT_REF )
+ {
+ //DEBUG_L("op_code == COMPONENT_REF\n");
+ if ( inner_op_code == INDIRECT_REF )
+ {
+ //DEBUG_L("TREE_CODE( inner_op) == INDIRECT_REF\n");
+ if ( is_reorg_type ( base_type_of ( type), info) ) // inner_type???
+ {
+ //DEBUG_L(" returns: ReorgOpT_Indirect\n");
+ return ReorgOpT_Indirect;
+ }
+ // Just normal field reference otherwise...
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ if ( inner_op_code == MEM_REF ) {
+ //DEBUG_L("TREE_CODE( inner_op) == MEM_REF\n");
+ if ( is_reorg_type ( base_type_of ( inner_type), info) )
+ {
+ //DEBUG_L(" returns: ReorgOpT_Indirect\n");
+ return ReorgOpT_Indirect;
+ }
+ // Just normal field reference otherwise...
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ DEBUG_L("TREE_CODE( inner_op) not INDIRECT_REF or MEM_REF\n");
+ // Note, doesn't this ignore ARRAY_REF of this?
+ // I think it's OK at least until we start supporting
+ // multi-pools.
+ if ( is_reorg_type ( base_type_of ( inner_type), info) )
+ {
+ //DEBUG_L(" returns: ReorgOpT_AryDir\n");
+ return ReorgOpT_AryDir;
+ }
+ // Just normal field reference otherwise...
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ if ( op_code == ARRAY_REF )
+ {
+ //DEBUG_L("op_code == ARRAY_REF\n");
+ if ( is_reorg_type( base_type_of ( type), info) )
+ {
+ //DEBUG_L(" returns: ReorgOpT_Array\n");
+ return ReorgOpT_Array;
+ }
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ if( op_code == INDIRECT_REF )
+ {
+ //DEBUG_L("op_code == INDIRECT_REF\n");
+ // Do we want to chase the base type?
+ // No, we care about (and transform) just
+ // *r and not **...r (where r is a ReorgType.)
+ if( is_reorg_type ( type, info) )
+ {
+ //DEBUG_L(" returns: ReorgOpT_Deref\n");
+ return ReorgOpT_Deref;
+ }
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+ }
+ //DEBUG_L(" returns: ReorgOpT_Scalar\n");
+ return ReorgOpT_Scalar;
+}
+
+bool
+is_reorg_type( tree rt, Info *info )
+{
+ return get_reorgtype_info ( rt, info) != NULL;
+}
+
+tree
+base_type_of ( tree type)
+{
+ //DEBUG_L("base_type_of: ");
+ //DEBUG_F( print_generic_expr, stderr, type, TDF_DETAILS);
+ //DEBUG("\n");
+ for ( ; POINTER_TYPE_P ( type) ||
+ TREE_CODE ( type) == ARRAY_TYPE ||
+ TREE_CODE ( type) == VAR_DECL ||
+ TREE_CODE ( type) == PARM_DECL
+ ; type = TREE_TYPE ( type) );
+ return type;
+}
+
+tree
+base_type_with_levels ( tree type, int *levels)
+{
+ //DEBUG_L("base_type_of: ");
+ //DEBUG_F( print_generic_expr, stderr, type, TDF_DETAILS);
+ //DEBUG("\n");
+ int lev = 0;
+ bool indir;
+ for ( ; (indir = POINTER_TYPE_P ( type)) ||
+ TREE_CODE ( type) == ARRAY_TYPE ||
+ TREE_CODE ( type) == VAR_DECL ||
+ TREE_CODE ( type) == PARM_DECL
+ ; type = TREE_TYPE ( type) )
+ {
+ if ( indir ) lev++;
+ }
+ *levels = lev;
+ 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)
+{
+ //DEBUG_L( "find_struct_type_ptr_to_struct: ");
+ if ( !POINTER_TYPE_P ( type) ) {
+ //DEBUG(" bail\n");
+
+ return NULL;
+ }
+ for ( ; POINTER_TYPE_P ( type); type = TREE_TYPE ( type) );
+
+ if ( TREE_CODE ( type) == RECORD_TYPE ) {
+ //DEBUG( " look for info\n");
+
+ return get_reorgtype_info ( type, info);
+ }
+ //DEBUG(" fell through\n");
+
+ return NULL;
+}
+
+// The applied function func can be used to search because it forces
+// a return if it returns true;
+void
+apply_to_all_gimple ( bool (*function)(gimple *, void *), bool phis_too, void *data )
+{
+ struct cgraph_node *node;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func);
+ basic_block bb;
+ FOR_EACH_BB_FN ( bb, func)
+ {
+ if ( phis_too )
+ {
+ gimple_seq seq = bb->il.gimple.phi_nodes;
+ if ( seq )
+ {
+ gimple_stmt_iterator phii;
+ for ( phii = gsi_start (seq); !gsi_end_p (phii); gsi_next (&phii))
+ {
+ gimple *phi_stmt = gsi_stmt ( phii);
+ if ( (*function) ( phi_stmt, data )) return;
+ }
+ }
+ }
+ gimple_stmt_iterator gsi;
+ for ( gsi = gsi_start_bb ( bb); !gsi_end_p ( gsi); gsi_next ( &gsi) )
+ {
+ gimple *stmt = gsi_stmt ( gsi);
+ // If we are searching for something then return here because
+ // it's found.
+ if ( (*function) ( stmt, data )) return;
+ }
+ }
+ pop_cfun ();
+ }
+}
+
+// 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");
+
+ // This replaces part of the below
+ bool a_rec = TREE_CODE ( a ) == RECORD_TYPE;
+ bool b_rec = TREE_CODE ( b ) == RECORD_TYPE;
+ if ( !(a_rec && a_rec) ) return false;
+
+ // This is too strict
+ //gcc_assert ( TREE_CODE ( a ) == RECORD_TYPE && TYPE_NAME ( a) != 0);
+ //gcc_assert ( TREE_CODE ( b ) == RECORD_TYPE && TYPE_NAME ( b) != 0);
+
+ // We could barf here iff the type names of records are missing.
+ // But we'll do something dubious instead since that seems to not work.
+ // Isn't that grand!
+ if ( TYPE_NAME ( a) == 0 || TYPE_NAME ( b) == 0 )
+ {
+ return a == b;
+ }
+
+ bool ret = TYPE_NAME ( a) == TYPE_NAME ( b);
+
+ //DEBUG( "returns %s\n", ret ? "true" : "false");
+
+ return ret;
+}
+
+// May need to add secondary map container to
+// look them up or even modify the container
+// type of ReorgType
+ReorgType_t *
+get_reorgtype_info ( tree type, Info* info)
+{
+ DEBUG_L( "get_reorgtype_info\n");
+
+ // 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.
+ DEBUG_L("");
+ DEBUG_F( print_generic_expr, stderr, type, TDF_DETAILS);
+ DEBUG("\n");
+ if ( same_type_p ( ri->gcc_type, type) )
+ {
+ DEBUG_A( " returns %p\n", &(*ri));
+
+ return &(*ri);
+ }
+ }
+ DEBUG_A( " returns NULL\n");
+ return NULL;
+}
+
+// These are only used by the following to routines to pass
+// information through a walking function
+typedef struct hidden_info hidden_info_t;
+struct hidden_info {
+ ReorgType_t *found_reorg;
+ Info *info;
+};
+
+static tree
+detect_reorg ( tree *tp, int *dummy, void *data)
+{
+ struct walk_stmt_info *walk_data = ( struct walk_stmt_info *)data;
+ hidden_info_t *hi = ( hidden_info_t *)walk_data->info;
+ DEBUG_L( "*tp = ");
+ DEBUG_F( print_generic_expr, stderr, *tp, (dump_flags_t)-1);
+ DEBUG("\n");
+ tree operand = base_type_of ( TREE_TYPE ( *tp));
+ ReorgType_t *ri = get_reorgtype_info ( operand, hi->info);
+ if ( ri != NULL )
+ {
+ hi->found_reorg = ri;
+ }
+
+ return NULL_TREE;
+}
+
+ReorgType_t *
+contains_a_reorgtype ( gimple *stmt, Info *info)
+{
+ DEBUG_L ( "contains_a_reorgtype: ");
+ DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ INDENT(2);
+
+ if ( gimple_code ( stmt) == GIMPLE_PHI )
+ {
+ INDENT(-2);
+ tree base = base_type_of ( TREE_TYPE ( PHI_RESULT ( stmt)));
+ return get_reorgtype_info ( base, info);
+ }
+ else
+ {
+ // Note walk_stmt_info is compilcated, use it's info
+ // field for hidden_info
+ hidden_info_t hi = { NULL, info };
+ struct walk_stmt_info walk_info; // expt
+ memset ( &walk_info, 0, sizeof ( walk_info));
+ walk_info.info = ( void*)&hi; //expt
+ walk_gimple_op ( stmt,
+ detect_reorg,
+ &walk_info);
+ INDENT(-2);
+ return hi.found_reorg;
+ }
+}
+
+static tree
+detect_reorg_in_expr ( tree *tp, int *w_s, void *data)
+{
+ //DEBUG_L("*tp = ");
+ //DEBUG_F( flexible_print, stderr, *tp, 1, (dump_flags_t)0);
+ hidden_info_t *tre_hi = ( hidden_info_t *)data;
+ //DEBUG_L("TREE_TYPE ( *tp) = ");
+ //DEBUG_F( flexible_print, stderr, TREE_TYPE ( *tp), 1, (dump_flags_t)0);
+ tree operand = base_type_of ( TREE_TYPE ( *tp));
+ //DEBUG_L("operand = %p, ", operand);
+ DEBUG_F( flexible_print, stderr, operand, 1, (dump_flags_t)0);
+ ReorgType_t *ri = get_reorgtype_info ( operand, tre_hi->info);
+ if ( ri != NULL )
+ {
+ // If we found a reorg type save it and
+ // return with a non null value to signify
+ // to trip the return from the tree walk
+ tre_hi->found_reorg = ri;
+ return *tp;
+ }
+
+ return NULL_TREE;
+}
+
+bool
+tree_contains_a_reorgtype_p ( tree expr, Info *info)
+{
+ hidden_info_t tre_hi = { NULL, info };
+ // The stuff comment out was for gimple walks. Yikes!
+ //struct walk_stmt_info walk_info;
+ //memset ( &walk_info, 0, sizeof ( walk_info));
+ //walk_info.info = ( void*)&tre_hi;
+ walk_tree_1 ( &expr, detect_reorg_in_expr, (void *)&tre_hi, NULL, NULL);
+
+ return tre_hi.found_reorg != NULL;
+}
+
+ReorgType_t *
+tree_contains_a_reorgtype ( tree expr, Info *info)
+{
+ hidden_info_t tre_hi = { NULL, info };
+ // The stuff comment out was for gimple walks. Yikes!
+ //struct walk_stmt_info walk_info;
+ //memset ( &walk_info, 0, sizeof ( walk_info));
+ //walk_info.info = ( void*)&tre_hi;
+ walk_tree_1 ( &expr, detect_reorg_in_expr, (void *)&tre_hi, NULL, NULL);
+
+ return tre_hi.found_reorg;
+}
+
+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);
+}
+
+void
+print_base_reorg ( FILE *file, int leading_space, ReorgType_t *reorg, bool detailed )
+{
+ // 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, #%d, ", leading_space, "",text, reorg->id);
+
+ if( reorg->do_dead_field_elim ) {
+ fprintf ( file, "elim:{ ");
+ // TBD
+ fprintf ( file, "}, ");
+ }
+
+ if( reorg->do_field_reorder ) {
+ fprintf ( file, "reorder:{ ");
+ // TBD
+ fprintf ( file, "}, ");
+ }
+
+ if( reorg->do_instance_interleave ) {
+ fprintf ( file, "inter:{ ");
+ // TBD
+ fprintf ( file, "%s, ",
+ reorg->instance_interleave.multi_pool ? "multi" : "single" );
+ // TBD When multi-pool implemented (and found) emit pointer_rep.
+ fprintf ( file, "}, ");
+ }
+ if ( reorg->reorg_ver_type != NULL )
+ {
+ // TBD does this belong here? How will the clone be done with elim and
+ // reorder
+ const char *clone_name =
+ identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( reorg->reorg_ver_type)));
+ fprintf ( file, "%s%s", clone_name, reorg->pointer_rep ? ", " : "");
+ }
+ if ( reorg->pointer_rep != NULL )
+ {
+ // TBD does this belong here? How will the clone be done with elim and
+ // reorder
+ const char *pointer_name =
+ identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( reorg->pointer_rep)));
+ fprintf ( file, "%s", pointer_name);
+ }
+
+ fprintf ( file, "}\n");
+ if ( detailed )
+ {
+ tree field;
+ for ( field = TYPE_FIELDS( reorg->reorg_ver_type);
+ field;
+ field = DECL_CHAIN( field))
+ {
+ fprintf ( file, "%*s", leading_space + 4, "");
+ print_generic_expr ( file, field, (dump_flags_t)0);
+ fprintf ( stderr, ": ");
+ print_generic_expr ( file, TREE_TYPE ( field), (dump_flags_t)0);
+ fprintf ( file, "\n");
+ }
+ }
+}
+
+static void
+print_base_reorgs ( FILE *file, int leading_space, Info *info, bool detailed)
+{
+ for ( int i = 0; i < info->reorg_type->size (); i++ ) {
+ print_base_reorg ( file, leading_space, &(*(info->reorg_type))[i], detailed);
+ }
+}
+
+
+static void
+print_detailed_reorgs (FILE *file, int leading_space, Info *info)
+{
+ print_base_reorgs ( file, leading_space, info, true);
+}
+
+static void
+print_reorgs ( FILE *file, int leading_space, Info *info)
+{
+ print_base_reorgs ( file, leading_space, info, false);
+}
+
+void
+print_reorg ( FILE *file, int leading_space, ReorgType_t *reorg )
+{
+ print_base_reorg ( file, leading_space, reorg, false);
+}
+
+static void
+print_progdecls ( FILE *file, int leading_space, Info * info)
+{
+ for ( int i = 0; i < info->prog_decl->size (); i++ ) {
+ print_progdecl ( file, leading_space, &(*(info->prog_decl))[i]);
+ }
+}
+
+static void
+print_progdecl ( FILE *file, int leading_space, ProgDecl_t *progdecl )
+{
+ //INDENT(leading_space);
+ //DEBUG_L( "print_progdecl check TREE_CODE = %s\n", code_str( TREE_CODE( progdecl->gcc_decl)));
+ //INDENT(-leading_space);
+ //DEBUG_A("");
+ fprintf ( file, "%*s", leading_space, "");
+ //print_generic_decl ( file, progdecl->gcc_decl, (dump_flags_t)-1);
+ print_generic_decl ( file, progdecl->gcc_decl, TDF_DETAILS);
+ fprintf ( file, "\n");
+}
+
+void
+print_program ( FILE *file, bool my_format, int leading_space, Info_t *info)
+{
+ struct cgraph_node *node;
+ fprintf ( file, "%*sProgram:\n", leading_space, "");
+
+ // Print Global Decls
+ //
+ varpool_node *var;
+ FOR_EACH_VARIABLE ( var)
+ {
+ tree decl = var->decl;
+ fprintf ( file, "%*s", leading_space, "");
+ print_generic_decl ( file, decl, (dump_flags_t)0);
+ fprintf ( file, "\n");
+ }
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ if ( my_format )
+ {
+ flexible_print ( file, TREE_TYPE( func->decl), 1, (dump_flags_t)0);
+ print_function ( file, leading_space + 4, func);
+ }
+ else
+ {
+ flexible_print ( file, TREE_TYPE( func->decl), 1, (dump_flags_t)0);
+ dump_function_header ( file, func->decl, (dump_flags_t)0);
+ dump_function_to_file ( func->decl, file, (dump_flags_t)0);
+ }
+ }
+
+ //DEBUG ("INTERNALS PRINT\n");
+ //DEBUG_F (apply_to_all_gimple, print_internals, true, (void*)info);
+}
+
+static void
+print_function ( FILE *file, int leading_space, struct function *func)
+{
+ basic_block bb;
+
+ fprintf ( file, "%*sFunc: ", leading_space + 2, "");
+ // Print Func Type
+ print_generic_expr ( file, TREE_TYPE(TREE_TYPE( func->decl)), (dump_flags_t)0);
+
+ // Print Func Name
+ fprintf ( file, " %s ( ", lang_hooks.decl_printable_name ( func->decl, 2));
+
+ // Print Parameter Decls
+ tree parm;
+ for ( parm = DECL_ARGUMENTS ( func->decl);
+ parm;
+ parm = DECL_CHAIN ( parm) )
+ {
+ print_generic_expr ( file, TREE_TYPE( parm), (dump_flags_t)0);
+ fprintf ( file, " ");
+ print_generic_expr ( file, parm, (dump_flags_t)0);
+ fprintf ( file, "; ");
+ }
+ fprintf ( file, ")\n");
+
+ // Print Local Decls
+ tree decl;
+ unsigned i;
+ FOR_EACH_LOCAL_DECL ( func, i, decl)
+ {
+ fprintf ( file, "%*s", leading_space + 6, "");
+ print_generic_expr ( file, TREE_TYPE( decl), (dump_flags_t)0);
+ fprintf ( file, " ");
+ print_generic_expr ( file, decl, (dump_flags_t)0);
+ fprintf ( file, ";\n");
+ }
+
+ FOR_EACH_BB_FN ( bb, func)
+ {
+ // print bb num
+ fprintf ( file, "%*sBB %d:", leading_space + 4, "", bb->index );
+
+ // Tried to use function gimple_dump_bb is here instead of
+ // the following loop but it's worthless.
+
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE ( e, ei, bb->succs )
+ {
+ basic_block succ_bb = e->dest;
+ fprintf ( file, ", BB%d", succ_bb->index);
+ if ( e->flags & EDGE_TRUE_VALUE ) fprintf ( file, " true");
+ if ( e->flags & EDGE_FALSE_VALUE ) fprintf ( file, " false");
+ if ( e->flags & EDGE_FALLTHRU ) fprintf ( file, " fallthru");
+ }
+ fprintf ( file, "\n");
+
+ gimple_seq seq = bb->il.gimple.phi_nodes;
+ if ( seq )
+ {
+ gimple_stmt_iterator phii;
+ for ( phii = gsi_start (seq); !gsi_end_p (phii); gsi_next (&phii))
+ {
+ fprintf ( file, "%*s", leading_space + 6, "" );
+ print_gimple_stmt ( file, gsi_stmt ( phii), 0, TDF_DETAILS);
+ }
+ }
+
+ gimple_stmt_iterator gsi;
+ for ( gsi = gsi_start_bb ( bb);
+ !gsi_end_p ( gsi);
+ gsi_next ( &gsi) )
+ {
+ gimple *stmt = gsi_stmt ( gsi);
+ fprintf ( file, "%*s", leading_space + 6, "" );
+ // Issue: for "if" this does not print the gotos.
+ print_gimple_stmt ( file, stmt, 0, TDF_DETAILS);
+ }
+ }
+}
+
+ReorgType_t *
+get_reorgtype( gimple *stmt, Info *info, int i)
+{
+ // Looking at operands of statement, when we get to
+ // the ith one, return it.
+ int num_reorgs = 0;
+ unsigned num_ops = gimple_num_ops ( stmt);
+ unsigned j;
+ for ( j = 0; j < num_ops; j++ )
+ {
+ tree op = gimple_op ( stmt, j);
+ if ( tree_contains_a_reorgtype_p ( op, info) ) {
+ num_reorgs++;
+ if ( num_reorgs == i )
+ {
+ return get_reorgtype_info ( op, info);
+ }
+ }
+ }
+ gcc_assert ( 0);
+}
+
+int
+num_reorgtypes( gimple *stmt, Info *info)
+{
+ //DEBUG_L("num_reorgtypes: ");
+ //DEBUG_F ( print_gimple_stmt, stderr, stmt, 0);
+ // Looking at operands of statement, count
+ // the number that have reorg types.
+ // Note, they may be (most likely are) the same as other
+ // reorg types in the statement.
+ int num_reorgs = 0;
+ unsigned num_ops = gimple_num_ops ( stmt);
+ unsigned i;
+ for ( i = 0; i < num_ops; i++ )
+ {
+ tree op = gimple_op ( stmt, i);
+ //DEBUG_A("op%d: ",i);
+ //DEBUG_F( print_generic_expr, stderr, op, (dump_flags_t)-1);
+ if ( tree_contains_a_reorgtype_p ( op, info) )
+ {
+ num_reorgs++;
+ //DEBUG(" reorg");
+ }
+ //DEBUG( "\n");
+ }
+ return num_reorgs;
+}
+
+void
+print_type ( FILE *file, tree type)
+{
+ const char *text
+ = identifier_to_locale ( IDENTIFIER_POINTER ( TYPE_NAME ( type)));
+ fprintf ( file, "type: %s\n", text);
+}
+
+bool
+uses_field_of_reorgtypes( gimple *stmt, Info * info)
+{
+ // TBD
+ // This is a bit more sophisticated than needed
+ // for "hello world" so I'll defer this for a bit.
+ return false;
+}
+
+void
+modify_ssa_name_type ( tree ssa_name, tree type)
+{
+ // This rips off the code in make_ssa_name_fn.
+ // Note, this probabily be made into special function
+ // that is part of tree-ssanames.
+ //DEBUG_L("modify_ssa_name_type ssa_name ");
+ //DEBUG_F(print_generic_expr, stderr, ssa_name, (dump_flags_t)0);
+ //DEBUG("\n");
+ //gcc_assert ( TREE_TYPE ( type));
+ //DEBUG_A("type: ");
+ //DEBUG_F(print_generic_expr, stderr, type, (dump_flags_t)0);
+ //DEBUG("\n");
+ //DEBUG_A("TREE_TYPE(type): ");
+ //DEBUG_F(print_generic_expr, stderr, TREE_TYPE(type), (dump_flags_t)0);
+ //DEBUG("\n");
+ //DEBUG_A("TYPE_MAIN_VARIANT(type) :");
+ //DEBUG_F(print_generic_expr, stderr, TYPE_MAIN_VARIANT(type), (dump_flags_t)0);//
+ //DEBUG("\n");
+ //DEBUG_A("ssa_defined_default_def_p(ssa_name) %s\n",
+ // ssa_defined_default_def_p(ssa_name) ? "true" : "false");
+
+ if ( TYPE_P ( type) )
+ {
+ //DEBUG_L("TYPE_P true\n");
+ gcc_assert ( TYPE_MAIN_VARIANT ( type));
+ TREE_TYPE ( ssa_name) = TYPE_MAIN_VARIANT ( type);
+ if ( SSA_NAME_IS_DEFAULT_DEF ( ssa_name) )
+ {
+ // Again this is what breaks (pretty-print) something
+ // about expecting an integer_type.
+ // Our _reorg_SP_ptr_type_type_t really is an integer
+ // type but it doesn't know it.
+ SET_SSA_NAME_VAR_OR_IDENTIFIER ( ssa_name, TYPE_MAIN_VARIANT ( type));
+ }
+ else
+ {
+ // The following breaks defaults defs hence the check above.
+ SET_SSA_NAME_VAR_OR_IDENTIFIER ( ssa_name, NULL_TREE);
+ }
+ }
+ else
+ {
+ //DEBUG_L("TYPE_P false\n");
+ gcc_assert ( TREE_TYPE ( type));
+ TREE_TYPE ( ssa_name) = TREE_TYPE ( type);
+ SET_SSA_NAME_VAR_OR_IDENTIFIER ( ssa_name, type);
+ }
+}
+
+//-- debugging only --
+//static const char *
+#if DEBUGGING
+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 VOID_TYPE:
+ return "VOID_TYPE";
+ case VAR_DECL:
+ return "VAR_DECL";
+ case TYPE_DECL:
+ return "TYPE_DECL";
+ case CONST_DECL:
+ return "CONST_DECL";
+ case PARM_DECL:
+ return "PARM_DECL";
+ case FIELD_DECL:
+ return "FIELD_DECL";
+ case FUNCTION_DECL:
+ return "FUNCTION_DECL";
+ case RESULT_DECL:
+ return "RESULT_DECL";
+ default:
+ return get_tree_code_name ( tc);
+ 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";
+ }
+ }
+}
+#endif
+
+const char *
+type_name_to_str ( tree tn)
+{
+ gcc_assert ( tn != NULL );
+ gcc_assert ( IDENTIFIER_POINTER ( tn) != NULL );
+ return identifier_to_locale ( IDENTIFIER_POINTER ( tn));
+}
+
+#if DEBUGGING
+void
+handle_debug_indenting ( int amount )
+{
+ debug_indenting += amount;
+ debug_indenting = MAX ( debug_indenting, 0);
+}
+#endif
+
+#if DEBUGGING
+#if 0
+// A Wolf Fence is whatever it needs to be whenever it needs to be it.
+int
+wf_func ( tree *slot, tree *dummy)
+{
+ tree t_val = *slot;
+ gcc_assert( t_val->ssa_name.var);
+ return 0;
+}
+
+void
+wolf_fence (
+ Info *info // Pass level gobal info (might not use it)
+ )
+{
+ struct cgraph_node *node;
+
+ //fprintf( stderr,
+ // "Wolf Fence: Find wolf via gcc_assert(t_val->ssa_name.var)\n");
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func);
+
+ DEFAULT_DEFS ( func)->traverse_noresize < tree *, wf_func> ( NULL);
+
+ pop_cfun ();
+ }
+ fprintf( stderr, "No Wolf\n");
+}
+#endif
+
+#if 0
+void
+wolf_fence (
+ Info *info // Pass level gobal info (might not use it)
+ )
+{
+ struct cgraph_node *node;
+
+ //fprintf( stderr,
+ // "Wolf Fence: Find wolf via gcc_assert(t_val->ssa_name.var)\n");
+
+ fprintf( stderr, "Wolf?\n");
+
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func);
+
+ unsigned int len = SSANAMES ( func)->length ();
+ for ( unsigned int i = 0; i < len; i++)
+ {
+ tree ssa_name = (*SSANAMES ( func))[i];
+ if ( ssa_name == NULL ) continue;
+ if ( SSA_NAME_IS_DEFAULT_DEF ( ssa_name) )
+ {
+ gimple *def_stmt = SSA_NAME_DEF_STMT ( ssa_name);
+ if ( !gimple_nop_p ( def_stmt) )
+ {
+ fprintf ( stderr, "Wolf! : ");
+ print_gimple_stmt ( stderr, def_stmt, 0);
+ gcc_assert (0);
+ }
+ }
+ }
+ pop_cfun ();
+ }
+ fprintf( stderr, "No Wolf\n");
+}
+#endif
+
+void
+wolf_fence (
+ Info *info // Pass level gobal info (might not use it)
+ )
+{
+ if ( ssa_check ( stderr, Show_failures, Fail_1st_bad, false, false) )
+ {
+ fprintf ( stderr, "Wolf!\n");
+ gcc_assert (0);
+ }
+
+ fprintf( stderr, "No Wolf\n");
+}
+
+// returns true for failure
+bool
+ssa_check ( FILE *file, Display display, Failure failure, bool types, bool header )
+{
+ if ( header ) fprintf ( file, "ssa_check:\n");
+ struct cgraph_node *node;
+ bool has_a_failure = false;
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node)
+ {
+ struct function *func = DECL_STRUCT_FUNCTION ( node->decl);
+ push_cfun ( func);
+
+ unsigned int len = SSANAMES ( func)->length ();
+ for ( unsigned int i = 0; i < len; i++)
+ {
+ tree ssa_name = (*SSANAMES ( func))[i];
+ if ( ssa_name == NULL ) continue;
+ bool a_default_def = SSA_NAME_IS_DEFAULT_DEF ( ssa_name);
+ gimple *defining_stmt = SSA_NAME_DEF_STMT ( ssa_name);;
+ bool no_defining_stmt = defining_stmt == NULL;
+ bool defined_by_nop = defining_stmt && gimple_code ( defining_stmt) == GIMPLE_NOP;
+ bool has_type = TREE_TYPE ( ssa_name) != NULL;
+ tree type = TREE_TYPE ( ssa_name);
+ tree bottom_type = base_type_of ( type);
+ bool fails = !has_type ||
+ no_defining_stmt ||
+ (a_default_def && !defined_by_nop) ||
+ (!a_default_def && defined_by_nop);
+ if (fails) has_a_failure = true;
+ if ( display == Show_everything || (fails && display == Show_failures) )
+ {
+ fprintf ( file, "ssa_name = ");
+ print_generic_expr ( file, ssa_name, (dump_flags_t)0);
+ fprintf ( file, "%s", has_type ? ", has no type" : "");
+ fprintf ( file, "%s", a_default_def ? ", is default_def" : "");
+ fprintf ( file, "%s", no_defining_stmt ? ", has no defining stmt" : "");
+ fprintf ( file, "%s", defined_by_nop ? ", defined by a nop" : "");
+ if (types)
+ {
+ fprintf ( file, ", type = ");
+ print_generic_expr ( file, type, (dump_flags_t)0);
+ fprintf ( file, ", bottom_type = ");
+ print_generic_expr ( file, bottom_type, (dump_flags_t)0);
+ }
+ fprintf ( file, "\n");
+ }
+ if ( has_a_failure && Fail_1st_bad == failure ) break;
+ }
+ pop_cfun ();
+ if ( has_a_failure && Fail_1st_bad == failure ) break;
+ }
+ return failure != Do_not_fail && has_a_failure;
+}
+
+#endif
+void
+flexible_print( FILE *f, tree t, int nl, dump_flags_t d)
+{
+ if ( DECL_P( t) )
+ {
+ print_generic_decl(f,t,d);
+ }
+ else
+ {
+ print_generic_expr(f,t,d);
+ }
+ if ( nl ) fprintf ( f, "\n");
+}
+
+//---------------- Pass Control Follows ----------------
+
+const pass_data pass_data_ipa_structure_reorg =
+{
+ IPA_PASS, /* type */
+ "structure-reorg", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ 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 */ // ???
+ 0, /* 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 )
+ && in_lto_p );
+ }
+
+ 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..8454c42dd89
--- /dev/null
+++ b/gcc/ipa-structure-reorg.h
@@ -0,0 +1,293 @@
+/* Interprocedural structure reorganization
+ Copyright (C) 2019-2020 Free Software Foundation, Inc.
+
+ Contributed by Gary Oblock <gary@amperecomputing.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/>. */
+
+// This is depercated
+#define USE_NEW_INTERFACE 1
+// This is when our stuff is integrated
+#define INTEGRATION_FUNCTIONAL 0
+// Erick this is when you do something that really steps on some toes
+#define KLUDGE 1
+#define USE_REORG_TYPES 1
+// If PRINT_FORMAT is true use pass specific print format.
+#define PRINT_FORMAT false
+
+typedef struct RT_Elim RT_Elim;
+typedef struct RT_Reorder RT_Reorder;
+typedef struct RT_Interleave RT_Interleave;
+
+#include <set>
+#include "collect-types.h"
+
+struct RT_Elim {
+ int dummy;
+};
+
+struct RT_Reorder {
+ int dummy;
+};
+
+struct RT_Interleave {
+ int numbOfGlobalArrays; // Statically allocated only
+ int numbOfLocalArrays; // Statically allocated only
+ int numbOfDynmAllocs;
+ tree base;
+ double reorg_perf;
+ double regular_perf;
+ bool multi_pool; // single pool if not set
+ int dummy;
+};
+
+typedef struct ReorgType ReorgType_t;
+// TODO: Gary, is there supposed to be
+// 1 ReorgType_t for every tree?
+// Don't we need something that also is global?
+// I have a set of trees that do not escape
+// and I would like to use that for the moment.
+// Not sure how it will evolve in the future...
+// REPLY: Erick, I'm not sure I follow what you
+// are asking. In my mind there should
+// be one reorg type for every unique type and
+// if some N types are equivalent then there should
+// be only one reorg type for all of them.
+struct ReorgType {
+ unsigned id;
+ bool delete_me;
+ tree gcc_type; // This info is for this type.
+ // TBD will field reordering and/or dead field elimination use
+ // use the reorg_ver_type? I think it's likely that they can.
+ tree reorg_ver_type; // the base type
+ tree pointer_rep; // new pointer format (multi-pool)
+ bool do_dead_field_elim;
+ bool do_field_reorder;
+ bool do_instance_interleave;
+ RT_Elim dead_field_elim;
+ RT_Reorder field_reorder;
+ RT_Interleave instance_interleave;
+};
+
+typedef struct ProgDecl ProgDecl_t;
+struct ProgDecl {
+ tree gcc_decl;
+};
+
+enum ReorgOpTrans {
+ // TODO: What is the purpose of this enum?
+ // Let's try to use scalar insead of this... nope!
+ ReorgOpT_Temp, // SSA temp
+ ReorgOpT_Address, // "&x[i]"
+ ReorgOpT_Pointer, // "a"
+ ReorgOpT_Struct, // "s"
+ ReorgOpT_Deref, // "*a"
+ ReorgOpT_Array, // "x[i]"
+ ReorgOpT_Scalar, // "z"
+ ReorgOpT_Indirect, // "a->f"
+ ReorgOpT_AryDir // "x[i].f"
+};
+
+enum CompressionControl {
+ Initial,
+ Subsequent
+};
+
+enum ReorgTransformation {
+ // TODO: Gary, if these are transformation, shouldn't they have
+ // a pre-state and a post-state?
+ // Here I am only seeing statements. Not sure why
+ // a reorg transformation has statements / expressions.
+ //
+ // Also, why aren't we using the expressions already
+ // defined by GCC? For example EQ_EXPR?
+ // Ultimately what is the purpose of these?
+ 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, //
+ ReorgT_UserFunc, //
+ ReorgT_Convert, // type casts
+ ReorgT_Return, // return t
+ 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 {
+ // TODO: What is the meaning of reorg type?
+ // Hasn't this meaning changed now that we have three
+ // transformations roughly running at the same time?
+ 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
+ // ptrset_t holds types which point to records
+ // and types which escape
+ ptrset_t sets;
+ int num_deleted;
+ double total_cache_accesses;
+ FILE *reorg_dump_file;
+ // Debug flags
+ bool show_all_reorg_cands;
+ bool show_all_reorg_cands_in_detail;
+ bool show_prog_decls;
+ bool show_delete;
+ bool show_new_BBs;
+ bool show_transforms;
+ bool show_bounds;
+ bool is_non_escaping_set_empty();
+
+ Info (std::vector <ReorgType_t> *v1,
+ std::vector <ReorgType_t> *v2,
+ std::vector <ProgDecl_t> *v3,
+ std::map <tree, BoolPair_t> *v4)
+ : reorg_type(v1)
+ , saved_reorg_type(v2)
+ , prog_decl(v3)
+ , struct_types(v4)
+ , num_deleted(0)
+ , total_cache_accesses(0)
+ , reorg_dump_file(NULL)
+ , show_all_reorg_cands(false)
+ , show_all_reorg_cands_in_detail(false)
+ , show_prog_decls(false)
+ , show_new_BBs(false)
+ , show_transforms(false)
+ , show_bounds(false)
+ {};
+};
+
+// This will perform a function on the supplied
+// reorg type. It's primarily to support debugging.
+typedef void (*ReorgFn)( Info *, ReorgType_t *);
+
+#define USE_NEW_INTERFACE 1
+#if USE_NEW_INTERFACE
+extern int str_reorg_dead_field_eliminate_qual ( Info *);
+extern int str_reorg_dead_field_eliminate_trans ( Info *);
+extern int str_reorg_field_reorder_qual ( Info *);
+extern int str_reorg_field_reorder_trans ( Info *);
+extern int str_reorg_instance_interleave_qual ( Info *);
+extern int str_reorg_instance_interleave_trans ( Info *);
+#else
+extern int str_reorg_dead_field_eliminate ( Info *);
+extern int str_reorg_field_reorder ( Info *);
+extern int str_reorg_instance_interleave ( Info *);
+#endif
+
+extern int number_of_levels ( tree);
+extern bool modify_decl_core ( tree *, 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);
+extern enum ReorgOpTrans recognize_op ( tree, Info_t *);
+extern ReorgTransformation reorg_recognize ( gimple *,
+ cgraph_node *,
+ Info_t *);
+extern void apply_to_all_gimple ( bool (*)(gimple *, void *), bool, void *);
+extern ReorgType_t *get_reorgtype_info ( tree, Info_t *);
+extern void print_reorg_with_msg ( FILE *, ReorgType_t *, int, const char *);
+extern ReorgType_t *contains_a_reorgtype ( gimple *, Info *);
+extern bool tree_contains_a_reorgtype_p ( tree, Info *);
+extern ReorgType_t *tree_contains_a_reorgtype ( tree, Info *);
+extern bool is_reorg_type ( tree, Info_t *);
+extern tree base_type_of ( tree);
+extern tree base_type_with_levels ( tree, int *);
+extern void print_reorg ( FILE *, int, ReorgType_t *);
+extern void print_program ( FILE *, bool, int, Info_t *);
+extern void print_type ( FILE *, tree);
+extern void modify_ssa_name_type ( tree, tree);
+extern bool print_internals (gimple *, void *);
+
+
+
+// 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.
+
+#define DEBUGGING 0
+#if DEBUGGING
+enum Display {
+ Show_nothing,
+ Show_failures,
+ Show_everything
+};
+
+enum Failure {
+ Do_not_fail,
+ Fail_1st_bad,
+ Fail_at_End
+};
+
+extern int debug_indenting;
+extern void handle_debug_indenting( int);
+extern const char *code_str( enum tree_code);
+extern void wolf_fence( Info *);
+extern bool ssa_check ( FILE *, Display, Failure, bool, bool);
+
+// Line numbered
+#define DEBUG_L(...) { fprintf( stderr, "L# %4d: %*s", __LINE__, debug_indenting, ""); fprintf( stderr, __VA_ARGS__); }
+// Alinged with line numbered
+#define DEBUG_A(...) { fprintf( stderr, "%*s", debug_indenting + 7, ""); fprintf( stderr, __VA_ARGS__); }
+//With no indenting
+#define DEBUG(...) { fprintf( stderr, __VA_ARGS__); }
+#define DEBUG_F(f,...) f( __VA_ARGS__)
+#define INDENT(a) handle_debug_indenting(a)
+#else
+#define DEBUG_L(...)
+#define DEBUG_A(...)
+#define DEBUG(...)
+#define DEBUG_F(...)
+#define INDENT(a)
+
+#endif
+extern void flexible_print( FILE *, tree, int, dump_flags_t);
+
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
new file mode 100644
index 00000000000..45875f74443
--- /dev/null
+++ b/gcc/ipa-type-escape-analysis.c
@@ -0,0 +1,369 @@
+#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 "gimple-collector.hpp"
+#include "gimple-escaper.hpp"
+#include "gimple-caster.hpp"
+#include "gimple-accesser.hpp"
+#include "type-stringifier.hpp"
+#include "type-incomplete-equality.hpp"
+#include "type-reconstructor.hpp"
+#include "gimple-rewriter.hpp"
+#include <vector>
+
+
+static unsigned int iphw_execute();
+
+namespace {
+/* ==What is type-escape-analysis?==
+ * type-escape-analysis is a SIMPLE_IPA_PASS that performs no transformations.
+ * type-escape-analysis only performs analysis and outputs to a WPA dump file.
+ *
+ * ==Why should we run type-escape-analysis?==
+ * type-escape-analysis is useful to run unit tests in gcc.
+ * By having the type-escape-analysis execute during WPA we are able to use
+ * the dejagnu framework to see if an expected output matches the observed
+ * output in the wpa dump file.
+ *
+ * ==How do we use type-escape-analysis?==
+ * Compile with
+ * -flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis
+ *
+ * To use type-escape-analysis in tests use the following lines
+ * { dg-do link }
+ * { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" }
+ * C code to test...
+ * { dg-final { scan-wpa-ipa-dump "regex" "type-escape-analysis" } }
+ *
+ * ==TODO==
+ * At the moment, the tests are not set up to work with the current framework,
+ * so I will need to update them in the following day.
+ */
+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 && flag_profile_use; }
+ 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);
+}
+
+static void collect_types();
+
+static unsigned int
+iphw_execute()
+{
+ collect_types();
+ return 0;
+}
+
+static void
+fix_escaping_types_in_set(ptrset_t &types)
+{
+ bool fixed_point_reached = false;
+ TypeIncompleteEquality structuralEquality;
+ TypeStringifier stringifier;
+ do {
+ std::vector<const_tree> fixes;
+ fixed_point_reached = true;
+ for (auto i = types.escaping.cbegin(), e = types.escaping.cend(); i != e; ++i)
+ {
+ for (auto j = types.non_escaping.cbegin(), f = types.non_escaping.cend(); j != f; ++j)
+ {
+ const_tree type_esc = *i;
+ gcc_assert(type_esc);
+ const_tree type_non = *j;
+ gcc_assert(type_non);
+ // There can be cases where incomplete types are marked as non-escaping
+ // and complete types counter parts are marked as escaping.
+ //const bool interesting_case = eq_type_compare(type_esc, type_non);
+ //TODO: We are going to need a different type comparison because this one
+ //fails to take into account the recursion...
+ std::string type_esc_name = TypeStringifier::get_type_identifier(type_esc);
+ std::string type_non_name = TypeStringifier::get_type_identifier(type_non);
+
+ type_esc_name = stringifier.stringify(type_esc);
+ type_non_name = stringifier.stringify(type_non);
+
+ const bool equal = structuralEquality.equal(type_esc, type_non);
+ if (!equal) continue;
+
+ log("recalulating %s == %s\n", type_esc_name.c_str(), type_non_name.c_str());
+ fixed_point_reached = false;
+ // Add incomplete to escaping
+ // delete incomplete from non_escaping
+ // We shouldn't do that inside our iteration loop.
+ fixes.push_back(type_non);
+ }
+ }
+
+ for (auto i = fixes.cbegin(), e = fixes.cend(); i != e; ++i)
+ {
+ const_tree escaping_type = *i;
+ types.escaping.insert(escaping_type);
+ types.non_escaping.erase(escaping_type);
+ }
+ } while (!fixed_point_reached);
+}
+
+static void
+collect_types()
+{
+ GimpleTypeCollector collector;
+ collector.walk();
+ collector.print_collected();
+ ptrset_t types = collector.get_pointer_set();
+ GimpleCaster caster(types);
+ caster.walk();
+ if (flag_print_cast_analysis) caster.print_reasons();
+ ptrset_t casting = caster.get_sets();
+ fix_escaping_types_in_set(casting);
+ GimpleAccesser accesser;
+ accesser.walk();
+ if (flag_print_access_analysis) accesser.print_accesses();
+ record_field_map_t record_field_map = accesser.get_map();
+ TypeIncompleteEquality equality;
+ bool has_fields_that_can_be_deleted = false;
+ typedef std::set<unsigned> field_offsets_t;
+ typedef std::map<const_tree, field_offsets_t> record_field_offset_map_t;
+ record_field_offset_map_t record_field_offset_map;
+ //TODO: We need to optimize this, compiling GCC is taking too long
+ for (auto i = record_field_map.begin(), e = record_field_map.end(); i != e; ++i)
+ {
+ const_tree r_i = i->first;
+ std::vector<const_tree> equivalence;
+ for (auto j = record_field_map.cbegin(), f = record_field_map.cend(); j != f; j++)
+ {
+ const_tree r_j = j->first;
+ const bool pointer_equal = r_i == r_j;
+ if (pointer_equal) continue;
+
+ bool is_p_record = casting.in_points_to_record(r_i) && casting.in_points_to_record(r_j);
+ if (!is_p_record) continue;
+
+ const bool are_equal = equality.equal(r_i, r_j);
+ if (!are_equal) continue;
+
+ equivalence.push_back(r_j);
+ }
+
+ field_offsets_t field_offset;
+ field_access_map_t original_field_map = record_field_map[r_i];
+ for (auto j = original_field_map.begin(), f = original_field_map.end(); j != f; ++j)
+ {
+ const_tree f_k = j->first;
+ unsigned access = j->second;
+ const bool is_read = access & Read;
+ unsigned f_offset = tree_to_uhwi(DECL_FIELD_OFFSET(f_k));
+ unsigned f_offset_2 = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(f_k));
+ //log("%s offset %u %u is_read %s\n", TypeStringifier::get_field_identifier(f_k).c_str(), f_offset, f_offset_2, is_read ? "t" :"f");
+ if (!is_read) continue;
+ field_offset.insert(f_offset * 8 + f_offset_2);
+ }
+ for (auto j = equivalence.begin(), f = equivalence.end(); j != f; j++)
+ {
+ const_tree r_j = *j;
+ field_access_map_t equivalent_field_map = record_field_map[r_j];
+
+ for (auto k = equivalent_field_map.begin(), g = equivalent_field_map.end(); k != g; ++k)
+ {
+ const_tree f_k = k->first;
+ unsigned access = k->second;
+ const bool is_read = access & Read;
+ unsigned f_offset = tree_to_uhwi(DECL_FIELD_OFFSET(f_k));
+ unsigned f_offset_2 = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(f_k));
+ //log("%s offset %u %u is_read %s\n", TypeStringifier::get_field_identifier(f_k).c_str(), f_offset, f_offset_2, is_read ? "t" :"f");
+ if (!is_read) continue;
+ field_offset.insert(f_offset * 8 + f_offset_2);
+ }
+ }
+ record_field_offset_map[r_i] = field_offset;
+ }
+
+
+ const typeset &non_escaping = casting.non_escaping;
+
+ std::vector<const_tree> to_erase;
+ std::set<const_tree> to_keep;
+ for (auto i = record_field_offset_map.begin(), e = record_field_offset_map.end(); i != e; ++i)
+ {
+ const_tree record = i->first;
+ const bool in_set = non_escaping.find(record) != non_escaping.end();
+ if (!in_set) {
+ to_erase.push_back(record);
+ continue;
+ }
+
+ field_offsets_t field_offset = i->second;
+ for (tree field = TYPE_FIELDS(record); field; field = DECL_CHAIN(field))
+ {
+ unsigned f_offset = tree_to_uhwi(DECL_FIELD_OFFSET(field));
+ unsigned f_offset_2 = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(field));
+ f_offset = f_offset * 8 + f_offset_2;
+ bool in_set2 = field_offset.find(f_offset) != field_offset.end();
+ if (in_set2) {
+ field_offset.erase(f_offset);
+ continue;
+ }
+ to_keep.insert(record);
+ field_offset.insert(f_offset);
+ has_fields_that_can_be_deleted = true;
+ log("%s.%s may be deleted\n", TypeStringifier::get_type_identifier(record).c_str(), TypeStringifier::get_field_identifier(field).c_str());
+ }
+ record_field_offset_map[record] = field_offset;
+ }
+
+ for (auto i = to_erase.begin(), e = to_erase.end(); i != e; ++i)
+ {
+ const_tree record = *i;
+ record_field_offset_map.erase(record);
+ }
+
+ if (!has_fields_that_can_be_deleted) return;
+
+ TypeReconstructor reconstructor(record_field_offset_map);
+ TypeStringifier stringifier;
+
+ // TODO:
+ // Here, what we want to do is we want to rewrite only the
+ // types which we believe we can rewrite, that and all types which
+ // point to those types...
+ //
+ // Otherwise, it will lead to difficulties in the future since
+ // we could be modifying many different types.
+ // So we have to make sure that we are only modifying the types of interest.
+ for (auto i = types.points_to_record.cbegin(), e = types.points_to_record.cend(); i != e; ++i)
+ {
+ const_tree record = *i;
+ std::string name_from = stringifier.stringify(TYPE_MAIN_VARIANT(record));
+ bool points_to_record = false;
+ const_tree tt = record;
+
+
+ //TODO:
+ //This is our little hack to make sure that we are
+ //only modifying types which are of interest.
+ //However, we really shouldn't.
+ //Let's clean the input to reconstructor.walk
+ while (TREE_TYPE(tt)) { tt = TREE_TYPE(tt); };
+ points_to_record = TREE_CODE(tt) == RECORD_TYPE;
+ if (!points_to_record) continue;
+
+ bool in_map = record_field_offset_map.find(tt) != record_field_offset_map.end();
+ if (!in_map) continue;
+
+ // We need to walk over the type main variant first...
+ reconstructor.walk(TYPE_MAIN_VARIANT(record));
+ log("walking main variant %s\n", name_from.c_str());
+ }
+
+ for (auto i = types.points_to_record.cbegin(), e = types.points_to_record.cend(); i != e; ++i)
+ {
+ const_tree record = *i;
+ std::string name_from = stringifier.stringify(record);
+ bool points_to_record = false;
+ const_tree tt = record;
+
+
+ //TODO:
+ //This is our little hack to make sure that we are
+ //only modifying types which are of interest.
+ //However, we really shouldn't.
+ //Let's clean the input to reconstructor.walk
+ while (TREE_TYPE(tt)) { tt = TREE_TYPE(tt); };
+ points_to_record = TREE_CODE(tt) == RECORD_TYPE;
+ if (!points_to_record) continue;
+
+ bool in_map = record_field_offset_map.find(tt) != record_field_offset_map.end();
+ if (!in_map) continue;
+
+ // We need to walk over the type main variant first...
+ reconstructor.walk(record);
+ log("walking non main%s\n", name_from.c_str());
+ }
+
+
+ TypeReconstructor::reorg_record_map_t map = reconstructor.get_map();
+ TypeReconstructor::reorg_field_map_t field_map = reconstructor.get_field_map();
+
+ for (auto i = map.cbegin(), e = map.cend(); i != e; ++i)
+ {
+ const_tree o_record = i->first;
+ tree r_record = i->second;
+ tree m_record = TYPE_MAIN_VARIANT(r_record);
+ std::string name_from = stringifier.stringify(o_record);
+ std::string name_to = stringifier.stringify(r_record);
+ std::string name_to_mv = stringifier.stringify(m_record);
+ bool c_f = TYPE_CACHED_VALUES_P(o_record);
+ bool c_t = TYPE_CACHED_VALUES_P(r_record);
+ bool c_m = TYPE_CACHED_VALUES_P(m_record);
+ TYPE_CACHED_VALUES_P((tree)o_record) = false;
+ TYPE_CACHED_VALUES_P((tree)m_record) = false;
+
+ log("map f: %s TYPE_CACHED_VALUES_P %s \n", name_from.c_str(), c_f ? "t" : "f");
+ log("map t: %s TYPE_CACHED_VALUES_P %s \n", name_to.c_str(), c_t ? "t" : "f");
+ log("map m: %s TYPE_CACHED_VALUES_P %s \n", name_to_mv.c_str(), c_m ? "t" : "f");
+ bool in_map = map.find(m_record) != map.end();
+ if (!in_map) continue;
+ tree mm_record = map[m_record];
+ std::string name_to_mmv = stringifier.stringify(mm_record);
+ bool c_m2 = TYPE_CACHED_VALUES_P(mm_record);
+ log("map m2: %s TYPE_CACHED_VALUES_P %s\n", name_to_mmv.c_str(), c_m2 ? "t" : "f");
+ // TODO: This is a hack...
+ TYPE_MAIN_VARIANT(r_record) = mm_record;
+ // Do we need to layout the type again?
+ }
+
+
+ GimpleTypeRewriter rewriter(map, field_map);
+ rewriter.walk();
+ rewriter._rewrite_function_decl();
+
+ GimpleWalker walker;
+ walker.walk(); // Just for printing...
+
+ log("FINISHED\n");
+}
diff --git a/gcc/passes.def b/gcc/passes.def
index c0098d755bf..67d2520c1f8 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -171,6 +171,9 @@ 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_type_escape_analysis);
+ NEXT_PASS (pass_ipa_structure_reorg);
+ NEXT_PASS (pass_ipa_prototype);
NEXT_PASS (pass_ipa_pta);
NEXT_PASS (pass_omp_simd_clone);
TERMINATE_PASS_LIST (all_late_ipa_passes)
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 7dd1e2685a4..4df2c473359 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -81,6 +81,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 f01e811917d..bcb7e921eac 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -501,6 +501,7 @@ 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_prototype (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);
extern ipa_opt_pass_d *make_pass_ipa_icf (gcc::context *ctxt);
@@ -508,6 +509,8 @@ extern ipa_opt_pass_d *make_pass_ipa_devirt (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_odr (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_reference (gcc::context *ctxt);
extern ipa_opt_pass_d *make_pass_ipa_pure_const (gcc::context *ctxt);
+extern simple_ipa_opt_pass *make_pass_ipa_structure_reorg (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_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);
diff --git a/gcc/type-accessor.c b/gcc/type-accessor.c
new file mode 100644
index 00000000000..a332115d879
--- /dev/null
+++ b/gcc/type-accessor.c
@@ -0,0 +1,34 @@
+#include "type-accessor.hpp"
+#include "type-stringifier.hpp"
+
+void
+TypeAccessor::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ log("type walking\n");
+ add_all_fields_in_struct(t);
+}
+
+void
+TypeAccessor::add_all_fields_in_struct(const_tree t)
+{
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(t);
+ log("am i in add all fields ? %s\n", name.c_str());
+ const enum tree_code c = TREE_CODE(t);
+ const bool is_record = RECORD_TYPE == c;
+ if (!is_record) return;
+
+ const bool record_already_in_map = _map.find(t) != _map.end();
+ field_access_map_t field_map;
+ field_map = record_already_in_map ? _map[t] : field_map;
+
+ // Let's add all fields to the field map as empty.
+ for (tree field = TYPE_FIELDS(t); field; field = DECL_CHAIN(field))
+ {
+ const bool field_already_in_map_2 = field_map.find(field) != field_map.end();
+ if (field_already_in_map_2) continue;
+ field_map[field] = Empty;
+ }
+
+ _map[t] = field_map;
+}
diff --git a/gcc/type-accessor.hpp b/gcc/type-accessor.hpp
new file mode 100644
index 00000000000..d86bf287f1a
--- /dev/null
+++ b/gcc/type-accessor.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "expr-accessor.hpp"
+#include "type-walker.hpp"
+
+typedef std::map<const_tree, unsigned> field_access_map_t;
+typedef std::map<const_tree, field_access_map_t> record_field_map_t;
+
+class TypeAccessor : public TypeWalker
+{
+public:
+ TypeAccessor(record_field_map_t &map) : _map(map) { };
+private:
+ record_field_map_t &_map;
+ virtual void _walk_RECORD_TYPE_pre(const_tree t) final;
+ void add_all_fields_in_struct(const_tree t);
+};
diff --git a/gcc/type-canonical-equality.c b/gcc/type-canonical-equality.c
new file mode 100644
index 00000000000..93221c0a86f
--- /dev/null
+++ b/gcc/type-canonical-equality.c
@@ -0,0 +1,56 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-structural-equality.hpp"
+#include "type-structural-main-variant.hpp"
+#include "type-canonical-equality.hpp"
+#include "type-stringifier.hpp"
+
+bool
+TypeCanonicalEquality::_equal(const_tree l, const_tree r)
+{
+ bool valid_inputs = l && r;
+ if (!valid_inputs) return l == r;
+
+ const_tree canonical_l = TYPE_CANONICAL(l);
+ const_tree canonical_r = TYPE_CANONICAL(r);
+ const bool can_compare_canonical = canonical_l && canonical_r;
+ if (!can_compare_canonical) return TypeStructuralEquality::_equal(l, r);
+
+ const bool different = canonical_l != canonical_r;
+ const std::string n_l = TypeStringifier::get_type_identifier(l);
+ const std::string n_r = TypeStringifier::get_type_identifier(r);
+ if (different) return false;
+
+ return TypeStructuralEqualityMainVariant::_equal(l, r);
+}
diff --git a/gcc/type-canonical-equality.hpp b/gcc/type-canonical-equality.hpp
new file mode 100644
index 00000000000..98a159b4dd0
--- /dev/null
+++ b/gcc/type-canonical-equality.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "type-structural-main-variant.hpp"
+
+class TypeCanonicalEquality : public TypeStructuralEqualityMainVariant {
+public:
+ TypeCanonicalEquality() {};
+protected:
+ virtual bool _equal(const_tree l, const_tree r);
+};
diff --git a/gcc/type-collector.c b/gcc/type-collector.c
new file mode 100644
index 00000000000..e5bccb0a34a
--- /dev/null
+++ b/gcc/type-collector.c
@@ -0,0 +1,271 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "type-collector.hpp"
+#include "type-stringifier.hpp"
+#include "types-inlines.h"
+
+void
+TypeCollector::collect(const_tree t)
+{
+ const bool in_set = ptrset.in_universe(t);
+ // memoization...
+ if (in_set) return;
+ gcc_assert(t);
+
+ if (!ptr.empty())
+ {
+ TypeStringifier stringifier;
+ std::string in_name = stringifier.stringify(t);
+ gcc_unreachable();
+ }
+ walk(t);
+}
+
+void
+TypeCollector::_sanity_check()
+{
+ for (auto i = ptrset.points_to_record.cbegin(), e = ptrset.points_to_record.cend(); i != e; ++i)
+ {
+ for (auto j = ptrset.complement.cbegin(), f = ptrset.complement.cend(); j != f; ++j)
+ {
+ const_tree type_ptr = *i;
+ gcc_assert(type_ptr);
+ const_tree type_com = *j;
+ gcc_assert(type_com);
+ const bool valid_sets = type_ptr != type_com;
+ if (valid_sets) continue;
+ // Normally, we want a stronger type comparison
+ // that is not just the pointer address
+ // but this is the first sanity check and then we will need to determine
+ // the stronger type comparison.
+ // But first we will need to fix the types...
+ TypeStringifier stringifier;
+ std::string name_ptr = stringifier.stringify(type_ptr);
+ std::string name_com = stringifier.stringify(type_com);
+ log("%p %s == %p %s\n", type_ptr, name_ptr.c_str(), type_com, name_com.c_str());
+ gcc_unreachable();
+ }
+ }
+}
+
+bool
+TypeCollector::is_memoized(const_tree t)
+{
+ const bool in_set = ptrset.in_universe(t);
+ if (!in_set) return false;
+
+ const bool points_to_record = ptrset.in_points_to_record(t);
+ for (auto i = ptr.begin(), e = ptr.end(); i != e; ++i)
+ {
+ i->second |= points_to_record;
+ }
+ return true;
+}
+
+void
+TypeCollector::_walk_VOID_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_VOID_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_INTEGER_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_INTEGER_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_REAL_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_REAL_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_FIXED_POINT_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_FIXED_POINT_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_COMPLEX_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_COMPLEX_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_ENUMERAL_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_ENUMERAL_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_BOOLEAN_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_BOOLEAN_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_collect_simple(const_tree t)
+{
+ ptrset.insert(t, ptr[t]);
+ ptr.erase(t);
+}
+
+void
+TypeCollector::_walk_ARRAY_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_ARRAY_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_POINTER_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_POINTER_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_REFERENCE_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_REFERENCE_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_RECORD_TYPE_post(const_tree t)
+{
+ // All in ptr point to record
+ for (auto i = ptr.begin(), e = ptr.end(); i != e; ++i)
+ {
+ i->second = true;
+ }
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_UNION_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_UNION_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_FUNCTION_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_FUNCTION_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
+
+void
+TypeCollector::_walk_METHOD_TYPE_post(const_tree t)
+{
+ _collect_simple(t);
+}
+
+void
+TypeCollector::_walk_METHOD_TYPE_pre(const_tree t)
+{
+ ptr[t] = false;
+}
diff --git a/gcc/type-collector.hpp b/gcc/type-collector.hpp
new file mode 100644
index 00000000000..0252747ee9a
--- /dev/null
+++ b/gcc/type-collector.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "type-walker.hpp"
+#include "collect-types.h"
+#include <map>
+#include <stack>
+
+class TypeCollector : public TypeWalker {
+public:
+ void collect(const_tree t);
+ TypeCollector() {};
+ ptrset_t get_pointer_set() { _sanity_check(); return ptrset; }
+private:
+ std::map<const_tree, bool> ptr;
+ ptrset_t ptrset;
+ void _sanity_check();
+ void _collect_simple(const_tree t);
+ virtual bool is_memoized(const_tree t);
+
+ virtual void _walk_VOID_TYPE_pre(const_tree t);
+ virtual void _walk_VOID_TYPE_post(const_tree t);
+ virtual void _walk_INTEGER_TYPE_pre(const_tree t);
+ virtual void _walk_INTEGER_TYPE_post(const_tree t);
+ virtual void _walk_REAL_TYPE_pre(const_tree t);
+ virtual void _walk_REAL_TYPE_post(const_tree t);
+ virtual void _walk_FIXED_POINT_TYPE_pre(const_tree t);
+ virtual void _walk_FIXED_POINT_TYPE_post(const_tree t);
+ virtual void _walk_COMPLEX_TYPE_pre(const_tree t);
+ virtual void _walk_COMPLEX_TYPE_post(const_tree t);
+ virtual void _walk_ENUMERAL_TYPE_pre(const_tree t);
+ virtual void _walk_ENUMERAL_TYPE_post(const_tree t);
+ virtual void _walk_BOOLEAN_TYPE_pre(const_tree t);
+ virtual void _walk_BOOLEAN_TYPE_post(const_tree t);
+ virtual void _walk_ARRAY_TYPE_pre(const_tree t);
+ virtual void _walk_ARRAY_TYPE_post(const_tree t);
+ virtual void _walk_POINTER_TYPE_pre(const_tree t);
+ virtual void _walk_POINTER_TYPE_post(const_tree t);
+ virtual void _walk_REFERENCE_TYPE_pre(const_tree t);
+ virtual void _walk_REFERENCE_TYPE_post(const_tree t);
+ virtual void _walk_RECORD_TYPE_pre(const_tree t);
+ virtual void _walk_RECORD_TYPE_post(const_tree t);
+ virtual void _walk_UNION_TYPE_pre(const_tree t);
+ virtual void _walk_UNION_TYPE_post(const_tree t);
+ virtual void _walk_FUNCTION_TYPE_pre(const_tree t);
+ virtual void _walk_FUNCTION_TYPE_post(const_tree t);
+ virtual void _walk_METHOD_TYPE_pre(const_tree t);
+ virtual void _walk_METHOD_TYPE_post(const_tree t);
+};
+
diff --git a/gcc/type-escaper.c b/gcc/type-escaper.c
new file mode 100644
index 00000000000..870c2453bba
--- /dev/null
+++ b/gcc/type-escaper.c
@@ -0,0 +1,231 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+#include "types-inlines.h"
+
+#include "type-escaper.hpp"
+#include "type-stringifier.hpp"
+
+bool
+TypeEscaper::is_memoized(const_tree t)
+{
+ const bool in_set = calc.find(t) != calc.end();
+ if (!in_set) return false;
+
+ const bool will_not_escape = !_reason.is_escaping();
+ if (will_not_escape) return true;
+
+ const bool already_escaping = in_set && calc[t].is_escaping();
+ if (already_escaping) return true;
+
+ return false;
+}
+
+static inline void
+assert_type_is_in_universe(const_tree type, ptrset_t &types)
+{
+#ifdef SANITY_CHECKS
+ gcc_assert(types.in_universe(type));
+#endif
+}
+
+ptrset_t
+TypeEscaper::get_sets()
+{
+ place_escaping_types_in_set();
+ return _ptrset;
+}
+
+void
+TypeEscaper::place_escaping_types_in_set()
+{
+ TypeStringifier stringifier;
+ for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i)
+ {
+ const_tree type = i->first;
+ // We should have seen it before
+ assert_type_is_in_universe(type, _ptrset);
+
+ // We should only track interesting types
+ // Types which are not in points_to_record are the ones
+ // that are pointed to by records.
+ // I think it is possible to prune them ahead of time...
+ if (!_ptrset.in_points_to_record(type)) continue;
+
+ const Reason reason = i->second;
+ std::string name = stringifier.stringify(type);
+ reason.is_escaping() ? _ptrset.escaping.insert(type) : _ptrset.non_escaping.insert(type);
+ }
+}
+
+void
+TypeEscaper::update(const_tree t, Reason r)
+{
+ gcc_assert(t);
+ _reason = r;
+ walk(t);
+}
+
+void
+TypeEscaper::update_single_level(const_tree t, Reason r)
+{
+ gcc_assert(t);
+ const bool already_in_typemap = calc.find(t) != calc.end();
+ already_in_typemap ? calc[t] |= r : calc[t] = r;
+}
+
+void
+TypeEscaper::_update(const_tree t)
+{
+ gcc_assert(t);
+ // assert type is in universe
+ const bool already_in_typemap = calc.find(t) != calc.end();
+ // Do we have to invalidate all types which point to a volatile type?
+ // Or do we have to invalidate all types pointed to by a volatile type?
+ // Or do we only invalidate all types which are volatile.
+ // This is only the third option.
+ const bool is_volatile = TYPE_VOLATILE(t);
+ Reason _is_volatile;
+ _is_volatile.type_is_volatile = is_volatile;
+ Reason _inner = _reason | _is_volatile;
+ _inner.type_is_casted = _inside_indirect_field > 0 ? false : _inner.type_is_casted;
+ if (_inside_function > 0) _inner.type_is_casted = false;
+ already_in_typemap ? calc[t] |= _inner : calc[t] = _inner;
+}
+
+void
+TypeEscaper::_walk_ARRAY_TYPE_pre(const_tree t)
+{
+ _update(t);
+}
+
+void
+TypeEscaper::_walk_POINTER_TYPE_pre(const_tree t)
+{
+ _inside_indirect_field = _inside_field > 0 ? _inside_indirect_field + 1 : _inside_indirect_field;
+ _update(t);
+}
+
+void
+TypeEscaper::_walk_POINTER_TYPE_post(const_tree t)
+{
+ _inside_indirect_field = _inside_field > 0 ? _inside_indirect_field - 1 : _inside_indirect_field;
+}
+
+void
+TypeEscaper::_walk_REFERENCE_TYPE_pre(const_tree t)
+{
+ _update(t);
+}
+
+void
+TypeEscaper::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ _update(t);
+}
+
+void
+TypeEscaper::_walk_UNION_TYPE_pre(const_tree t)
+{
+ _inside_union++;
+ bool is_escaping = _inside_union > 0;
+ _update(t);
+ // After us... so that we can see what is our previous value
+ _reason.type_is_in_union |= is_escaping;
+}
+
+void
+TypeEscaper::_walk_field_pre(const_tree t)
+{
+ _inside_field++;
+}
+
+void
+TypeEscaper::_walk_field_post(const_tree t)
+{
+ _inside_field--;
+}
+
+void
+TypeEscaper::_walk_UNION_TYPE_post(const_tree t)
+{
+ _inside_union--;
+ Reason prev = calc[t];
+ _update(t);
+ _reason = prev;
+}
+
+void
+TypeEscaper::_walk_FUNCTION_TYPE_pre(const_tree t)
+{
+ _inside_function++;
+}
+
+void
+TypeEscaper::_walk_FUNCTION_TYPE_post(const_tree t)
+{
+ _inside_function--;
+}
+void
+TypeEscaper::_walk_function_or_method(const_tree t)
+{
+}
+
+
+void
+TypeEscaper::_walk_FUNCTION_TYPE(const_tree t)
+{
+}
+
+void
+TypeEscaper::_walk_METHOD_TYPE(const_tree t)
+{
+}
+
+
+void
+TypeEscaper::_walk_METHOD_TYPE_pre(const_tree t)
+{
+}
+
+void
+TypeEscaper::print_reasons()
+{
+ TypeStringifier stringifier;
+ for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i)
+ {
+ const_tree t = i->first;
+ std::string name = stringifier.stringify(t);
+ const bool in_universe = _ptrset.in_universe(t);
+ Reason r = i->second;
+ log("%s reason: ", name.c_str());
+ r.print();
+ }
+}
diff --git a/gcc/type-escaper.hpp b/gcc/type-escaper.hpp
new file mode 100644
index 00000000000..3647374f716
--- /dev/null
+++ b/gcc/type-escaper.hpp
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "type-walker.hpp"
+#include "ipa-prototype.h"
+#include "collect-types.h"
+#include <map>
+
+class TypeEscaper : public TypeWalker
+{
+public:
+ TypeEscaper(ptrset_t &p) : _ptrset(p), _inside_union(0), _inside_field(0), _inside_indirect_field(0), _inside_function(0) {};
+ void update(const_tree t, Reason r);
+ void update_single_level(const_tree t, Reason r);
+ ptrset_t get_sets();
+ ptrset_t &_ptrset;
+ typemap calc;
+ void print_reasons();
+ virtual void _walk_POINTER_TYPE_pre(const_tree t) final;
+ virtual void _walk_POINTER_TYPE_post(const_tree t) final;
+ virtual void _walk_REFERENCE_TYPE_pre(const_tree t) final;
+ virtual void _walk_ARRAY_TYPE_pre(const_tree t) final;
+ virtual void _walk_RECORD_TYPE_pre(const_tree t) final;
+ virtual void _walk_UNION_TYPE_pre(const_tree t) final;
+ virtual void _walk_UNION_TYPE_post(const_tree t) override final;
+ virtual void _walk_METHOD_TYPE_pre(const_tree t) final override;
+ virtual void _walk_FUNCTION_TYPE_pre(const_tree t) final override;
+ virtual void _walk_FUNCTION_TYPE_post(const_tree t) final override;
+ virtual void _walk_METHOD_TYPE(const_tree t) final override;
+ virtual void _walk_FUNCTION_TYPE(const_tree t) final override;
+ virtual void _walk_function_or_method(const_tree t) final override;
+ virtual void _walk_field_pre(const_tree t) final;
+ virtual void _walk_field_post(const_tree t) final;
+ virtual bool is_memoized(const_tree t);
+ unsigned _inside_union;
+ unsigned _inside_field;
+ unsigned _inside_indirect_field;
+ unsigned _inside_function;
+ Reason _reason;
+ void _update(const_tree t);
+ void place_escaping_types_in_set();
+};
+
diff --git a/gcc/type-incomplete-equality.c b/gcc/type-incomplete-equality.c
new file mode 100644
index 00000000000..88072c40022
--- /dev/null
+++ b/gcc/type-incomplete-equality.c
@@ -0,0 +1,61 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-structural-equality.hpp"
+#include "type-structural-main-variant.hpp"
+#include "type-canonical-equality.hpp"
+#include "type-incomplete-equality.hpp"
+#include "type-stringifier.hpp"
+
+bool
+TypeIncompleteEquality::_equal(const_tree l, const_tree r)
+{
+ bool valid_inputs = l && r;
+ if (!valid_inputs) return l == r;
+
+ // if any of these are incomplete, then we can only compare using identifiers...
+ const bool complete_l = is_complete(l);
+ const bool complete_r = is_complete(r);
+ bool can_compare_structurally = complete_l && complete_r;
+ if (can_compare_structurally) return TypeStructuralEquality::_equal(l, r);
+
+ const_tree m_l = TYPE_MAIN_VARIANT(l);
+ const_tree m_r = TYPE_MAIN_VARIANT(r);
+ gcc_assert(m_l && m_r);
+ can_compare_structurally = m_l == m_r;
+ if (can_compare_structurally) return true;
+
+ const std::string n_l = TypeStringifier::get_type_identifier(m_l);
+ const std::string n_r = TypeStringifier::get_type_identifier(m_r);
+ return n_l.compare(n_r) == 0;
+}
diff --git a/gcc/type-incomplete-equality.hpp b/gcc/type-incomplete-equality.hpp
new file mode 100644
index 00000000000..4188f49713c
--- /dev/null
+++ b/gcc/type-incomplete-equality.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "type-canonical-equality.hpp"
+
+class TypeIncompleteEquality : public TypeCanonicalEquality {
+public:
+ TypeIncompleteEquality () {};
+protected:
+ virtual bool _equal(const_tree l, const_tree r);
+};
diff --git a/gcc/type-reconstructor.c b/gcc/type-reconstructor.c
new file mode 100644
index 00000000000..91d4f383ea7
--- /dev/null
+++ b/gcc/type-reconstructor.c
@@ -0,0 +1,412 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+#include "types-inlines.h"
+
+#include "type-reconstructor.hpp"
+#include "type-stringifier.hpp"
+#include "stor-layout.h"
+
+
+// TODO:
+// I think it might be possible that we need to create
+// new nodes as opposed to copying the nodes.
+// I say this because I think the copy is a shallow copy
+// and it might be making things difficult if we don't
+// know everything that is happening...
+// so we might want to rewrite this class...
+//
+//
+// TODO:
+// Also, there's a bug in which the TYPE_MAIN_VARIANT is an old type...
+// which is not a good thing.
+
+void
+TypeReconstructor::set_is_not_modified_yet(const_tree t)
+{
+ gcc_assert(t);
+ const bool is_in_reorg_map = _reorg_map.find(t) != _reorg_map.end();
+ modified_map[t] = false;
+ if (is_in_reorg_map) mark_all_pointing_here_as_modified();
+
+ const_tree tt = TREE_TYPE(t);
+ if (!tt) return;
+
+ const bool is_in_reorg_map_2 = _reorg_map.find(tt) != _reorg_map.end();
+ log ("is in reorg_map_2 ? %s\n", is_in_reorg_map_2 ? "t" : "f");
+ if (!is_in_reorg_map_2) return;
+
+ tree type = _reorg_map[tt];
+ const bool is_modified = strstr(TypeStringifier::get_type_identifier(type).c_str(), ".reorg");
+ log("is modified %s\n", is_modified ? "t" : "f");
+ if (!is_modified) return;
+
+ mark_all_pointing_here_as_modified();
+
+}
+
+void
+TypeReconstructor::mark_all_pointing_here_as_modified()
+{
+ for (auto i = modified_map.begin(), e = modified_map.end(); i != e; ++i)
+ {
+ const_tree type = i->first;
+ i->second = true;
+ }
+}
+
+bool
+TypeReconstructor::get_is_modified(const_tree t)
+{
+ gcc_assert(t);
+ const bool in_map = modified_map.find(t) != modified_map.end();
+ gcc_assert(in_map);
+ bool retval = modified_map[t];
+ modified_map.erase(t);
+
+ bool points_to_record = false;
+ tree tt = (tree)t;
+ while (TREE_TYPE(tt))
+ {
+ tt = TREE_TYPE(tt);
+ }
+ points_to_record = TREE_CODE(tt) == RECORD_TYPE;
+
+
+ return retval && points_to_record;
+}
+
+bool
+TypeReconstructor::is_memoized(const_tree t)
+{
+ const bool already_changed = _reorg_map.find(t) != _reorg_map.end();
+ mark_all_pointing_here_as_modified();
+ const bool has_typed_cached_values = TYPE_CACHED_VALUES_P (t);
+ TypeStringifier stringifier;
+ std::string name = stringifier.stringify(t);
+ return already_changed;
+}
+
+static tree
+get_new_identifier(const_tree type)
+{
+ const char* identifier = TypeStringifier::get_type_identifier(type).c_str();
+ const bool is_new_type = strstr(identifier, "reorg");
+ gcc_assert(!is_new_type);
+ char *new_name;
+ asprintf(&new_name, "%s.reorg", identifier);
+ return get_identifier(new_name);
+}
+
+// Invariant for all _pre functions:
+// _reorg_map[t] == NULL (due to memoization)
+//
+// Invariant for all _post functions:
+// _reorg_map[TREE_TYPE(t)] != NULL
+// unless TREE_TYPE(t) is not a type which points to a record
+// a.k.a. no modifications
+//
+// To preserve invariant, we must include
+// the following at the end of all _post functions:
+// _reorg_map[t] = /* reorg type */
+//
+// How information is passed?
+// To further _post functions via stacks
+//
+// To previous _post functions via _reorg_map (and maybe others?)
+//
+//
+void
+TypeReconstructor::_walk_ARRAY_TYPE_pre(const_tree t)
+{
+ for_reference.push(t);
+ set_is_not_modified_yet(t);
+
+ tree copy = build_variant_type_copy((tree) t);
+ tree domain = TYPE_DOMAIN(t);
+ if (domain) {
+ tree copy_domain = copy_node(domain);
+ tree min = TYPE_MIN_VALUE(domain);
+ tree max = TYPE_MAX_VALUE(domain);
+ TYPE_MIN_VALUE(copy_domain) = copy_node(min);
+ TYPE_MAX_VALUE(copy_domain) = copy_node(max);
+ }
+ in_progress.push(copy);
+
+}
+
+void
+TypeReconstructor::_walk_ARRAY_TYPE_post(const_tree t)
+{
+ const_tree t2 = for_reference.top();
+ gcc_assert(t2 == t);
+ for_reference.pop();
+ tree copy = in_progress.top();
+ in_progress.pop();
+
+ bool is_modified = get_is_modified(t);
+
+ TREE_TYPE(copy) = build_variant_type_copy(TREE_TYPE(copy));
+ copy = is_modified ? build_distinct_type_copy(copy) : copy;
+ TREE_TYPE(copy) = is_modified ? _reorg_map[TREE_TYPE(t)] : TREE_TYPE(copy);
+ TYPE_NAME(copy) = is_modified ? get_new_identifier(copy) : TYPE_NAME(copy);
+ // This is useful so that we go again through type layout
+ TYPE_SIZE(copy) = is_modified ? NULL : TYPE_SIZE(copy);
+ tree domain = TYPE_DOMAIN(t);
+ if (domain) {
+ tree copy_domain = copy_node(domain);
+ tree min = TYPE_MIN_VALUE(domain);
+ tree max = TYPE_MAX_VALUE(domain);
+ TYPE_MIN_VALUE(copy_domain) = copy_node(min);
+ TYPE_MAX_VALUE(copy_domain) = copy_node(max);
+ }
+ TypeStringifier stringifier;
+ //std::string name = stringifier.stringify(copy);
+ log("are we going to crash is modified %s %s\n", is_modified ? "t" : "f", TypeStringifier::get_type_identifier(copy).c_str());
+ if (is_modified) layout_type(copy);
+ TYPE_CACHED_VALUES_P (copy) = false;
+ //TYPE_CACHED_VALUES (copy) = TYPE_CACHED_VALUES(t);
+ tree tt = (tree)t;
+ while (TREE_TYPE(tt)) { tt = TREE_TYPE(tt); };
+
+ const bool points_to_record = TREE_CODE(tt) == RECORD_TYPE;
+ if (!points_to_record) return;
+
+ _reorg_map[t] = is_modified ? copy : (tree)t;
+}
+
+void
+TypeReconstructor::_walk_POINTER_TYPE_pre(const_tree t)
+{
+ for_reference.push(t);
+ set_is_not_modified_yet(t);
+
+ tree copy = build_variant_type_copy((tree) t);
+ in_progress.push(copy);
+}
+
+void
+TypeReconstructor::_walk_POINTER_TYPE_post(const_tree t)
+{
+ const_tree t2 = for_reference.top();
+ gcc_assert(t2 == t);
+ for_reference.pop();
+ tree copy = in_progress.top();
+ in_progress.pop();
+
+ bool is_modified = get_is_modified(t);
+
+ copy = is_modified ? build_variant_type_copy(copy) : copy;
+ TREE_TYPE(copy) = is_modified ? _reorg_map[TREE_TYPE(t)] : TREE_TYPE(copy);
+ TYPE_NAME(copy) = is_modified ? get_new_identifier(copy) : TYPE_NAME(copy);
+ // This is useful so that we go again through type layout
+ //TYPE_SIZE(copy) = is_modified ? NULL : TYPE_SIZE(copy);
+ //if (is_modified) layout_type(copy);
+ TYPE_CACHED_VALUES_P (copy) = false;
+ //TYPE_CACHED_VALUES (copy) = TYPE_CACHED_VALUES(t);
+ //Let's just make sure that we are pointing to a a struct...
+
+ tree tt = (tree)t;
+ while (TREE_TYPE(tt)) { tt = TREE_TYPE(tt); };
+ const bool points_to_record = TREE_CODE(tt) == RECORD_TYPE;
+ if (!points_to_record) return;
+
+ _reorg_map[t] = is_modified ? copy : (tree)t;
+}
+
+void
+TypeReconstructor::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ const bool is_main_variant = TYPE_MAIN_VARIANT(t) == t;
+ if (!is_main_variant) {
+ const_tree main_variant = TYPE_MAIN_VARIANT(t);
+ _walk_RECORD_TYPE_pre(main_variant);
+ TypeWalker::_walk_RECORD_TYPE(main_variant);
+ _walk_RECORD_TYPE_post(main_variant);
+ }
+
+ set_is_not_modified_yet(t);
+ for_reference.push(t);
+ // We don't know if we will modify this type t
+ // So, let's make a copy. Just in case.
+ tree copy = build_variant_type_copy((tree) t);
+ in_progress.push(copy);
+ field_list_stack.push( field_tuple_list_t() );
+}
+
+void
+TypeReconstructor::_walk_RECORD_TYPE_post(const_tree t)
+{
+ const_tree t2 = for_reference.top();
+ gcc_assert(t2 == t);
+ for_reference.pop();
+
+ tree copy = in_progress.top();
+ in_progress.pop();
+ field_tuple_list_t field_tuple_list = field_list_stack.top();
+ field_list_stack.pop();
+
+ // So, here all the work has been done to make sure
+ // that the fields produced a field_tuple_list_t
+ // with old fields and pointers to new fields.
+ // There might be NULL values if new fields are eliminated.
+ // So, now we want to do a couple of things.
+ // First, is we need to change the TYPE_FIELDS
+ // of the copy
+ bool is_modified = get_is_modified(t);
+ tree prev_field = NULL;
+ for (auto i = field_tuple_list.cbegin(), e = field_tuple_list.cend(); i != e; ++i)
+ {
+ field_tuple_t field_tuple = *i;
+ const_tree original_field = field_tuple.first;
+ tree modified_field = field_tuple.second;
+ if (!modified_field) {
+ is_modified = true;
+ continue;
+ }
+
+ tree current_field = modified_field;
+ if (!prev_field) {
+ TYPE_FIELDS(copy) = current_field;
+ } else {
+ DECL_CHAIN(prev_field) = current_field;
+ }
+ prev_field = current_field;
+ }
+
+ // We only had one field
+ if (!prev_field && is_modified) {
+ log("deleting all fields for struct %s\n", TypeStringifier::get_type_identifier(copy).c_str());
+ TYPE_FIELDS(copy) = NULL;
+ }
+
+
+ const bool is_main_variant = TYPE_MAIN_VARIANT(t) == t;
+ // We already must have done the main variant...
+ if (!is_main_variant)
+ {
+ tree main = TYPE_MAIN_VARIANT(t);
+ tree main_reorg = _reorg_map[main];
+ TypeStringifier stringifier;
+ std::string main_s = stringifier.stringify(main_reorg);
+ log("is modified %s main variant reorged build variant type %s\n", is_modified ? "T" : "F", main_s.c_str());
+ tree copy_variant = build_variant_type_copy(main_reorg);
+ TYPE_NAME(copy_variant) = get_new_identifier(copy);
+ TYPE_SIZE(copy_variant) = NULL;
+ TYPE_MAIN_VARIANT(copy_variant) = main_reorg;
+ TYPE_SIZE(main_reorg) = NULL;
+ layout_type(copy_variant);
+ _reorg_map[t] = copy_variant;
+ } else {
+ // Ok, so now that we have fixed the TYPE_FIELDS of the copy...
+ // We need to call layout_type
+ copy = is_modified ? build_distinct_type_copy(copy) : copy;
+ TYPE_NAME(copy) = is_modified ? get_new_identifier(copy) : TYPE_NAME(copy);
+ // This is useful so that we go again through type layout
+ TYPE_SIZE(copy) = is_modified ? NULL : TYPE_SIZE(copy);
+ TYPE_MAIN_VARIANT(copy) = is_modified ? copy : TYPE_MAIN_VARIANT(copy);
+ tree main_variant = TYPE_MAIN_VARIANT(copy);
+ TypeStringifier stringifier;
+ std::string main_s = stringifier.stringify(main_variant);
+ log("main variant reorged build distinct %s\n", main_s.c_str());
+ if (is_modified) layout_type(copy);
+ _reorg_map[t] = is_modified ? copy : (tree)t;
+ }
+
+ tree record = _reorg_map[t];
+ for (tree field = TYPE_FIELDS(record); field; field = DECL_CHAIN(field))
+ {
+ relayout_decl(field);
+ }
+
+}
+
+void
+TypeReconstructor::_walk_UNION_TYPE_pre(const_tree t)
+{
+}
+
+void
+TypeReconstructor::_walk_UNION_TYPE_post(const_tree t)
+{
+}
+
+void
+TypeReconstructor::_walk_field_pre(const_tree t)
+{
+ for_reference.push(t);
+ // We don't know if we will rewrite the field
+ // that we are working on. So proactively, let's make
+ // a copy
+ tree copy = copy_node((tree) t);
+ tree type_copy = build_variant_type_copy((tree)(TREE_TYPE(t)));
+ TREE_TYPE(copy) = type_copy;
+ // To communicate this field to the other methods,
+ // let's put it in the "in_progress" stack.
+ in_progress.push(copy);
+}
+
+void
+TypeReconstructor::_walk_field_post(const_tree t)
+{
+ const_tree t2 = for_reference.top();
+ gcc_assert(t2 == t);
+ for_reference.pop();
+
+ // Let's get the copy we were working on.
+ tree copy = in_progress.top();
+ // Let's put the stack in the same position...
+ in_progress.pop();
+
+ // What record does this field belongs to?
+ const_tree record = for_reference.top();
+
+ field_offsets_t field_offsets = _records[record];
+ // What's the field offset?
+ unsigned f_byte_offset = tree_to_uhwi(DECL_FIELD_OFFSET(t));
+ unsigned f_bit_offset = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(t));
+ unsigned f_offset = 8 * f_byte_offset + f_bit_offset;
+
+ const bool can_field_be_deleted = field_offsets.find(f_offset) != field_offsets.end();
+ if (can_field_be_deleted) mark_all_pointing_here_as_modified();
+ const_tree original_type = TREE_TYPE(t);
+ const bool type_memoized = is_memoized(original_type);
+
+ TREE_TYPE(copy) = type_memoized ? _reorg_map[original_type] : TREE_TYPE(copy);
+
+ field_tuple_t tuple = std::make_pair(t, can_field_be_deleted ? NULL : copy);
+
+ // Put the field into the vector
+ field_tuple_list_t &field_tuple_list = field_list_stack.top();
+ field_tuple_list.push_back(tuple);
+ const bool already_has_field = _reorg_fields.find(t) != _reorg_fields.end();
+ if (already_has_field) return;
+ _reorg_fields[t] = std::make_pair(copy, can_field_be_deleted);
+}
diff --git a/gcc/type-reconstructor.hpp b/gcc/type-reconstructor.hpp
new file mode 100644
index 00000000000..4623fc88346
--- /dev/null
+++ b/gcc/type-reconstructor.hpp
@@ -0,0 +1,47 @@
+#pragma once
+
+#include <set>
+#include <map>
+#include <stack>
+#include <vector>
+
+#include "type-walker.hpp"
+
+class TypeReconstructor : public TypeWalker
+{
+public:
+ typedef std::map<const_tree, tree> reorg_record_map_t;
+ typedef std::map<const_tree, std::pair<tree, bool>> reorg_field_map_t;
+ typedef std::map<const_tree, bool> is_modified_map_t;
+ typedef std::set<unsigned> field_offsets_t;
+ typedef std::map<const_tree, field_offsets_t> record_field_offset_map_t;
+private:
+ std::stack<tree> in_progress;
+ std::stack<const_tree> for_reference;
+ typedef std::pair<const_tree, tree> field_tuple_t;
+ typedef std::vector<field_tuple_t> field_tuple_list_t;
+ typedef std::stack<field_tuple_list_t> field_tuple_list_stack_t;
+ record_field_offset_map_t _records;
+ field_tuple_list_stack_t field_list_stack;
+ reorg_record_map_t _reorg_map;
+ reorg_field_map_t _reorg_fields;
+ is_modified_map_t modified_map;
+ void set_is_not_modified_yet(const_tree);
+ void mark_all_pointing_here_as_modified();
+ bool get_is_modified(const_tree);
+ virtual void _walk_field_pre(const_tree);
+ virtual void _walk_field_post(const_tree);
+ virtual void _walk_RECORD_TYPE_pre(const_tree);
+ virtual void _walk_RECORD_TYPE_post(const_tree);
+ virtual void _walk_UNION_TYPE_pre(const_tree);
+ virtual void _walk_UNION_TYPE_post(const_tree);
+ virtual void _walk_ARRAY_TYPE_pre(const_tree);
+ virtual void _walk_ARRAY_TYPE_post(const_tree);
+ virtual void _walk_POINTER_TYPE_pre(const_tree);
+ virtual void _walk_POINTER_TYPE_post(const_tree);
+public:
+ virtual bool is_memoized(const_tree t);
+ TypeReconstructor(record_field_offset_map_t records) : _records(records) {};
+ reorg_record_map_t get_map() { return _reorg_map; };
+ reorg_field_map_t get_field_map() { return _reorg_fields; };
+};
diff --git a/gcc/type-stringifier.c b/gcc/type-stringifier.c
new file mode 100644
index 00000000000..39e4e0ec9dc
--- /dev/null
+++ b/gcc/type-stringifier.c
@@ -0,0 +1,246 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "type-stringifier.hpp"
+#include "types-inlines.h"
+#include <string>
+
+std::string
+TypeStringifier::stringify(const_tree t)
+{
+ _stringification.clear();
+ gcc_assert(t);
+ walk(t);
+ return _stringification;
+}
+
+void
+TypeStringifier::_walk_VOID_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_INTEGER_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_REAL_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_FIXED_POINT_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_COMPLEX_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_OFFSET_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_walk_BOOLEAN_TYPE_pre(const_tree t)
+{
+ _stringify_simple(t);
+}
+
+void
+TypeStringifier::_stringify_simple(const_tree t)
+{
+ gcc_assert(t);
+ const enum tree_code code = TREE_CODE(t);
+ this->_stringification += std::string(get_tree_code_name(code));
+}
+
+void
+TypeStringifier::_walk_POINTER_TYPE_post(__attribute__((unused))const_tree t)
+{
+ this->_stringification += std::string("*");
+}
+
+void
+TypeStringifier::_walk_ARRAY_TYPE_post(__attribute__((unused))const_tree t)
+{
+ this->_stringification += std::string("[]");
+}
+
+void
+TypeStringifier::_walk_REFERENCE_TYPE_post(__attribute__((unused))const_tree t)
+{
+ this->_stringification += std::string("&");
+}
+
+void
+TypeStringifier::_walk_UNION_TYPE_pre(const_tree t)
+{
+ this->_stringification += std::string(" union ");
+ _stringify_aggregate_pre(t);
+}
+
+void
+TypeStringifier::_walk_UNION_TYPE_post(const_tree t)
+{
+ _stringify_aggregate_post(t);
+}
+
+void
+TypeStringifier::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ this->_stringification += std::string(" record ");
+ _stringify_aggregate_pre(t);
+}
+
+void
+TypeStringifier::_walk_RECORD_TYPE_post(const_tree t)
+{
+ _stringify_aggregate_post(t);
+}
+
+void
+TypeStringifier::_stringify_aggregate_pre(const_tree t)
+{
+ this->_stringification += TypeStringifier::get_type_identifier(t) + std::string(" {");
+}
+
+void
+TypeStringifier::_stringify_aggregate_post(__attribute__((unused))const_tree t)
+{
+ this->_stringification += std::string("}");
+}
+
+void
+TypeStringifier::_walk_field_post(const_tree t)
+{
+ this->_stringification += std::string(" ") + TypeStringifier::get_field_identifier(t) + std::string(";");
+}
+
+void
+TypeStringifier::_walk_METHOD_TYPE_pre(const_tree t)
+{
+ _stringify_fm_pre(t);
+}
+
+void
+TypeStringifier::_walk_METHOD_TYPE_post(const_tree t)
+{
+ _stringify_fm_post(t);
+}
+
+void
+TypeStringifier::_walk_FUNCTION_TYPE_pre(const_tree t)
+{
+ _stringify_fm_pre(t);
+}
+
+void
+TypeStringifier::_walk_FUNCTION_TYPE_post(const_tree t)
+{
+ _stringify_fm_post(t);
+}
+
+void
+TypeStringifier::_stringify_fm_pre(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string("function { ");
+}
+
+void
+TypeStringifier::_stringify_fm_post(__attribute__((unused))const_tree t)
+{
+ this->_stringification += std::string("}");
+}
+
+void
+TypeStringifier::_walk_return_pre(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string("(");
+}
+
+void
+TypeStringifier::_walk_return_post(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string(")");
+}
+
+void
+TypeStringifier::_walk_args_pre(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string("(");
+}
+
+void
+TypeStringifier::_walk_args_post(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string(")");
+}
+
+void
+TypeStringifier::_walk_arg_post(__attribute__((unused)) const_tree t)
+{
+ this->_stringification += std::string(", ");
+}
+
+std::string
+TypeStringifier::get_type_identifier(const_tree t)
+{
+ tree name = TYPE_NAME(t);
+ const bool no_name = NULL_TREE == name;
+ if (no_name) return std::string("");
+
+ const enum tree_code name_code = TREE_CODE(name);
+ const bool is_name_type_decl = TYPE_DECL == name_code;
+ name = is_name_type_decl ? DECL_NAME(name) : name;
+ const char* identifier_ptr = IDENTIFIER_POINTER(name);
+ gcc_assert(identifier_ptr);
+ return std::string(identifier_ptr);
+}
+
+std::string
+TypeStringifier::get_field_identifier(const_tree t)
+{
+ assert_is_type(t, FIELD_DECL);
+ const_tree decl_name = DECL_NAME(t);
+ if (!decl_name) return std::string("");
+
+ const char* identifier = IDENTIFIER_POINTER(decl_name);
+ return std::string(identifier);
+}
diff --git a/gcc/type-stringifier.hpp b/gcc/type-stringifier.hpp
new file mode 100644
index 00000000000..b2e1261fc62
--- /dev/null
+++ b/gcc/type-stringifier.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "type-walker.hpp"
+#include <string>
+
+class TypeStringifier : public TypeWalker
+{
+private:
+ std::string _stringification;
+
+
+ void _stringify_simple(const_tree t);
+ void _stringify_aggregate_pre(const_tree t);
+ void _stringify_aggregate_post(const_tree t);
+ void _stringify_fm_pre(const_tree t);
+ void _stringify_fm_post(const_tree t);
+
+ virtual void _walk_VOID_TYPE_pre(const_tree t);
+ virtual void _walk_INTEGER_TYPE_pre(const_tree t);
+ virtual void _walk_REAL_TYPE_pre(const_tree t);
+ virtual void _walk_FIXED_POINT_TYPE_pre(const_tree t);
+ virtual void _walk_COMPLEX_TYPE_pre(const_tree t);
+ virtual void _walk_BOOLEAN_TYPE_pre(const_tree t);
+ virtual void _walk_OFFSET_TYPE_pre(const_tree t);
+ virtual void _walk_POINTER_TYPE_post(const_tree t);
+ virtual void _walk_REFERENCE_TYPE_post(const_tree t);
+ virtual void _walk_ARRAY_TYPE_post(const_tree t);
+ virtual void _walk_RECORD_TYPE_pre(const_tree t);
+ virtual void _walk_RECORD_TYPE_post(const_tree t);
+ virtual void _walk_UNION_TYPE_pre(const_tree t);
+ virtual void _walk_UNION_TYPE_post(const_tree t);
+ virtual void _walk_field_post(const_tree t);
+ virtual void _walk_return_pre(const_tree t);
+ virtual void _walk_return_post(const_tree t);
+ virtual void _walk_args_pre(const_tree t);
+ virtual void _walk_args_post(const_tree t);
+ virtual void _walk_arg_post(const_tree t);
+ virtual void _walk_METHOD_TYPE_pre(const_tree t);
+ virtual void _walk_METHOD_TYPE_post(const_tree t);
+ virtual void _walk_FUNCTION_TYPE_pre(const_tree t);
+ virtual void _walk_FUNCTION_TYPE_post(const_tree t);
+public:
+ static std::string get_type_identifier(const_tree t);
+ static std::string get_field_identifier(const_tree t);
+ std::string stringify(const_tree t);
+ TypeStringifier() {};
+};
+
diff --git a/gcc/type-structural-equality.c b/gcc/type-structural-equality.c
new file mode 100644
index 00000000000..6195c259158
--- /dev/null
+++ b/gcc/type-structural-equality.c
@@ -0,0 +1,199 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-structural-equality.hpp"
+#include "type-stringifier.hpp"
+
+bool
+TypeStructuralEquality::equal(const_tree l, const_tree r)
+{
+ return _equal(l, r);
+}
+
+bool
+TypeStructuralEquality::_equal(const_tree l, const_tree r)
+{
+ bool valid_inputs = l && r;
+ if (!valid_inputs) return l == r;
+
+ bool equal_codes = _equal_code(l, r);
+ if (!equal_codes) return equal_codes;
+
+ bool recurse_l = set_l.find(l) != set_l.end();
+ bool recurse_r = set_r.find(r) != set_r.end();
+ // TODO: Is this the case every time?
+ bool recurse = recurse_l || recurse_r;
+ if (recurse) return recurse;
+
+ set_l.insert(l);
+ set_r.insert(r);
+ const enum tree_code code = TREE_CODE(l);
+ bool equal_children = false;
+ switch(code)
+ {
+#define TSE_CASE(code) \
+ case code: \
+ equal_children = _walk_ ## code (l, r); \
+ break
+
+ TSE_CASE(VOID_TYPE);
+ TSE_CASE(INTEGER_TYPE);
+ TSE_CASE(REAL_TYPE);
+ TSE_CASE(FIXED_POINT_TYPE);
+ TSE_CASE(COMPLEX_TYPE);
+ TSE_CASE(ENUMERAL_TYPE);
+ TSE_CASE(BOOLEAN_TYPE);
+ TSE_CASE(OFFSET_TYPE);
+ TSE_CASE(RECORD_TYPE);
+ TSE_CASE(POINTER_TYPE);
+ TSE_CASE(REFERENCE_TYPE);
+ TSE_CASE(ARRAY_TYPE);
+ TSE_CASE(UNION_TYPE);
+ TSE_CASE(FUNCTION_TYPE);
+ TSE_CASE(METHOD_TYPE);
+ default:
+ gcc_unreachable();
+ break;
+ }
+
+ set_l.erase(l);
+ set_r.erase(r);
+ return equal_children;
+
+}
+
+bool
+TypeStructuralEquality::_equal_code(const_tree l, const_tree r)
+{
+ const enum tree_code code_l = TREE_CODE(l);
+ const enum tree_code code_r = TREE_CODE(r);
+ const bool equal = code_l == code_r;
+ return equal;
+}
+
+#define TSE_FUNC_DEF_SIMPLE(code) \
+bool \
+TypeStructuralEquality::_walk_ ## code (const_tree l, const_tree r) \
+{ \
+ return _equal_code(l, r); \
+}
+
+TSE_FUNC_DEF_SIMPLE(VOID_TYPE)
+TSE_FUNC_DEF_SIMPLE(INTEGER_TYPE)
+TSE_FUNC_DEF_SIMPLE(REAL_TYPE)
+TSE_FUNC_DEF_SIMPLE(FIXED_POINT_TYPE)
+TSE_FUNC_DEF_SIMPLE(ENUMERAL_TYPE)
+TSE_FUNC_DEF_SIMPLE(BOOLEAN_TYPE)
+TSE_FUNC_DEF_SIMPLE(OFFSET_TYPE)
+TSE_FUNC_DEF_SIMPLE(COMPLEX_TYPE)
+
+bool
+TypeStructuralEquality::_equal_wrapper(const_tree l, const_tree r)
+{
+ const_tree inner_l = TREE_TYPE(l);
+ const_tree inner_r = TREE_TYPE(r);
+ return _equal(inner_l, inner_r);
+}
+
+#define TSE_FUNC_DEF_WRAPPER(code) \
+bool \
+TypeStructuralEquality::_walk_ ## code (const_tree l, const_tree r) \
+{ \
+ return _equal_wrapper(l, r); \
+}
+
+TSE_FUNC_DEF_WRAPPER(REFERENCE_TYPE)
+TSE_FUNC_DEF_WRAPPER(ARRAY_TYPE)
+TSE_FUNC_DEF_WRAPPER(POINTER_TYPE)
+
+#define TSE_FUNC_DEF_CONTAINER(code) \
+bool \
+TypeStructuralEquality::_walk_ ## code (const_tree l, const_tree r) \
+{ \
+ const_tree field_l = TYPE_FIELDS(l); \
+ const_tree field_r = TYPE_FIELDS(r); \
+ bool efield_l = field_l; \
+ bool efield_r = field_r; \
+ bool still_equal = efield_l == efield_r; \
+ if (!still_equal) return still_equal; \
+ \
+ while (field_l && field_r && still_equal) \
+ { \
+ const_tree tfield_l = TREE_TYPE(field_l); \
+ const_tree tfield_r = TREE_TYPE(field_r); \
+ still_equal &= _equal(tfield_l, tfield_r); \
+ field_l = DECL_CHAIN(field_l); \
+ field_r = DECL_CHAIN(field_r); \
+ efield_l = field_l; \
+ efield_r = field_r; \
+ still_equal &= efield_l == efield_r; \
+ } \
+ return still_equal; \
+}
+
+TSE_FUNC_DEF_CONTAINER(RECORD_TYPE)
+TSE_FUNC_DEF_CONTAINER(UNION_TYPE)
+
+#define TSE_FUNC_DEF_FUNC(code) \
+bool \
+TypeStructuralEquality::_walk_ ## code (const_tree l, const_tree r) \
+{ \
+ const_tree tret_l = TREE_TYPE(l); \
+ const_tree tret_r = TREE_TYPE(r); \
+ bool still_equal = _equal(tret_l, tret_r); \
+ if (!still_equal) return still_equal; \
+ \
+ const_tree arg_l = TYPE_ARG_TYPES(l); \
+ const_tree arg_r = TYPE_ARG_TYPES(r); \
+ bool earg_l = arg_l; \
+ bool earg_r = arg_r; \
+ still_equal &= earg_l == earg_r; \
+ while (arg_l && arg_r && still_equal) \
+ { \
+ const_tree targ_l = TREE_VALUE(arg_l); \
+ const_tree targ_r = TREE_VALUE(arg_r); \
+ still_equal &= _equal(targ_l, targ_r); \
+ arg_l = TREE_CHAIN(arg_l); \
+ arg_r = TREE_CHAIN(arg_r); \
+ earg_l = arg_l; \
+ earg_r = arg_r; \
+ still_equal &= earg_l == earg_r; \
+ } \
+ return still_equal; \
+}
+
+TSE_FUNC_DEF_FUNC(FUNCTION_TYPE)
+TSE_FUNC_DEF_FUNC(METHOD_TYPE)
+
+
+
diff --git a/gcc/type-structural-equality.hpp b/gcc/type-structural-equality.hpp
new file mode 100644
index 00000000000..b5f1944bd31
--- /dev/null
+++ b/gcc/type-structural-equality.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <set>
+
+class TypeStructuralEquality {
+public:
+ TypeStructuralEquality() {};
+ bool equal(const_tree a, const_tree b);
+protected:
+ virtual bool _equal(const_tree a, const_tree b);
+private:
+ typedef std::set<const_tree> tset_t;
+
+ tset_t set_l;
+ tset_t set_r;
+ bool _equal_code(const_tree a, const_tree b);
+ bool _equal_wrapper(const_tree a, const_tree b);
+
+#define TSE_FUNC_DECL(code) \
+ virtual bool _walk_ ## code (const_tree l, const_tree r)
+ TSE_FUNC_DECL(VOID_TYPE);
+ TSE_FUNC_DECL(COMPLEX_TYPE);
+ TSE_FUNC_DECL(INTEGER_TYPE);
+ TSE_FUNC_DECL(REAL_TYPE);
+ TSE_FUNC_DECL(FIXED_POINT_TYPE);
+ TSE_FUNC_DECL(POINTER_TYPE);
+ TSE_FUNC_DECL(ENUMERAL_TYPE);
+ TSE_FUNC_DECL(BOOLEAN_TYPE);
+ TSE_FUNC_DECL(OFFSET_TYPE);
+ TSE_FUNC_DECL(RECORD_TYPE);
+ TSE_FUNC_DECL(REFERENCE_TYPE);
+ TSE_FUNC_DECL(ARRAY_TYPE);
+ TSE_FUNC_DECL(UNION_TYPE);
+ TSE_FUNC_DECL(FUNCTION_TYPE);
+ TSE_FUNC_DECL(METHOD_TYPE);
+
+ const_tree left;
+};
diff --git a/gcc/type-structural-main-variant.c b/gcc/type-structural-main-variant.c
new file mode 100644
index 00000000000..9cc95d5ec63
--- /dev/null
+++ b/gcc/type-structural-main-variant.c
@@ -0,0 +1,49 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+
+
+#include "types-inlines.h"
+#include "type-structural-equality.hpp"
+#include "type-structural-main-variant.hpp"
+
+bool
+TypeStructuralEqualityMainVariant::_equal(const_tree l, const_tree r)
+{
+ bool valid_inputs = l && r;
+ if (!valid_inputs) return l == r;
+
+ const_tree mv_l = TYPE_MAIN_VARIANT(l);
+ const_tree mv_r = TYPE_MAIN_VARIANT(r);
+ const bool mv_equal = mv_l == mv_r;
+ if (mv_equal) return mv_equal;
+
+ return TypeStructuralEquality::_equal(l, r);
+}
diff --git a/gcc/type-structural-main-variant.hpp b/gcc/type-structural-main-variant.hpp
new file mode 100644
index 00000000000..2fa00aad350
--- /dev/null
+++ b/gcc/type-structural-main-variant.hpp
@@ -0,0 +1,10 @@
+#pragma once
+
+#include "type-structural-equality.hpp"
+
+class TypeStructuralEqualityMainVariant : public TypeStructuralEquality {
+public:
+ TypeStructuralEqualityMainVariant() {};
+protected:
+ virtual bool _equal(const_tree l, const_tree r);
+};
diff --git a/gcc/type-walker.c b/gcc/type-walker.c
new file mode 100644
index 00000000000..d7554c9e6af
--- /dev/null
+++ b/gcc/type-walker.c
@@ -0,0 +1,282 @@
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+
+#include "type-walker.hpp"
+#include "types-inlines.h"
+
+void
+TypeWalker::walk(const_tree t)
+{
+ gcc_assert(t);
+ this->tset.clear();
+ this->_walk(t);
+}
+
+void
+TypeWalker::_walk(const_tree type)
+{
+ if (!type) return;
+ gcc_assert(type);
+
+ // This is an optimization
+ const bool _is_memoized = is_memoized(type);
+ if (_is_memoized) return;
+
+ // This is for correctness...
+ const bool in_set = tset.find(type) != tset.end();
+ if (in_set) return;
+
+ tset.insert(type);
+ const enum tree_code code = TREE_CODE(type);
+ switch (code)
+ {
+ case VOID_TYPE:
+ this->walk_VOID_TYPE(type);
+ break;
+ case INTEGER_TYPE:
+ this->walk_INTEGER_TYPE(type);
+ break;
+ case REAL_TYPE:
+ this->walk_REAL_TYPE(type);
+ break;
+ case FIXED_POINT_TYPE:
+ this->walk_FIXED_POINT_TYPE(type);
+ break;
+ case COMPLEX_TYPE:
+ this->walk_COMPLEX_TYPE(type);
+ break;
+ case ENUMERAL_TYPE:
+ this->walk_ENUMERAL_TYPE(type);
+ break;
+ case BOOLEAN_TYPE:
+ this->walk_BOOLEAN_TYPE(type);
+ break;
+ case OFFSET_TYPE:
+ this->walk_OFFSET_TYPE(type);
+ break;
+ case RECORD_TYPE:
+ this->walk_RECORD_TYPE(type);
+ break;
+ case POINTER_TYPE:
+ this->walk_POINTER_TYPE(type);
+ break;
+ case REFERENCE_TYPE:
+ this->walk_REFERENCE_TYPE(type);
+ break;
+ case ARRAY_TYPE:
+ this->walk_ARRAY_TYPE(type);
+ break;
+ case UNION_TYPE:
+ this->walk_UNION_TYPE(type);
+ break;
+ case FUNCTION_TYPE:
+ this->walk_FUNCTION_TYPE(type);
+ break;
+ case METHOD_TYPE:
+ this->walk_METHOD_TYPE(type);
+ break;
+ case QUAL_UNION_TYPE:
+ case LANG_TYPE:
+ default:
+ {
+ log("missing %s\n", get_tree_code_name(code));
+ gcc_unreachable();
+ }
+ break;
+ }
+
+ tset.erase(type);
+}
+
+
+#define TypeWalkerFuncDef(code) \
+void \
+TypeWalker::walk_ ## code (const_tree t) \
+{ \
+ assert_is_type(t, code); \
+ _walk_ ## code ## _pre(t); \
+ _walk_ ## code (t); \
+ _walk_ ## code ## _post(t); \
+}
+
+#define TypeWalkerFuncDefInternal(code) \
+void TypeWalker::_walk_ ## code (__attribute__((unused)) const_tree t) {}
+
+TypeWalkerFuncDef(VOID_TYPE)
+TypeWalkerFuncDefInternal(VOID_TYPE)
+TypeWalkerFuncDef(INTEGER_TYPE)
+TypeWalkerFuncDefInternal(INTEGER_TYPE)
+TypeWalkerFuncDef(REAL_TYPE)
+TypeWalkerFuncDefInternal(REAL_TYPE)
+TypeWalkerFuncDef(BOOLEAN_TYPE)
+TypeWalkerFuncDefInternal(BOOLEAN_TYPE)
+TypeWalkerFuncDef(OFFSET_TYPE)
+TypeWalkerFuncDefInternal(OFFSET_TYPE)
+TypeWalkerFuncDef(FIXED_POINT_TYPE)
+TypeWalkerFuncDefInternal(FIXED_POINT_TYPE)
+TypeWalkerFuncDef(COMPLEX_TYPE)
+TypeWalkerFuncDefInternal(COMPLEX_TYPE)
+TypeWalkerFuncDef(ENUMERAL_TYPE)
+TypeWalkerFuncDefInternal(ENUMERAL_TYPE)
+
+void
+TypeWalker::_walk_wrapper(const_tree t)
+{
+ const_tree inner_type = TREE_TYPE(t);
+ gcc_assert(inner_type);
+ _walk(inner_type);
+}
+
+#define TypeWalkerFuncDefWrapper(code) \
+void \
+TypeWalker::_walk_ ## code (const_tree t) \
+{ \
+ _walk_wrapper(t); \
+}
+
+TypeWalkerFuncDef(POINTER_TYPE)
+TypeWalkerFuncDefWrapper(POINTER_TYPE)
+TypeWalkerFuncDefWrapper(REFERENCE_TYPE)
+TypeWalkerFuncDef(REFERENCE_TYPE)
+TypeWalkerFuncDef(ARRAY_TYPE)
+TypeWalkerFuncDefWrapper(ARRAY_TYPE)
+
+TypeWalkerFuncDef(RECORD_TYPE)
+
+void
+TypeWalker::_walk_RECORD_TYPE(const_tree t)
+{
+ _walk_record_or_union(t);
+}
+
+TypeWalkerFuncDef(UNION_TYPE)
+
+void
+TypeWalker::_walk_UNION_TYPE(const_tree t)
+{
+ _walk_record_or_union(t);
+}
+
+void
+TypeWalker::_walk_record_or_union(const_tree t)
+{
+ for (tree field = TYPE_FIELDS(t); field; field = DECL_CHAIN(field))
+ {
+ gcc_assert(field);
+ walk_field(field);
+ }
+}
+
+void
+TypeWalker::walk_field(const_tree t)
+{
+ _walk_field_pre(t);
+ _walk_field(t);
+ _walk_field_post(t);
+}
+
+void
+TypeWalker::_walk_field(const_tree t)
+{
+ const_tree inner_type = TREE_TYPE(t);
+ gcc_assert(inner_type);
+ _walk(inner_type);
+}
+
+TypeWalkerFuncDef(FUNCTION_TYPE)
+
+void
+TypeWalker::_walk_FUNCTION_TYPE(const_tree t)
+{
+ _walk_function_or_method(t);
+}
+
+TypeWalkerFuncDef(METHOD_TYPE)
+
+void
+TypeWalker::_walk_METHOD_TYPE(const_tree t)
+{
+ _walk_function_or_method(t);
+}
+
+void
+TypeWalker::_walk_function_or_method(const_tree t)
+{
+ const_tree ret_type = TREE_TYPE(t);
+ walk_return(ret_type);
+ walk_args(t);
+}
+
+void
+TypeWalker::walk_return(const_tree t)
+{
+ _walk_return_pre(t);
+ _walk_return(t);
+ _walk_return_post(t);
+}
+
+void
+TypeWalker::_walk_return(const_tree t)
+{
+ _walk(t);
+}
+
+void
+TypeWalker::walk_args(const_tree t)
+{
+ _walk_args_pre(t);
+ _walk_args(t);
+ _walk_args_post(t);
+}
+
+void
+TypeWalker::_walk_args(const_tree t)
+{
+ for (tree arg_node = TYPE_ARG_TYPES(t); NULL_TREE != arg_node; arg_node = TREE_CHAIN(arg_node))
+ {
+ const_tree arg_node_type = TREE_VALUE(arg_node);
+ gcc_assert(arg_node_type);
+ walk_arg(arg_node_type);
+ }
+}
+
+void
+TypeWalker::walk_arg(const_tree t)
+{
+ _walk_arg_pre(t);
+ _walk_arg(t);
+ _walk_arg_post(t);
+}
+
+void
+TypeWalker::_walk_arg(const_tree t)
+{
+ _walk(t);
+}
diff --git a/gcc/type-walker.hpp b/gcc/type-walker.hpp
new file mode 100644
index 00000000000..60c979481ee
--- /dev/null
+++ b/gcc/type-walker.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+#include <set>
+
+class TypeWalker {
+public:
+ TypeWalker() {};
+ void walk(const_tree t);
+
+protected:
+ typedef std::set<const_tree> tset_t;
+
+protected:
+ tset_t tset;
+
+ void _walk(const_tree t);
+ void _walk_wrapper(const_tree t);
+ void _walk_record_or_union(const_tree t);
+ virtual void _walk_function_or_method(const_tree t);
+ virtual bool is_memoized(__attribute__((unused))const_tree t) { return false; };
+
+#define TypeWalkerFuncDecl(code) \
+ virtual void _walk_ ## code ## _pre(const_tree t) {}; \
+ virtual void walk_ ## code (const_tree t); \
+ virtual void _walk_ ## code (const_tree t); \
+ virtual void _walk_ ## code ## _post(const_tree t) {}
+
+ TypeWalkerFuncDecl(VOID_TYPE);
+ TypeWalkerFuncDecl(INTEGER_TYPE);
+ TypeWalkerFuncDecl(REAL_TYPE);
+ TypeWalkerFuncDecl(FIXED_POINT_TYPE);
+ TypeWalkerFuncDecl(COMPLEX_TYPE);
+ TypeWalkerFuncDecl(ENUMERAL_TYPE);
+ TypeWalkerFuncDecl(BOOLEAN_TYPE);
+ TypeWalkerFuncDecl(OFFSET_TYPE);
+ TypeWalkerFuncDecl(RECORD_TYPE);
+ TypeWalkerFuncDecl(POINTER_TYPE);
+ TypeWalkerFuncDecl(REFERENCE_TYPE);
+ TypeWalkerFuncDecl(ARRAY_TYPE);
+ TypeWalkerFuncDecl(UNION_TYPE);
+ TypeWalkerFuncDecl(FUNCTION_TYPE);
+ TypeWalkerFuncDecl(METHOD_TYPE);
+
+ // These are not types...
+ TypeWalkerFuncDecl(field);
+ TypeWalkerFuncDecl(return);
+ TypeWalkerFuncDecl(args);
+ TypeWalkerFuncDecl(arg);
+};
+
diff --git a/gcc/types-inlines.h b/gcc/types-inlines.h
new file mode 100644
index 00000000000..60666c3ce26
--- /dev/null
+++ b/gcc/types-inlines.h
@@ -0,0 +1,104 @@
+#pragma once
+
+#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-ssa-alias.h"
+#include "tree-ssanames.h"
+#include "gimple.h"
+#include "cfg.h" // needed for gimple-iterator.h
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include <stdbool.h>
+#include <stdio.h>
+
+
+inline void
+log(const char* const fmt, ...)
+{
+ if (!dump_file) return;
+
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(dump_file, fmt, args);
+ fflush(dump_file);
+ va_end(args);
+}
+
+inline void
+is_gimple_code(gimple *stmt, const enum gimple_code ex_code)
+{
+ gcc_assert(stmt);
+ const enum gimple_code ob_code = gimple_code(stmt);
+ const bool succeeds = ex_code == ob_code;
+ gcc_assert(succeeds);
+}
+
+inline void
+assert_is_complete(const_tree a)
+{
+ gcc_assert(a);
+ const_tree type_size = TYPE_SIZE(a);
+ gcc_assert(NULL_TREE != type_size);
+}
+
+inline bool
+is_complete(const_tree a)
+{
+ gcc_assert(a);
+ const_tree type_size = TYPE_SIZE(a);
+ const bool _is_complete = NULL_TREE != type_size;
+ return _is_complete;
+}
+
+inline bool
+is_incomplete(const_tree a)
+{
+ return !is_complete(a);
+}
+
+inline void
+assert_is_type(const_tree a, const enum tree_code expected_code)
+{
+ gcc_assert(a);
+ const enum tree_code observed_code = TREE_CODE(a);
+ const bool eq_codes = observed_code == expected_code;
+ gcc_assert(eq_codes);
+}
+
+inline void
+assert_is_complete_type(const_tree a, const enum tree_code expected_code)
+{
+ //assert_is_complete(a);
+ assert_is_type(a, expected_code);
+}
+
+inline void
+is_gimple_rhs_class(gimple *stmt, const enum gimple_rhs_class ex_class)
+{
+ gcc_assert(stmt);
+ is_gimple_code(stmt, GIMPLE_ASSIGN);
+ const enum gimple_rhs_class ob_class = gimple_assign_rhs_class(stmt);
+ const bool succeeds = ex_class == ob_class;
+ gcc_assert(succeeds);
+}