summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-15 14:35:12 +0200
committerErick Ochoa <erick.ochoa@theobroma-systems.com>2020-06-16 08:58:13 +0200
commit4a28abd0fc3e5a413d4459e3c69f7cffdf87e8a9 (patch)
tree248e91f02ae7efc4505b4c3f89d0c77f479a18b1
parent689c5c302269a564508238d96482ea1be933acae (diff)
reconstructing structs
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/expr-accessor.c37
-rw-r--r--gcc/expr-accessor.hpp2
-rw-r--r--gcc/gimple-accesser.c1
-rw-r--r--gcc/gimple-escaper.c53
-rw-r--r--gcc/ipa-type-escape-analysis.c33
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c11
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c17
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c17
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c21
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c6
-rw-r--r--gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c6
-rw-r--r--gcc/type-field-deleter.c37
-rw-r--r--gcc/type-field-deleter.hpp18
-rw-r--r--gcc/type-reconstructor.c135
-rw-r--r--gcc/type-reconstructor.hpp39
16 files changed, 327 insertions, 108 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ee8d20cad29..7b7de74905b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1410,7 +1410,7 @@ OBJS = \
ipa-prototype.o \
ipa-type-escape-analysis.o \
type-walker.o \
- type-field-deleter.o \
+ type-reconstructor.o \
expr-walker.o \
gimple-walker.o \
gimple-accesser.o \
diff --git a/gcc/expr-accessor.c b/gcc/expr-accessor.c
index 594c8d553d6..249558f0c68 100644
--- a/gcc/expr-accessor.c
+++ b/gcc/expr-accessor.c
@@ -36,6 +36,35 @@
#include "expr-walker.hpp"
void
+ExprAccessor::add_all_fields_in_struct(const_tree t)
+{
+ 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 = record_field_map.find(t) != record_field_map.end();
+ field_access_map_t field_map;
+ field_map = record_already_in_map ? record_field_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;
+ }
+
+ record_field_map[t] = field_map;
+}
+
+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;
@@ -50,6 +79,13 @@ ExprAccessor::_walk_COMPONENT_REF_pre(const_tree e)
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();
@@ -60,6 +96,7 @@ ExprAccessor::_walk_COMPONENT_REF_pre(const_tree e)
prev_access |= _access;
field_map[op1] = prev_access;
+ add_all_fields_in_struct(op0_t);
record_field_map[op0_t] = field_map;
}
diff --git a/gcc/expr-accessor.hpp b/gcc/expr-accessor.hpp
index 242f6b2e268..e29219ad729 100644
--- a/gcc/expr-accessor.hpp
+++ b/gcc/expr-accessor.hpp
@@ -20,9 +20,11 @@ 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/gimple-accesser.c b/gcc/gimple-accesser.c
index 18d74f499c0..7c1bd51f6cb 100644
--- a/gcc/gimple-accesser.c
+++ b/gcc/gimple-accesser.c
@@ -60,6 +60,7 @@ GimpleAccesser::_walk_pre(gassign *s)
exprAccessor.update(rhs1, Read);
const_tree lhs = gimple_assign_lhs(s);
if (!lhs) break;
+ log("in lhs gimple-accessor\n");
exprAccessor.update(lhs, Write);
break;
}
diff --git a/gcc/gimple-escaper.c b/gcc/gimple-escaper.c
index 3de1c26d038..82e41d0490e 100644
--- a/gcc/gimple-escaper.c
+++ b/gcc/gimple-escaper.c
@@ -101,26 +101,32 @@ bool
GimpleEscaper::filter_known_function(const_tree fndecl)
{
assert_is_type(fndecl, FUNCTION_DECL);
- const_tree identifier_node = DECL_NAME(fndecl);
- if (!identifier_node) return false;
+ 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 *_free = "free";
- const char *_malloc = "malloc";
- const char *_realloc = "realloc";
- const char *_calloc = "calloc";
- const char *_memset = "memset";
const char *_specqsort= "spec_qsort";
const char *_med3 = "arc_compare";
const char *_getArcPosition = "getArcPosition";
const char *_med3_ = "med3.part.0";
const char* name = IDENTIFIER_POINTER(identifier_node);
gcc_assert(name);
- filter |= strcmp(_free, name) == 0;
- filter |= strcmp(_malloc, name) == 0;
- filter |= strcmp(_realloc, name) == 0;
- filter |= strcmp(_memset, name) == 0;
- filter |= strcmp(_calloc, name) == 0;
filter |= strcmp(_specqsort, name) == 0;
filter |= strcmp(_med3, name) == 0;
filter |= strcmp(_med3_, name) == 0;
@@ -132,28 +138,7 @@ bool
GimpleEscaper::filter_known_function(cgraph_node *node)
{
if (!node) return false;
- bool filter = false;
- const char *_free = "free";
- const char *_malloc = "malloc";
- const char *_realloc = "realloc";
- const char *_calloc = "calloc";
- const char *_memset = "memset";
- const char *_specqsort= "spec_qsort";
- const char *_med3 = "arc_compare";
- const char *_getArcPosition = "getArcPosition";
- const char *_med3_ = "med3.part.0";
- const char *name = node->name();
- gcc_assert(name);
- filter |= strcmp(_free, name) == 0;
- filter |= strcmp(_malloc, name) == 0;
- filter |= strcmp(_realloc, name) == 0;
- filter |= strcmp(_memset, name) == 0;
- filter |= strcmp(_calloc, name) == 0;
- filter |= strcmp(_specqsort, name) == 0;
- filter |= strcmp(_med3, name) == 0;
- filter |= strcmp(_med3_, name) == 0;
- filter |= strcmp(_getArcPosition, name) == 0;
- return filter;
+ return filter_known_function(node->decl);
}
void
diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c
index c9af5aa3d98..bdd9f09fc3d 100644
--- a/gcc/ipa-type-escape-analysis.c
+++ b/gcc/ipa-type-escape-analysis.c
@@ -26,9 +26,9 @@
#include "gimple-escaper.hpp"
#include "gimple-caster.hpp"
#include "gimple-accesser.hpp"
-#include "type-field-deleter.hpp"
#include "type-stringifier.hpp"
#include "type-incomplete-equality.hpp"
+#include "type-reconstructor.hpp"
#include <vector>
@@ -121,7 +121,6 @@ fix_escaping_types_in_set(ptrset_t &types)
//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);
@@ -237,7 +236,7 @@ collect_types()
const typeset &non_escaping = casting.non_escaping;
- for (auto i = record_field_offset_map.cbegin(), e = record_field_offset_map.cend(); i != e; ++i)
+ 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();
@@ -250,9 +249,35 @@ collect_types()
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) continue;
+ if (in_set2) {
+ field_offset.erase(f_offset);
+ continue;
+ }
+ field_offset.insert(f_offset);
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;
+ }
+
+ TypeReconstructor reconstructor(record_field_offset_map);
+
+ for (auto i = record_field_offset_map.cbegin(), e = record_field_offset_map.cend(); i != e; ++i)
+ {
+ const_tree record = i->first;
+ reconstructor.walk(record);
}
+
+ TypeReconstructor::reorg_record_map_t map = reconstructor.get_map();
+
+ TypeStringifier stringifier;
+ for (auto i = map.cbegin(), e = map.cend(); i != e; ++i)
+ {
+ const_tree from = i->first;
+ const_tree to = i->second;
+ std::string name_from = stringifier.stringify(from);
+ std::string name_to = stringifier.stringify(to);
+ log("%s -> %s\n", name_from.c_str(), name_to.c_str());
+ }
+
log("FINISHED\n");
}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c
deleted file mode 100644
index 22185badeab..00000000000
--- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/* { dg-do run } */
-/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
-
-// Dummy test to find out if
-// our optimization is registered
-
-int
-main ()
-{
- return 0;
-}
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c
new file mode 100644
index 00000000000..c79bc41e1f8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c
@@ -0,0 +1,17 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s { _Bool a; _Bool b; _Bool c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ printf("%d\n", astruct.a);
+ printf("%d\n", astruct.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;. .. record astruct_s .boolean_type a;boolean_type c;." "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c
new file mode 100644
index 00000000000..166fbccfbcd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c
@@ -0,0 +1,17 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s { float a; _Bool b; int c;};
+struct astruct_s astruct;
+
+
+int
+main ()
+{
+ printf("%d\n", astruct.a);
+ printf("%d\n", astruct.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .real_type a.boolean_type b.integer_type c.. .. record astruct_s .real_type a.integer_type c.." "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c
new file mode 100644
index 00000000000..b0959c209f3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c
@@ -0,0 +1,21 @@
+/* { dg-do link } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */
+
+#include <stdio.h>
+
+struct astruct_s { float a; _Bool b; int c;};
+struct ostruct_s { struct astruct_s a; float b; float c; };
+struct ostruct_s ostruct;
+
+
+int
+main ()
+{
+ printf("%d\n", ostruct.b);
+ printf("%d\n", ostruct.c);
+ printf("%f\n", ostruct.a.a);
+ printf("%d\n", ostruct.a.c);
+}
+
+/* { dg-final { scan-ipa-dump " record astruct_s .real_type a;boolean_type b;integer_type c;. -> record astruct_s .real_type a;integer_type c;." "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump " record ostruct_s . record astruct_s .real_type a;boolean_type b;integer_type c;. a;real_type b;real_type c;. -> record ostruct_s . record astruct_s .real_type a;integer_type c;. a;real_type b;real_type c;." "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
index 07d6ea35e0f..1f6078e842d 100644
--- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
int
main ()
@@ -13,3 +13,7 @@ main ()
struct astruct_s astruct;
return 0;
}
+
+/* { dg-final { scan-ipa-dump "astruct_s.a may be deleted" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "astruct_s.b may be deleted" "type-escape-analysis" } } */
+/* { dg-final { scan-ipa-dump "astruct_s.c may be deleted" "type-escape-analysis" } } */
diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
index e32e18af2f4..1a2ba2030a3 100644
--- a/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
+++ b/gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-flto -flto-partition=none -fipa-dead-field-eliminate -fdump-ipa-structure-reorg -fipa-typelist-field=b -fipa-typelist-struct=astruct_s" } */
+/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis" } */
int
main ()
@@ -11,7 +11,9 @@ main ()
_Bool c;
};
struct astruct_s astruct;
+ astruct.a = astruct.c;
+ astruct.c = astruct.a;
return 0;
}
-/* "modifying,astruct_s" "typelist" */
+/* { dg-final { scan-ipa-dump "astruct_s.b may be deleted" "type-escape-analysis" } } */
diff --git a/gcc/type-field-deleter.c b/gcc/type-field-deleter.c
deleted file mode 100644
index 769de227c67..00000000000
--- a/gcc/type-field-deleter.c
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "types-inlines.h"
-#include "type-stringifier.hpp"
-#include <string>
-
-#include "type-field-deleter.hpp"
-
-void
-TypeFieldDeleter::_walk_RECORD_TYPE_pre(const_tree t)
-{
- // Easy comparison for now
- TypeStringifier stringifier;
- _print.push(t == _record);
- if (!_print.top()) return;
- const std::string name = stringifier.stringify(t);
- log ("looking at record %s\n", name.c_str());
-}
-
-void
-TypeFieldDeleter::_walk_RECORD_TYPE_post(const_tree t)
-{
- _print.pop();
-}
-
-void
-TypeFieldDeleter::_walk_field_pre(const_tree t)
-{
- if (!_print.top()) return;
-
- assert_is_type(t, FIELD_DECL);
- const bool in_set = _accesses.find(t) != _accesses.end();
- unsigned access = in_set ? _accesses[t] : Empty;
- const bool is_read = access & Read;
- if (is_read) return;
-
- const std::string identifier = TypeStringifier::get_field_identifier(t);
- log("will delete field %s\n", identifier.c_str());
-}
diff --git a/gcc/type-field-deleter.hpp b/gcc/type-field-deleter.hpp
deleted file mode 100644
index 7bbfbfd6584..00000000000
--- a/gcc/type-field-deleter.hpp
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-
-#include "type-walker.hpp"
-#include "expr-accessor.hpp"
-#include <stack>
-
-class TypeFieldDeleter : public TypeWalker {
-public:
- TypeFieldDeleter(const_tree record, field_access_map_t accesses) : _record(record), _accesses(accesses) {};
-private:
- const_tree _record;
- field_access_map_t _accesses;
- std::stack<bool> _print;
- virtual void _walk_RECORD_TYPE_pre(const_tree t);
- virtual void _walk_RECORD_TYPE_post(const_tree t);
- virtual void _walk_field_pre(const_tree t);
-};
-
diff --git a/gcc/type-reconstructor.c b/gcc/type-reconstructor.c
new file mode 100644
index 00000000000..c4f225f358d
--- /dev/null
+++ b/gcc/type-reconstructor.c
@@ -0,0 +1,135 @@
+#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"
+
+void
+TypeReconstructor::_walk_RECORD_TYPE_pre(const_tree t)
+{
+ const bool in_map = _records.find(t) != _records.end();
+ // The modifying stack let's us know if the current record
+ // type is being modified.
+ _modifying.push(in_map);
+
+ field_offsets_t empty;
+ _record_stack.push(in_map ? _records[t] : empty);
+
+ // Do we create a record here?
+ // Which is a copy of the old one?
+ _working_stack.push(build_distinct_type_copy((tree)t));
+
+ type_vector_t vec;
+ type_vector_t vec2;
+ _field_decls.push(vec);
+ _eliminated_fields.push(vec2);
+}
+
+void
+TypeReconstructor::_walk_RECORD_TYPE_post(const_tree t)
+{
+ type_vector_t fields_to_keep = _field_decls.top();
+ for (auto i = fields_to_keep.cbegin(), e = fields_to_keep.cend(); i != e; ++i)
+ {
+ const_tree field = *i;
+ log("I will keep %s\n", TypeStringifier::get_field_identifier(field).c_str());
+ }
+ type_vector_t fields_to_eliminate = _eliminated_fields.top();
+ _eliminated_fields.pop();
+ _field_decls.pop();
+ const_tree working_type = _working_stack.top();
+ _working_stack.pop();
+ _record_stack.pop();
+ const bool should_be_modified = _modifying.top();
+ _modifying.pop();
+
+ // There are no fields to eliminate
+ // if (fields_to_eliminate.empty()) return;
+ // But, we can have a nested struct that will be rewritten
+ // so, we should keep not exit early
+
+ // There are no fields to keep
+ // Can be an incomplete type
+ if (fields_to_keep.empty()) return;
+
+ tree f = (tree) fields_to_keep[0];
+ tree tf = TREE_TYPE(f);
+ bool field_type_in_reorg_map = _reorg_map.find(tf) != _reorg_map.end();
+ if (field_type_in_reorg_map)
+ {
+ TREE_TYPE(f) = (tree) _reorg_map[tf];
+ }
+ TYPE_FIELDS((tree)working_type) = f;
+ unsigned s = fields_to_keep.size();
+
+ for (unsigned i = 1; i < s; i++)
+ {
+ tree current = (tree) fields_to_keep[i];
+ tree tf = TREE_TYPE(current);
+ field_type_in_reorg_map = _reorg_map.find(tf) != _reorg_map.end();
+ if (field_type_in_reorg_map)
+ {
+ TREE_TYPE(current) = (tree) _reorg_map[tf];
+ }
+ DECL_CHAIN(f) = current;
+ f = current;
+ }
+
+ layout_type((tree)working_type);
+ _reorg_map[t] = working_type;
+}
+
+void
+TypeReconstructor::_walk_field_pre(const_tree t)
+{
+ unsigned f_offset = tree_to_uhwi(DECL_FIELD_OFFSET(t));
+ unsigned f_offset_2 = tree_to_uhwi(DECL_FIELD_BIT_OFFSET(t));
+ unsigned f_offset_3 = f_offset * 8 + f_offset_2;
+ field_offsets_t field_offsets = _record_stack.top();
+ const bool should_be_deleted = field_offsets.find(f_offset_3) != field_offsets.end();
+ const bool should_be_modified = _modifying.top();
+ if (should_be_modified && should_be_deleted) {
+ type_vector_t &vec_ = _eliminated_fields.top();
+ vec_.push_back(t);
+ return;
+ }
+
+ // This is a field declaration, that should be saved.
+ type_vector_t &vec = _field_decls.top();
+ vec.push_back(copy_node((tree)t));
+}
+
+void
+TypeReconstructor::_walk_field_post(const_tree t)
+{
+}
diff --git a/gcc/type-reconstructor.hpp b/gcc/type-reconstructor.hpp
new file mode 100644
index 00000000000..c802f59ebec
--- /dev/null
+++ b/gcc/type-reconstructor.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <set>
+#include <map>
+#include <stack>
+#include <vector>
+
+#include "type-walker.hpp"
+
+class TypeReconstructor : public TypeWalker
+{
+public:
+ typedef std::map<const_tree, const_tree> reorg_record_map_t;
+private:
+ typedef std::set<unsigned> field_offsets_t;
+ typedef std::map<const_tree, field_offsets_t> record_field_offset_map_t;
+ typedef std::stack<bool> field_stack_t;
+ typedef std::stack<field_offsets_t> record_stack_t;
+ typedef std::stack<const_tree> type_stack_t;
+ typedef std::vector<const_tree> type_vector_t;
+ typedef std::stack<type_vector_t> type_vector_stack_t;
+ typedef std::stack<bool> bool_stack_t;
+ record_field_offset_map_t _records;
+ reorg_record_map_t _reorg_map;
+ field_stack_t _field_stack;
+ record_stack_t _record_stack;
+ type_stack_t _working_stack;
+ type_vector_stack_t _field_decls;
+ type_vector_stack_t _eliminated_fields;
+ bool_stack_t _modifying;
+
+ 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);
+public:
+ TypeReconstructor(record_field_offset_map_t records) : _records(records) {};
+ reorg_record_map_t get_map() { return _reorg_map; };
+};