diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-15 14:35:12 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-16 08:58:13 +0200 |
commit | 4a28abd0fc3e5a413d4459e3c69f7cffdf87e8a9 (patch) | |
tree | 248e91f02ae7efc4505b4c3f89d0c77f479a18b1 | |
parent | 689c5c302269a564508238d96482ea1be933acae (diff) |
reconstructing structs
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/expr-accessor.c | 37 | ||||
-rw-r--r-- | gcc/expr-accessor.hpp | 2 | ||||
-rw-r--r-- | gcc/gimple-accesser.c | 1 | ||||
-rw-r--r-- | gcc/gimple-escaper.c | 53 | ||||
-rw-r--r-- | gcc/ipa-type-escape-analysis.c | 33 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-0-runs-0.c | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-03-new-type-0.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-04-heterogeneous-struct-0.c | 17 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-05-nested-struct-0.c | 21 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-1-prints-structs-0.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-structreorg-2-modifies-0.c | 6 | ||||
-rw-r--r-- | gcc/type-field-deleter.c | 37 | ||||
-rw-r--r-- | gcc/type-field-deleter.hpp | 18 | ||||
-rw-r--r-- | gcc/type-reconstructor.c | 135 | ||||
-rw-r--r-- | gcc/type-reconstructor.hpp | 39 |
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; }; +}; |