diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-03 16:51:45 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-03 16:51:45 +0200 |
commit | 2da29e3b3af58440a91bcad0c12585d5f1b9bd4c (patch) | |
tree | 7858ea48de2dae30ee2abf0eadabd97696ba88e1 | |
parent | d983bc700da3aada11f1a7fecc21b88609f30bf6 (diff) | |
parent | 0550cc23f21dea0517d0a2164a2a65683d058e5b (diff) |
Merging
33 files changed, 4223 insertions, 6 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 865fbd812b7..50cc85d4edc 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1409,6 +1409,16 @@ OBJS = \ internal-fn.o \ ipa-type-escape-analysis.o \ ipa-hello-world.o \ + ipa-prototype.o \ + ipa-type-collector.o \ + expr-walker.o \ + expr-collector.o \ + type-walker.o \ + type-collector.o \ + type-stringifier.o \ + compare-types.o \ + collect-types.o \ + name-types.o \ ipa-cp.o \ ipa-sra.o \ ipa-devirt.o \ diff --git a/gcc/collect-types.c b/gcc/collect-types.c new file mode 100644 index 00000000000..77257a8b8e0 --- /dev/null +++ b/gcc/collect-types.c @@ -0,0 +1,76 @@ +#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 "compare-types.h" +#include "types-inlines.h" +#include "type-stringifier.hpp" +#include "name-types.h" +#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); + // let's just double check... + 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; + 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; +} + diff --git a/gcc/collect-types.h b/gcc/collect-types.h new file mode 100644 index 00000000000..1a6126f6a6d --- /dev/null +++ b/gcc/collect-types.h @@ -0,0 +1,20 @@ +#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); +}; + +typedef struct points_to_record_sets_s ptrset_t; diff --git a/gcc/common.opt b/gcc/common.opt index b861ac0ec8f..7442c91d232 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3452,4 +3452,17 @@ fipa-hello-world Common Report Var(flag_ipa_hello_world) Optimization Hello world +fipa-type-collector +Common Report Var(flag_ipa_type_collector) Optimization +TBD + +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 ; This comment is to ensure we retain the blank line above. diff --git a/gcc/compare-types.c b/gcc/compare-types.c new file mode 100644 index 00000000000..9a615c2dd2a --- /dev/null +++ b/gcc/compare-types.c @@ -0,0 +1,467 @@ +#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 "compare-types.h" +#include "types-inlines.h" +#include "name-types.h" + +static bool +is_incomplete_type(const_tree a) +{ + gcc_assert(a); + const_tree type_size = TYPE_SIZE(a); + return NULL_TREE == type_size; +} + +unsigned +eq_main_variant(const_tree a, const_tree b) +{ + gcc_assert(a && b); + const_tree main_variant_a = TYPE_MAIN_VARIANT(a); + const_tree main_variant_b = TYPE_MAIN_VARIANT(b); + gcc_assert(main_variant_a && main_variant_b); + const bool are_equal = main_variant_a == main_variant_b; + return are_equal; +} + +unsigned +eq_canonical_internal(const_tree a, const_tree b) +{ + gcc_assert(a && b); + const_tree canonical_a = TYPE_CANONICAL(a); + const_tree canonical_b = TYPE_CANONICAL(b); + const bool are_equal = canonical_a == canonical_b; + return are_equal; +} + +static bool +eq_record_or_union_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + + tree field_a = TYPE_FIELDS(a); + tree field_b = TYPE_FIELDS(b); + while (field_a || field_b) + { + const bool different_lengths = (bool)field_a != (bool)field_b; + if (different_lengths) return false; + + const_tree field_type_a = TREE_TYPE(field_a); + const_tree field_type_b = TREE_TYPE(field_b); + gcc_assert(field_type_a && field_type_b); + const bool same_field_types = eq_types(field_type_a, field_type_b, force_structural); + if (!same_field_types) return false; + + field_a = DECL_CHAIN(field_a); + field_b = DECL_CHAIN(field_b); + } + + return true; +} + +static bool +eq_record_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, RECORD_TYPE); + assert_is_type(b, RECORD_TYPE); + return eq_record_or_union_types(a, b, force_structural); +} + +static bool +eq_union_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, UNION_TYPE); + assert_is_type(b, UNION_TYPE); + return eq_record_or_union_types(a, b, force_structural); +} + +static bool +eq_wrapper_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + const_tree inner_type_a = TREE_TYPE(a); + const_tree inner_type_b = TREE_TYPE(b); + gcc_assert(inner_type_a && inner_type_b); + return eq_types(inner_type_a, inner_type_b, force_structural); +} + +static bool +eq_pointer_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, POINTER_TYPE); + assert_is_type(b, POINTER_TYPE); + return eq_wrapper_types(a, b, force_structural); +} + +static bool +eq_reference_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, REFERENCE_TYPE); + assert_is_type(b, REFERENCE_TYPE); + return eq_wrapper_types(a, b, force_structural); +} + +static bool +eq_array_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, ARRAY_TYPE); + assert_is_type(b, ARRAY_TYPE); + return eq_wrapper_types(a, b, force_structural); +} + +static bool +eq_function_or_method_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + const_tree return_type_a = TREE_TYPE(a); + const_tree return_type_b = TREE_TYPE(b); + const bool is_return_equal = eq_types(return_type_a, return_type_b, force_structural); + if (!is_return_equal) return false; + + tree parm_a = TYPE_ARG_TYPES(a); + tree parm_b = TYPE_ARG_TYPES(b); + + while (parm_a || parm_b) + { + const bool different_lengths = (bool)parm_a != (bool)parm_b; + if (different_lengths) return false; + + const_tree parm_type_a = TREE_VALUE(parm_a); + const_tree parm_type_b = TREE_VALUE(parm_b); + gcc_assert(parm_type_a && parm_type_b); + const bool same_field_types = eq_types(parm_type_a, parm_type_b, force_structural); + if (!same_field_types) return false; + + parm_a = TREE_CHAIN(parm_a); + parm_b = TREE_CHAIN(parm_b); + } + + return true; +} + +static bool +eq_function_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, FUNCTION_TYPE); + assert_is_type(b, FUNCTION_TYPE); + return eq_function_or_method_types(a, b, force_structural); +} + +static bool +eq_method_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + assert_is_type(a, METHOD_TYPE); + assert_is_type(b, METHOD_TYPE); + + const_tree base_type_a = TYPE_METHOD_BASETYPE(a); + const_tree base_type_b = TYPE_METHOD_BASETYPE(b); + const bool eq_base_types = eq_types(base_type_a, base_type_b, force_structural); + return eq_base_types && eq_function_or_method_types(a, b, force_structural); +} + +static bool eq_structural(const_tree a, const_tree b, const bool force_structural = false); + +unsigned +eq_pointer(const_tree a, const_tree b) +{ + return a == b; +} + +unsigned +eq_identifier(const_tree a, const_tree b) +{ + // TODO: Note, we have had the following miscomparison: + // comparing 0,0: {} == 0,64:void_type* + // since at least one of these two types is incomplete + // and both lack an identifier... + std::string name_a = get_type_identifier(a); + std::string name_b = get_type_identifier(b); + const int length_a = name_a.length(); + const int length_b = name_b.length(); + const bool is_sound_input = length_a > 0 || length_b > 0; + const bool retval = is_sound_input && name_a.compare(name_b) == 0; + return retval; +} + +static bool +eq_structural(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + const enum tree_code code_a = TREE_CODE(a); + const enum tree_code code_b = TREE_CODE(b); + const bool equal_code = code_a == code_b; + if (!equal_code) return false; + + const enum tree_code code = code_a; + switch (code) + { + //FIXME: Just because two codes are the same + //doesn't mean they are the same type + //E.g. short != int + // float != double + // enum a != enum b + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case COMPLEX_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case OFFSET_TYPE: + return true; + break; + default: + break; + } + + switch (code) + { + case RECORD_TYPE: + return eq_record_types(a, b, force_structural); + break; + case POINTER_TYPE: + return eq_pointer_types(a, b, force_structural); + break; + case REFERENCE_TYPE: + return eq_reference_types(a, b, force_structural); + break; + case ARRAY_TYPE: + return eq_array_types(a, b, force_structural); + break; + case UNION_TYPE: + return eq_union_types(a, b, force_structural); + break; + case FUNCTION_TYPE: + return eq_function_types(a, b, force_structural); + break; + case METHOD_TYPE: + return eq_method_types(a, b, force_structural); + break; + case QUAL_UNION_TYPE: + case LANG_TYPE: + default: + // Unimplemented + gcc_unreachable(); + break; + } + + gcc_unreachable(); + return false; +} + +unsigned +eq_canonical(const_tree a, const_tree b) +{ + gcc_assert(a && b); + const bool struct_eq_a = TYPE_STRUCTURAL_EQUALITY_P(a); + const bool struct_eq_b = TYPE_STRUCTURAL_EQUALITY_P(b); + const bool use_structural_equality = struct_eq_a || struct_eq_b; + const bool are_equal = use_structural_equality ? eq_structural(a, b) : eq_canonical_internal(a, b); + return are_equal; +} + + +unsigned +eq_type_compare(const_tree a, const_tree b) +{ + return eq_types(a, b); +} + +unsigned +eq_type_structural(const_tree a, const_tree b) +{ + return eq_types(a, b, true); +} + +unsigned +eq_types(const_tree a, const_tree b, const bool force_structural) +{ + gcc_assert(a && b); + // This should be before comparing incomplete types. + // This is not enabled by default, and it is used for + // testing structural equality limitations. + if (force_structural) return eq_structural(a, b, force_structural); + + // eq_structural (a-incomplete, a-complete) = false + // eq_main_variant(a-incomplete, a-complete) = false + // eq_canonical (a-incomplete, a-complete) = false + // Fallback to eq_identifier only here. + // This should be the only static call to eq_identifier! + + const bool is_a_incomplete = is_incomplete_type(a); + const bool is_b_incomplete = is_incomplete_type(b); + const bool compare_incomplete_types = is_a_incomplete || is_b_incomplete; + if (compare_incomplete_types) return eq_identifier(a, b); + + + // Main variant is unreliable when we are comparing builtin types? + // comparing 0,64: {}* == 0,64:__gcov_info {0,32:integer_type;8,72: {}*;16,48:integer_type;24,88:integer_type*;32,544:void_type(0,64:integer_type*, 0,32:integer_type, 0,0:void_type)*[];96,128:integer_type;104,168:__gcov_fn_info {0,64: {}*;8,40:integer_type;12,44:integer_type;16,48:integer_type;24,280:__gcov_ctr_info {0,32:integer_type;8,72:integer_type*;}[];}**;}* + if (eq_main_variant(a, b) && eq_structural(a, b)) return true; + + if (!eq_canonical(a, b)) return false; + + // optimistic... + // maybe we should have a MAYBE? + return eq_structural(a, b); +} + +namespace test_type_equality { + +static void +test_main_variant() +{ + tree void_a = make_node(VOID_TYPE); + tree void_b = build_variant_type_copy(void_a); + const bool expected = true; + const bool observed = eq_types(void_a, void_b); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_pointer_types_eq() +{ + tree pointer_a = make_node(POINTER_TYPE); + tree inner_type = make_node(INTEGER_TYPE); + TREE_TYPE(pointer_a) = inner_type; + tree pointer_b = build_variant_type_copy(pointer_a); + const bool expected = true; + const bool observed = eq_types(pointer_a, pointer_b); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_pointer_types_ne() +{ + tree pointer_a = make_node(POINTER_TYPE); + tree inner_type_a = make_node(INTEGER_TYPE); + TREE_TYPE(pointer_a) = inner_type_a; + tree pointer_b = make_node(POINTER_TYPE); + tree inner_type_b = make_node(VOID_TYPE); + TREE_TYPE(pointer_b) = inner_type_b; + const bool expected = false; + const bool observed = eq_types(pointer_a, pointer_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_pointer_types_eq_structurally() +{ + tree pointer_a = make_node(POINTER_TYPE); + tree inner_type_a = make_node(INTEGER_TYPE); + TREE_TYPE(pointer_a) = inner_type_a; + tree pointer_b = make_node(POINTER_TYPE); + tree inner_type_b = make_node(INTEGER_TYPE); + TREE_TYPE(pointer_b) = inner_type_b; + const bool expected = true; + const bool observed = eq_types(pointer_a, pointer_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_void_eq() +{ + tree void_a = make_node(VOID_TYPE); + tree void_b = build_variant_type_copy(void_a); + const bool expected = true; + const bool observed = eq_types(void_a, void_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_structural_equality_different_types() +{ + tree type_a = make_node(VOID_TYPE); + tree type_b = make_node(RECORD_TYPE); + const bool expected = false; + const bool observed = eq_types(type_a, type_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_different_record_types() +{ + tree type_a = make_node(RECORD_TYPE); + tree type_b = make_node(RECORD_TYPE); + tree field_a = make_node(FIELD_DECL); + tree field_b = make_node(FIELD_DECL); + tree type_field_a = make_node(VOID_TYPE); + tree type_field_b = make_node(RECORD_TYPE); + TREE_TYPE(field_a) = type_field_a; + TREE_TYPE(field_b) = type_field_b; + TYPE_FIELDS(type_a) = field_a; + TYPE_FIELDS(type_b) = field_b; + const bool expected = false; + const bool observed = eq_types(type_a, type_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +static void +test_same_record_types() +{ + tree type_a = make_node(RECORD_TYPE); + tree field_a = make_node(FIELD_DECL); + tree type_field_a = make_node(VOID_TYPE); + TREE_TYPE(field_a) = type_field_a; + TYPE_FIELDS(type_a) = field_a; + tree type_b = build_variant_type_copy(type_a); + const bool expected = true; + const bool observed = eq_types(type_a, type_b, true); + const bool success = expected == observed; + gcc_assert(success); +} + +void +run_tests() +{ + test_main_variant(); + test_void_eq(); + test_structural_equality_different_types(); + test_different_record_types(); + test_same_record_types(); + test_pointer_types_eq_structurally(); + test_pointer_types_ne(); + test_pointer_types_eq(); + +} +} // test_type_equality diff --git a/gcc/compare-types.h b/gcc/compare-types.h new file mode 100644 index 00000000000..384819ce2d7 --- /dev/null +++ b/gcc/compare-types.h @@ -0,0 +1,18 @@ +#pragma once + + +namespace test_type_equality { void run_tests(); }; + +static constexpr unsigned not_equal = 0; +static constexpr unsigned equal_incomplete = 1 << 1; +// equal should be the last one +static constexpr unsigned equal = 1 << 2; + +extern unsigned eq_identifier(const_tree a, const_tree b); +extern unsigned eq_pointer(const_tree a, const_tree b); +extern unsigned eq_main_variant(const_tree a, const_tree b); +extern unsigned eq_canonical(const_tree a, const_tree b); +extern unsigned eq_canonical_internal(const_tree a, const_tree b); +extern unsigned eq_type_compare(const_tree a, const_tree b); +extern unsigned eq_type_structural(const_tree a, const_tree b); +extern unsigned eq_types(const_tree a, const_tree b, const bool force_structural = false); diff --git a/gcc/expr-collector.c b/gcc/expr-collector.c new file mode 100644 index 00000000000..2e20ba5100a --- /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..aba79d64307 --- /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 { +public: + ExprCollector() {}; + // TODO: You can get rid of this pointer + // if you make ExprCollector a singleton. + static TypeCollector* typeCollector; +private: + virtual void _walk_pre(const_tree e) final; +}; + diff --git a/gcc/expr-escaper.hpp b/gcc/expr-escaper.hpp new file mode 100644 index 00000000000..cae97ccea11 --- /dev/null +++ b/gcc/expr-escaper.hpp @@ -0,0 +1,31 @@ +#include "ipa-prototype.h" +#include "expr-walker.hpp" + +class ExprEscaper : public ExprWalker +{ +public: + ExprEscaper() {}; + void update(const_tree t, Reason r); + static TypeEscaper *typeEscaper; +private: + Reason _r; + virtual void _walk_pre(const_tree e); +}; + +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); +} + + diff --git a/gcc/expr-walker.c b/gcc/expr-walker.c new file mode 100644 index 00000000000..235e80dce96 --- /dev/null +++ b/gcc/expr-walker.c @@ -0,0 +1,273 @@ +#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; + 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_ ## code ## _pre (e); \ + _walk_ ## code (e); \ + _walk_ ## code ## _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) + +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, 1); +} + +void +ExprWalker::_walk_CONSTRUCTOR(const_tree e) +{ +#ifdef FUZZ_MODE + gcc_unreachable(); +#endif +} + +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); +} diff --git a/gcc/expr-walker.hpp b/gcc/expr-walker.hpp new file mode 100644 index 00000000000..1ff3ca4dadc --- /dev/null +++ b/gcc/expr-walker.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "types-inlines.h" + + +class ExprWalker +{ +public: + ExprWalker() {}; + void walk(const_tree e); +private: + virtual void _walk_pre(const_tree e) {}; + void _walk(const_tree e); + virtual void _walk_post(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(const_tree e) {}; \ + void walk_ ## code (const_tree e); \ + void _walk_ ## code (const_tree e); \ + virtual void _walk_ ## code ## _post(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); +}; + diff --git a/gcc/gimple.h b/gcc/gimple.h index ca7fec6247e..e5b594a5b01 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -6494,6 +6494,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 * @@ -6502,15 +6519,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..ca8b77268a1 --- /dev/null +++ b/gcc/ipa-prototype.c @@ -0,0 +1,764 @@ +#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 "name-types.h" +#include "compare-types.h" +#include "ipa-type-collector.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" + +//#define OPTIMIZED +#define SANITY_CHECKS + +typedef std::set<const_tree> undefset; + +void +Reason::print() const +{ + if (!this->is_escaping) return; + + log("g=%d p=%d r=%d c=%d v=%d u=%d\n", 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); +} + +Reason +Reason::operator|(const Reason &other) +{ + Reason retval {}; + retval.is_escaping = this->is_escaping | other.is_escaping; + 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; + return retval; +} + +Reason& +Reason::operator|=(const Reason &other) +{ + this->is_escaping |= other.is_escaping; + this->global_is_visible |= other.global_is_visible; + this->parameter_is_visible |= other.parameter_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; + return *this; +} + + +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 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 void update_escape_info( const_tree type, ptrset_t &types, Reason reason, typemap &calc); + +static bool +is_variable_escaping(varpool_node *vnode) +{ + gcc_assert(vnode); + return vnode->externally_visible; +} + +static void update_escape_info_expr(ptrset_t &types, typemap &calc, const_tree expr, Reason reason); + +static void +calculate_escaping_types_globals(ptrset_t &types, typemap &calc) +{ + varpool_node *vnode = NULL; + FOR_EACH_VARIABLE(vnode) + { + bool is_escaping = is_variable_escaping(vnode); + +#ifdef OPTIMIZED + if (!is_escaping) continue; +#endif + + Reason reason {}; // Not sure why {} works but () doesn't... It believes it is a function? + reason.is_escaping = is_escaping; + reason.global_is_visible = is_escaping; + update_escape_info_expr (types, calc, vnode->decl, reason); + } +} + +static bool +filter_known_function(cgraph_node *node) +{ + gcc_assert(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 *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; + return filter; +} + +static bool +is_function_escaping(cgraph_node *cnode) +{ + const bool filter = filter_known_function(cnode); + if (filter) return false; + + gcc_assert(cnode); + return cnode->externally_visible; +} + +static void +mark_escaping_parameters(ptrset_t &types, typemap &calc, cgraph_node *cnode, Reason reason) +{ + gcc_assert(cnode); + const_tree decl = cnode->decl; + gcc_assert(decl); + assert_is_type(decl, FUNCTION_DECL); +#ifdef OPTIMIZED + if (!reason.is_escaping) return; +#endif + + update_escape_info_expr(types, calc, decl, reason); +} + +static void +mark_escaping_return_type(ptrset_t &types, typemap &calc, cgraph_node *cnode, Reason reason) +{ + gcc_assert(cnode); + const_tree decl = cnode->decl; + gcc_assert(decl); + assert_is_type(decl, FUNCTION_DECL); +#ifdef OPTIMIZED + if (!reason.is_escaping) return; +#endif + + const_tree func_type = TREE_TYPE(decl); + assert_is_type(func_type, FUNCTION_TYPE); + const_tree ret_type = TREE_TYPE(func_type); + gcc_assert(ret_type); + update_escape_info(ret_type, types, reason, calc); +} + +static void +mark_escaping_function(ptrset_t &types, typemap &calc, cgraph_node *cnode) +{ + gcc_assert(cnode); + const bool is_escaping = is_function_escaping(cnode); +#ifdef OPTIMIZED + if (!is_escaping) return; +#endif + + Reason reason1 {}; + reason1.is_escaping = is_escaping; + reason1.parameter_is_visible = is_escaping; + mark_escaping_parameters(types, calc, cnode, reason1); + + Reason reason2 {}; + reason2.is_escaping = is_escaping; + reason2.return_is_visible = is_escaping; + mark_escaping_return_type(types, calc, cnode, reason2); +} + +static void +calculate_escaping_types_from_cast(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const_tree lhs = gimple_assign_lhs(stmt); + gcc_assert(lhs); + const_tree rhs = gimple_assign_rhs1(stmt); + gcc_assert(rhs); +} + +static void +calculate_escaping_types_from_assign_lhs(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const_tree lhs = gimple_assign_lhs(stmt); + gcc_assert(lhs); + Reason reason {}; + update_escape_info_expr(types, calc, lhs, reason); +} + +static void +calculate_escaping_types_from_assign_rhs3(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_rhs_class(stmt, GIMPLE_TERNARY_RHS); + const_tree rhs = gimple_assign_rhs3(stmt); + gcc_assert(rhs); + Reason reason {}; + update_escape_info_expr(types, calc, rhs, reason); +} + +static void +calculate_escaping_types_from_assign_rhs2(ptrset_t &types, typemap &calc, gimple *stmt) +{ + const_tree rhs = gimple_assign_rhs2(stmt); + gcc_assert(rhs); + Reason reason {}; + update_escape_info_expr(types, calc, rhs, reason); +} + +static void +calculate_escaping_types_from_assign_rhs1(ptrset_t &types, typemap &calc, gimple *stmt) +{ + const_tree rhs = gimple_assign_rhs1(stmt); + gcc_assert(rhs); + Reason reason {}; + update_escape_info_expr(types, calc, rhs, reason); +} + +static void +calculate_escaping_types_from_assign(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + calculate_escaping_types_from_assign_lhs(types, calc, stmt); + // If it is a cast, we must look at the lhs and the rhs... + const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt); + switch(gclass) + { + case GIMPLE_TERNARY_RHS: + calculate_escaping_types_from_assign_rhs3(types, calc, stmt); + /* fall-through */ + case GIMPLE_BINARY_RHS: + calculate_escaping_types_from_assign_rhs2(types, calc, stmt); + /* fall-through */ + case GIMPLE_UNARY_RHS: + case GIMPLE_SINGLE_RHS: + calculate_escaping_types_from_assign_rhs1(types, calc, stmt); + calculate_escaping_types_from_cast(types, calc, stmt); + break; + default: + gcc_unreachable(); + break; + } +} + +static void +calculate_escaping_types_from_call_lhs(ptrset_t &types, typemap &calc, undefset &undef, gimple *stmt) +{ + gcall *call = dyn_cast<gcall*>(stmt); + if (!call) return; + + const_tree lhs = gimple_call_lhs(stmt); + if (!lhs) return; + + tree fn = gimple_call_fndecl(stmt); + const bool is_undefined = undef.find(fn) != undef.end(); +#ifdef OPTIMIZED + if (!is_undefined) return; +#endif + + Reason reason {}; + reason.is_escaping = is_undefined; + reason.return_is_visible = is_undefined; + update_escape_info_expr(types, calc, lhs, reason); +} + +static void +calculate_escaping_types_from_call_rhs(ptrset_t &types, typemap &calc, undefset &undef, gimple *stmt) +{ + + tree fn = gimple_call_fndecl(stmt); + const bool is_undefined = undef.find(fn) != undef.end(); +#ifdef OPTIMIZED + if (!is_undefined) return; +#endif + + //tree decl_name = DECL_NAME(fn); + //const char* identifier = IDENTIFIER_POINTER(decl_name); + // What about gcov? + + Reason reason {}; + reason.is_escaping = is_undefined; + reason.parameter_is_visible = is_undefined; + + unsigned num_args = gimple_call_num_args(stmt); + for (unsigned i = 0; i < num_args; i++) + { + const_tree arg_i = gimple_call_arg(stmt, i); + gcc_assert(arg_i); + const_tree type_i = TREE_TYPE(arg_i); + update_escape_info(type_i, types, reason, calc); + } +} + +static void +calculate_escaping_types_from_call(ptrset_t &types, typemap &calc, undefset &undef, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_CALL); + gcall *call = dyn_cast<gcall*>(stmt); + tree fn = gimple_call_fndecl(stmt); + + const bool in_set = undef.find(fn) != undef.end(); +#ifdef OPTIMIZED + if (!in_set) return; +#endif + + calculate_escaping_types_from_call_lhs(types, calc, undef, stmt); + calculate_escaping_types_from_call_rhs(types, calc, undef, stmt); +} + +static void +calculate_escaping_types_from_cond_lhs(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_COND); + const_tree lhs = gimple_cond_lhs(stmt); + gcc_assert(lhs); + Reason reason {}; + update_escape_info_expr(types, calc, lhs, reason); +} + +static void +calculate_escaping_types_from_cond_rhs(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_COND); + const_tree rhs = gimple_cond_rhs(stmt); + Reason reason {}; + update_escape_info_expr(types, calc, rhs, reason); +} + +static void +calculate_escaping_types_from_cond(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_COND); + calculate_escaping_types_from_cond_lhs(types, calc, stmt); + calculate_escaping_types_from_cond_rhs(types, calc, stmt); +} + +static void +calculate_escaping_types_from_return(ptrset_t &types, typemap &calc, gimple *stmt) +{ + is_gimple_code(stmt, GIMPLE_RETURN); + const_tree retval = gimple_return_retval(stmt); + if (!retval) return; + + Reason reason {}; + update_escape_info_expr(types, calc, retval, reason); +} + +static void +calculate_escaping_types_from_stmt(ptrset_t &types, typemap &calc, undefset &undef, gimple *stmt) +{ + // Should be the same as ipa-type-collector.c + // Otherwise, we might be skipping exploring some paths... + gcc_assert(stmt); + const enum gimple_code code = gimple_code (stmt); + switch (code) + { + case GIMPLE_ASSIGN: + calculate_escaping_types_from_assign(types, calc, stmt); + break; + case GIMPLE_CALL: + calculate_escaping_types_from_call(types, calc, undef, stmt); + break; + case GIMPLE_COND: + calculate_escaping_types_from_cond(types, calc, stmt); + break; + case GIMPLE_RETURN: + calculate_escaping_types_from_return(types, calc, stmt); + break; + case GIMPLE_LABEL: + case GIMPLE_PREDICT: + case GIMPLE_DEBUG: + case GIMPLE_SWITCH: +#ifdef FUZZ_MODE + gcc_unreachable(); +#endif + break; + default: + { + const char* name = gimple_code_name[code]; + log("gimple code name %s\n", name); + gcc_unreachable(); + } + break; + } +} + +static void +calculate_escaping_types_from_bb(ptrset_t &types, typemap &calc, undefset &undef, basic_block bb) +{ + gcc_assert(bb); + for (auto gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) + { + gimple *stmt = gsi_stmt(gsi); + calculate_escaping_types_from_stmt(types, calc, undef, stmt); + } +} + +static void +calculate_escaping_types_from_cnode(ptrset_t &types, typemap &calc, cgraph_node *cnode, undefset &undef) +{ + 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) + { + calculate_escaping_types_from_bb(types, calc, undef, bb); + } + pop_cfun(); +} + +static void +calculate_escaping_ssa_names(ptrset_t &types, typemap &calc, cgraph_node *cnode) +{ + gcc_assert(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); + Reason reason {}; + FOR_EACH_SSA_NAME(i, ssa_name, cfun) + { + gcc_assert(ssa_name); + const_tree ssa_name_type = TREE_TYPE(ssa_name); + update_escape_info(ssa_name_type, types, reason, calc); + } + pop_cfun(); +} + +static void +calculate_escaping_locals(ptrset_t &types, typemap &calc, cgraph_node *cnode) +{ + gcc_assert(cnode); + const_tree decl = cnode->decl; + gcc_assert(decl); + function *func = DECL_STRUCT_FUNCTION(decl); + gcc_assert(func); + Reason reason {}; + const_tree func_type = TREE_TYPE(decl); + assert_is_type(func_type, FUNCTION_TYPE); + update_escape_info_expr(types, calc, decl, reason); + if (types.in_points_to_record(func_type)) update_escape_info(func_type, types, reason, calc); + int i = 0; + tree var_decl = NULL; + FOR_EACH_LOCAL_DECL(func, i, var_decl) + { + gcc_assert(var_decl); + update_escape_info_expr(types, calc, var_decl, reason); + } +} + + + +static void +calculate_escaping_functions(ptrset_t &types, typemap &calc) +{ + cgraph_node *cnode = NULL; + undefset undefined_functions; + FOR_EACH_FUNCTION(cnode) + { + gcc_assert(cnode); + const bool filter = filter_known_function(cnode); + if (filter) continue; + + const_tree decl = cnode->decl; + gcc_assert(decl); + undefined_functions.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_functions.erase(decl); + mark_escaping_function(types, calc, cnode); + calculate_escaping_locals(types, calc, cnode); + calculate_escaping_ssa_names(types, calc, cnode); + } + + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode) + { + gcc_assert(cnode); + calculate_escaping_types_from_cnode(types, calc, cnode, undefined_functions); + } +} + +static void +calculate_escaping_types(ptrset_t &types, typemap &calc) +{ + calculate_escaping_types_globals(types, calc); + calculate_escaping_functions(types, calc); +} + +static void +print_escaping_types(typemap &calc) +{ + for (auto i = calc.cbegin(), e = calc.cend(); i != e; ++i) + { + const_tree type = i->first; + const Reason reason = i->second; + log ("escaping: %s (or %s) = %s\n", get_type_identifier(type).c_str(), type_to_string(type).c_str(), reason.is_escaping ? "true" : "false"); + reason.print(); + } +} + +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; + 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... + const bool interesting_case = type_esc == type_non; + if (!interesting_case) continue; + + TypeStringifier stringifier; + std::string type_esc_name = stringifier.stringify(type_esc); + std::string type_non_name = stringifier.stringify(type_non); + log("**NOT** checking for incompleteness %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()); + } + +} + + +ptrset_t *TypeEscaper::types = NULL; +typemap TypeEscaper::calc; +static TypeEscaper _typeEscaper; +static ExprEscaper exprEscaper; +TypeEscaper *ExprEscaper::typeEscaper = NULL; + +static void +update_escape_info( const_tree type, ptrset_t &types, Reason reason, typemap &calc) +{ + _typeEscaper.update(type, reason); +} + +static void +update_escape_info_expr(ptrset_t &types, typemap &calc, const_tree expr, Reason reason) +{ + exprEscaper.update(expr, reason); +} + + +static unsigned int +iphw_execute() +{ + ptrset_t types; + TypeCollector::ptrset = &types; + TypeEscaper::types = &types; + ExprEscaper::typeEscaper = &_typeEscaper; + collect_types(types); + + typemap eacalc; // Escape Analysis Calculation + // Intermediate results + // Do not read escape analysis results from here + calculate_escaping_types(types, eacalc); + place_escaping_types_in_set(types, _typeEscaper.calc); + fix_escaping_types_in_set(types); + 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..77413d5c218 --- /dev/null +++ b/gcc/ipa-prototype.h @@ -0,0 +1,21 @@ +#pragma once + +#include <map> + +struct Reason { + bool is_escaping : 1; + 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; + Reason operator|(const Reason &); + Reason& operator|=(const Reason &); + void print() const; + Reason() : is_escaping(0), global_is_visible(0), parameter_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0) {}; +}; + + +typedef std::map<const_tree, Reason> typemap; + diff --git a/gcc/ipa-type-collector.c b/gcc/ipa-type-collector.c new file mode 100644 index 00000000000..f532a7f3e48 --- /dev/null +++ b/gcc/ipa-type-collector.c @@ -0,0 +1,594 @@ +#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 "compare-types.h" +#include "types-inlines.h" +#include <set> +#include <string> +#include <map> + +#include "collect-types.h" +#include "name-types.h" +#include "type-stringifier.hpp" + +#include "ipa-type-collector.h" +#include "type-collector.hpp" +#include "expr-walker.hpp" +#include "expr-collector.hpp" + +//#define FUZZ_MODE 1 +static void collect_types(const_tree t); + +namespace type_playground { +enum type_comparison_func_enum { + EQ_POINTER = 0, + EQ_IDENTIFIER, + EQ_MAIN_VARIANT, + EQ_CANONICAL, + EQ_STRUCTURAL, + EQ_CANONICAL_STRICT, + EQ_COMPARE, + EQ_END +}; +static unsigned const type_comparisons = EQ_END; +static const char* names[type_comparisons] = { + "EQ_POINTER", + "EQ_IDENTIFIER", + "EQ_MAIN_VARIANT", + "EQ_CANONICAL", + "EQ_CANONICAL_STRICT", + "EQ_STRUCTURAL", + "EQ_COMPARE" +}; +typedef unsigned (*type_comparison_func_t)(const_tree, const_tree); +static type_comparison_func_t comparisons[type_comparisons] = { + eq_pointer, + eq_identifier, + eq_main_variant, + eq_canonical, + eq_canonical_internal, + eq_type_structural, + eq_type_compare +}; +} + + + +static void collect_types_from_expr(const_tree expr, ptrset_t &types); + + +static void +collect_types_from_stmt_assign_lhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const_tree lhs = gimple_assign_lhs(stmt); + gcc_assert(lhs); + collect_types_from_expr(lhs, types); +} + +static void +collect_types_from_stmt_assign_rhs3(gimple *stmt, ptrset_t &types) +{ + is_gimple_rhs_class(stmt, GIMPLE_TERNARY_RHS); + const_tree rhs = gimple_assign_rhs3(stmt); + gcc_assert(rhs); + collect_types_from_expr(rhs, types); +} + +static void +collect_types_from_stmt_assign_rhs2(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt); + const bool is_ternary = GIMPLE_TERNARY_RHS == gclass; + const bool is_binary = GIMPLE_BINARY_RHS == gclass; + const bool is_valid_input = is_ternary || is_binary; + gcc_assert(is_valid_input); + const_tree rhs = gimple_assign_rhs2(stmt); + gcc_assert(rhs); + collect_types_from_expr(rhs, types); +} + +static void +collect_types_from_stmt_assign_rhs1(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt); + const bool is_ternary = GIMPLE_TERNARY_RHS == gclass; + const bool is_binary = GIMPLE_BINARY_RHS == gclass; + const bool is_unary = GIMPLE_UNARY_RHS == gclass; + const bool is_single = GIMPLE_SINGLE_RHS == gclass; + const bool is_valid_input = is_ternary || is_binary || is_unary || is_single; + gcc_assert(is_valid_input); + const_tree rhs = gimple_assign_rhs1(stmt); + gcc_assert(rhs); + collect_types_from_expr(rhs, types); +} + +static void +collect_types_from_stmt_assign_rhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + const enum gimple_rhs_class gclass = gimple_assign_rhs_class(stmt); + switch (gclass) + { + case GIMPLE_TERNARY_RHS: + collect_types_from_stmt_assign_rhs3(stmt, types); + /* fall-through */ + case GIMPLE_BINARY_RHS: + collect_types_from_stmt_assign_rhs2(stmt, types); + /* fall-through */ + case GIMPLE_UNARY_RHS: + case GIMPLE_SINGLE_RHS: + collect_types_from_stmt_assign_rhs1(stmt, types); + break; + default: + gcc_unreachable(); + break; + } +} + +static void +collect_types_from_stmt_assign(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_ASSIGN); + collect_types_from_stmt_assign_lhs(stmt, types); + collect_types_from_stmt_assign_rhs(stmt, types); +} + +static void +collect_types_from_stmt_call_lhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_CALL); + const_tree lhs = gimple_call_lhs(stmt); + if (!lhs) return; + + tree fn = gimple_call_fndecl(stmt); + if (!fn) return; + + const_tree decl_name = DECL_NAME(fn); + const char *identifier = decl_name ? IDENTIFIER_POINTER(decl_name) : ""; + collect_types_from_expr(lhs, types); +} + +static void +collect_types_from_stmt_call_rhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_CALL); + unsigned num_args = gimple_call_num_args(stmt); + for (unsigned i = 0; i < num_args; i++) + { + const_tree arg_i = gimple_call_arg(stmt, i); + collect_types_from_expr(arg_i, types); + } +} + +static void +collect_types_from_stmt_call(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_CALL); + collect_types_from_stmt_call_lhs(stmt, types); + collect_types_from_stmt_call_rhs(stmt, types); +} + +static void +collect_types_from_stmt_cond_lhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_COND); + const_tree lhs = gimple_cond_lhs(stmt); + gcc_assert(lhs); + collect_types_from_expr(lhs, types); +} + +static void +collect_types_from_stmt_cond_rhs(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_COND); + const_tree rhs = gimple_cond_rhs(stmt); + gcc_assert(rhs); + collect_types_from_expr(rhs, types); +} + +static void +collect_types_from_stmt_cond(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_COND); + collect_types_from_stmt_cond_lhs(stmt, types); + collect_types_from_stmt_cond_rhs(stmt, types); +} + +static void +collect_types_from_stmt_return(gimple *stmt, ptrset_t &types) +{ + is_gimple_code(stmt, GIMPLE_RETURN); + const_tree retval = gimple_return_retval(stmt); + if (!retval) return; + + collect_types_from_expr(retval, types); +} + +static void +collect_types_from_stmt(gimple *stmt, ptrset_t &types) +{ + gcc_assert(stmt); + const enum gimple_code code = gimple_code(stmt); + switch (code) { + case GIMPLE_ASSIGN: + collect_types_from_stmt_assign(stmt, types); + break; + case GIMPLE_CALL: + collect_types_from_stmt_call(stmt, types); + break; + case GIMPLE_COND: + collect_types_from_stmt_cond(stmt, types); + break; + case GIMPLE_RETURN: + collect_types_from_stmt_return(stmt, types); + break; + case GIMPLE_LABEL: + case GIMPLE_PREDICT: + case GIMPLE_DEBUG: + case GIMPLE_SWITCH: +#ifdef FUZZ_MODE + gcc_unreachable(); +#endif + break; + default: + { + const char* name = gimple_code_name[code]; + log("gimple code name %s\n", name); + gcc_unreachable(); + } + break; + } +} + + +static void +collect_types_from_cnode_decl(cgraph_node *cnode, ptrset_t &types) +{ + gcc_assert(cnode); + const_tree decl = cnode->decl; + gcc_assert(decl); + //collect_types_from_function_decl(decl, types); +} + +static void +collect_types_from_cnode_locals(cgraph_node *cnode, ptrset_t &types) +{ + gcc_assert(cnode); + const_tree decl = cnode->decl; + gcc_assert(decl); + collect_types_from_expr(decl, types); + 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); + collect_types_from_expr(var_decl, types); + } +} + +static void +collect_types_from_cnode_ssa_names(cgraph_node *cnode, ptrset_t &types) +{ + gcc_assert(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); + collect_types_from_expr(ssa_name, types); + } + pop_cfun(); +} + +static void +collect_types_from_bb(basic_block bb, ptrset_t &types) +{ + gcc_assert(bb); + for (auto gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) + { + gimple *stmt = gsi_stmt(gsi); + gcc_assert(stmt); + collect_types_from_stmt(stmt, types); + } +} + +static void +collect_types_from_cnode_bb(cgraph_node *cnode, ptrset_t &types) +{ + gcc_assert(cnode); + cnode->get_untransformed_body(); + 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) + { + gcc_assert(bb); + collect_types_from_bb(bb, types); + } + pop_cfun(); +} + +static void +collect_types_from_global(varpool_node *vnode, ptrset_t &types) +{ + gcc_assert(vnode); + struct ipa_ref *ref = NULL; + for (unsigned i = 0; vnode->iterate_referring(i, ref); i++) + { + tree decl = vnode->decl; + gcc_assert(decl); + collect_types_from_expr(decl, types); + } +} + +static void +collect_types_from_globals(ptrset_t &types) +{ + varpool_node *vnode = NULL; + unsigned long i = 0; + FOR_EACH_VARIABLE (vnode) + { + collect_types_from_global(vnode, types); + } +} + +static void +collect_types_from_functions_with_gimple_body(cgraph_node *cnode, ptrset_t &types) +{ + gcc_assert(cnode); + collect_types_from_cnode_decl(cnode, types); + collect_types_from_cnode_locals(cnode, types); + collect_types_from_cnode_ssa_names(cnode, types); + collect_types_from_cnode_bb(cnode, types); +} + +static void +print_types_in_set(ptrset_t &types) +{ + for (auto it = types.points_to_record.cbegin(); it != types.points_to_record.cend(); ++it) + { + const_tree type = *it; + std::string name = type_to_string(type); + } +} + +static const bool +filter_comparisons_functions_char(const char* function_name) +{ + // Everything should run + if (!flag_tp_comparison_functions) return true; + + const size_t buffer_size = 1024; + const size_t cli_length = strlen(flag_tp_comparison_functions); + gcc_assert(buffer_size > cli_length); + char whitelist[buffer_size]; + strcpy(whitelist, flag_tp_comparison_functions); + + + char* saveptr = whitelist; + char* token = NULL; + while (token = strtok_r(saveptr, ",", &saveptr)) + { + const bool name_allowed = strcmp(token, function_name) == 0; + if (name_allowed) return true; + } + + return false; +} + +static const bool +filter_comparisons_functions_int(unsigned function_id) +{ + if (!flag_tp_comparison_functions) return true; + + const char* function_name = type_playground::names[function_id]; + return filter_comparisons_functions_char(function_name); +} + +static const bool +filter_comparisons_functions(type_playground::type_comparison_func_t func) +{ + if (!flag_tp_comparison_functions) return true; + + for (unsigned i = 0; i < type_playground::type_comparisons; i++) + { + if (func != type_playground::comparisons[i]) continue; + + return filter_comparisons_functions_int(i); + } + + return false; +} + + +static void +compare_types_in_set(ptrset_t &types) +{ + for (auto i = types.points_to_record.cbegin(); i != types.points_to_record.cend(); ++i) + { + for (auto j = types.points_to_record.cbegin(); j != types.points_to_record.cend(); ++j) + { + const_tree a = *i; + const_tree b = *j; + for (unsigned k = 0; k < type_playground::type_comparisons; k++) + { + type_playground::type_comparison_func_t comparison = type_playground::comparisons[k]; + const bool allowed_to_run = filter_comparisons_functions(comparison); + if (!allowed_to_run) continue; + + const bool result = comparison(a, b); + } + } + } +} + +static void +filter_out_types_in_set(ptrset_t &types) +{ + // compare everything + if (!flag_tp_types_compared) return; + + const size_t buffer_size = 1024; + const size_t cli_length = strlen(flag_tp_comparison_functions); + gcc_assert(buffer_size > cli_length); + char whitelist[buffer_size]; + strcpy(whitelist, flag_tp_types_compared); + + bool name_allowed = false; + for (auto it = types.points_to_record.cbegin(); it != types.points_to_record.cend(); name_allowed ? ++it : it = types.points_to_record.erase(it)) + { + const_tree type = *it; + std::string observed_name = get_type_identifier(type); + char* saveptr = whitelist; + char* expected_name = NULL; + name_allowed = false; + + while (expected_name = strtok_r(saveptr, ",", &saveptr)) + { + name_allowed |= strcmp(expected_name, observed_name.c_str()) == 0; + } + } + +} + +static void +sanity_check_ptr_xor_complement(ptrset_t &types) +{ + for (auto i = types.points_to_record.cbegin(), e = types.points_to_record.cend(); i != e; ++i) + { + for (auto j = types.complement.cbegin(), f = types.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(); + } + } +} + +void +collect_types(ptrset_t &types) +{ + collect_types_from_globals(types); + + cgraph_node *node = NULL; + long unsigned i = 0; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) + { + node->get_untransformed_body(); + collect_types_from_functions_with_gimple_body(node, types); + // We still need to collect types from + // the function signatures of functions without gimple bodies... + } + sanity_check_ptr_xor_complement(types); +} + +static TypeCollector _typeCollector; +ptrset_t *TypeCollector::ptrset = NULL; +static ExprCollector exprCollector; +TypeCollector * ExprCollector::typeCollector = &_typeCollector; + +static void +collect_types_from_expr(const_tree expr, ptrset_t &types) +{ + exprCollector.walk(expr); +} + + +static unsigned int +iphw_execute() +{ + //test_type_equality::run_tests(); + //test_naming_types::run_tests(); + ptrset_t types; + //ExprCollector::typeCollector = &_typeCollector; + TypeCollector::ptrset = &types; + collect_types(types); + filter_out_types_in_set(types); + compare_types_in_set(types); + return 0; +} + +namespace { +const pass_data pass_data_ipa_type_collector = +{ + SIMPLE_IPA_PASS, + "type-collector", + OPTGROUP_NONE, + TV_NONE, + (PROP_cfg | PROP_ssa), + 0, + 0, + TODO_rebuild_alias, + 0, +}; + +class pass_ipa_type_collector : public simple_ipa_opt_pass +{ +public: + pass_ipa_type_collector (gcc::context *ctx) + : simple_ipa_opt_pass(pass_data_ipa_type_collector, ctx) + {} + + virtual bool gate(function*) { return flag_ipa_type_collector; } + virtual unsigned execute (function*) { return iphw_execute(); } +}; +} // anon namespace + +simple_ipa_opt_pass* +make_pass_ipa_type_collector (gcc::context *ctx) +{ + return new pass_ipa_type_collector (ctx); +} diff --git a/gcc/ipa-type-collector.h b/gcc/ipa-type-collector.h new file mode 100644 index 00000000000..16611c2db56 --- /dev/null +++ b/gcc/ipa-type-collector.h @@ -0,0 +1,5 @@ +#pragma once + +#include "collect-types.h" + +void collect_types(ptrset_t &types); diff --git a/gcc/name-types.c b/gcc/name-types.c new file mode 100644 index 00000000000..fe8f6c5575b --- /dev/null +++ b/gcc/name-types.c @@ -0,0 +1,421 @@ +#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 "name-types.h" +#include "type-walker.hpp" + +// Using std::string because it will manage memory for us +// And we don't know whether the user will free the memory. +// Also that's why we are returning a value rather than a +// pointer... + +static const std::string +type_to_string_simple(const_tree type) +{ + gcc_assert(type); + const enum tree_code code = TREE_CODE(type); + bool valid_input = false; + switch (code) + { + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case COMPLEX_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case OFFSET_TYPE: + valid_input = true; + break; + default: + valid_input = false; + break; + } + gcc_assert(valid_input); + + + return std::string(get_tree_code_name(code)); +} + +static const std::string +type_to_string_get_field_name(const_tree field) +{ + assert_is_type(field, FIELD_DECL); + const_tree decl_name = DECL_NAME(field); + if (!decl_name) return std::string(""); + + const char* identifier = IDENTIFIER_POINTER(decl_name); + return std::string(identifier); +} + +static const unsigned +type_to_string_get_field_offset(const_tree field) +{ + assert_is_type(field, FIELD_DECL); + tree cst = byte_position(field); + gcc_assert(cst); + unsigned offset = tree_to_uhwi (cst); + return offset; +} + +static const unsigned +type_to_string_get_type_size(const_tree type) +{ + gcc_assert(type); + const_tree type_size = TYPE_SIZE(type); + const bool is_incomplete = NULL_TREE == type_size; + if (is_incomplete) return 0; + + const bool fits_uhwi = tree_fits_uhwi_p(type_size); + if (fits_uhwi) return tree_to_uhwi (type_size); + + const bool fits_shwi = tree_fits_shwi_p(type_size); + if (fits_shwi) return tree_to_shwi (type_size); + + return 0; +} + +const std::string +get_type_identifier(const_tree type) +{ + tree name = TYPE_NAME(type); + // 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. + 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); +} + +static const std::string +type_to_string_get_record_name(const_tree type) +{ + assert_is_type(type, RECORD_TYPE); + tree name = TYPE_NAME(type); + // 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. + 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); +} + +static const std::string +type_to_string_get_record_or_union_name(const_tree type) +{ + + const enum tree_code code = TREE_CODE(type); + const bool is_record = RECORD_TYPE == code; + const bool is_union = UNION_TYPE == code; + const bool is_valid_input = is_record || is_union; + gcc_assert(is_valid_input); + tree name = TYPE_NAME(type); + + // 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. + 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); +} + +/* + * The idea behind this function is to receive either + * a record or a union type and return a string that + * represents this type. + * The output should look something like this: + * 0: astruct { + * 0: int a + * 8: int b + * 16: bstruct* + * 24: cstruct { + * 0: int a + * } + * 32: { + * } + * } + * The question I have now... is... should we follos bstruct* + * to see what it points to? Because, maybe there's two bstruct*s + * defined in different TU? + * So maybe more like this: + * 0: astruct { + * 0: int a + * 8: int b + * 16: bstruct { + * 0: int a + * }* + * 24: cstruct { + * 0: int a + * } + * 32: { + * } + */ +static const std::string +type_to_string_record_or_union(const_tree type) +{ + gcc_assert(type); + const enum tree_code code = TREE_CODE(type); + const bool is_record = RECORD_TYPE == code; + const bool is_union = UNION_TYPE == code; + const bool is_valid_input = is_record || is_union; + gcc_assert(is_valid_input); + + std::string name = type_to_string_get_record_or_union_name(type); + std::string aggregate = name + std::string(" {"); + + for (tree field = TYPE_FIELDS(type); field; field = DECL_CHAIN(field)) + { + //std::string field_name = type_to_string_get_field_name(field); + const_tree field_type = TREE_TYPE(field); + const unsigned field_offset = type_to_string_get_field_offset(field); + std::string field_type_name = type_to_string(field_type, field_offset); + aggregate += field_type_name + std::string(";"); + } + + aggregate += "}"; + return aggregate; +} + +static const std::string +type_to_string_record(const_tree type) +{ + assert_is_type(type, RECORD_TYPE); + return type_to_string_record_or_union(type); +} + +static const std::string +type_to_string_union(const_tree type) +{ + assert_is_type(type, UNION_TYPE); + return type_to_string_record_or_union(type); +} + +static const std::string +type_to_string_wrapper(const_tree type) +{ + gcc_assert(type); + const enum tree_code code = TREE_CODE(type); + bool is_valid_input = false; + switch (code) + { + case POINTER_TYPE: + case ARRAY_TYPE: + case REFERENCE_TYPE: + is_valid_input = true; + break; + default: + is_valid_input = false; + break; + } + gcc_assert(is_valid_input); + + const_tree inner_type = TREE_TYPE(type); + return type_to_string(inner_type, 0, false); +} + +static const std::string +type_to_string_pointer(const_tree type) +{ + assert_is_type(type, POINTER_TYPE); + return type_to_string_wrapper(type) + std::string("*"); +} + +static const std::string +type_to_string_array(const_tree type) +{ + assert_is_type(type, ARRAY_TYPE); + return type_to_string_wrapper(type) + std::string("[]"); +} + +static const std::string +type_to_string_reference(const_tree type) +{ + assert_is_type(type, REFERENCE_TYPE); + return type_to_string_wrapper(type) + std::string("&"); +} + +static const std::string +type_to_string_function_or_method(const_tree type) +{ + gcc_assert(type); + const enum tree_code code = TREE_CODE(type); + const bool is_function = FUNCTION_TYPE == code; + const bool is_method = METHOD_TYPE == code; + const bool is_valid = is_function || is_method; + gcc_assert(is_valid); + + const_tree return_type = TREE_TYPE(type); + gcc_assert(return_type); + + const std::string return_type_name = type_to_string(return_type, 0, false); + + std::string aggregate(""); + + for(tree param = TYPE_ARG_TYPES(type); param; param = TREE_CHAIN(param)) + { + const_tree param_type = TREE_VALUE(param); + //TODO: Why no param type? + //gcc_assert(param_type); + const bool has_more_params = TREE_CHAIN(param); + aggregate += type_to_string(param_type); + if (!has_more_params) break; + + aggregate += std::string(", "); + } + + //TODO: Add base_type for method types + std::string retval = return_type_name + std::string("(") + aggregate + std::string(")"); + return retval; +} + +static const std::string +type_to_string_function(const_tree type) +{ + assert_is_type(type, FUNCTION_TYPE); + return type_to_string_function_or_method(type); +} + +static const std::string +type_to_string_method(const_tree type) +{ + assert_is_type(type, METHOD_TYPE); + return type_to_string_function_or_method(type); +} + + +const std::string +type_to_string(const_tree type, const unsigned field_offset, const bool add_prelude) +{ + gcc_assert(type); + const enum tree_code code = TREE_CODE(type); + const unsigned size = type_to_string_get_type_size(type); + std::string prelude = add_prelude ? std::to_string(field_offset) + std::string(",") + std::to_string(field_offset + size) + std::string(":") : std::string(""); + + switch (code) + { + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case COMPLEX_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case OFFSET_TYPE: + return prelude + type_to_string_simple(type); + break; + default: + break; + } + + switch (code) + { + case RECORD_TYPE: + return prelude + type_to_string_record(type); + break; + case UNION_TYPE: + return prelude + type_to_string_union(type); + break; + case POINTER_TYPE: + return prelude + type_to_string_pointer(type); + break; + case REFERENCE_TYPE: + return prelude + type_to_string_reference(type); + break; + case ARRAY_TYPE: + return prelude + type_to_string_array(type); + break; + case FUNCTION_TYPE: + return prelude + type_to_string_function(type); + break; + case METHOD_TYPE: + return prelude + type_to_string_method(type); + break; + case QUAL_UNION_TYPE: + case LANG_TYPE: + default: + // unimplemented + gcc_unreachable(); + break; + } + + gcc_unreachable(); + return std::string("you shouldn't ever see this"); +} + +namespace test_naming_types { + +void test_generic_to_string(const enum tree_code code, const char * expected_char_array) +{ + std::string expected_value(expected_char_array); + tree type = make_node(code); + std::string observed_value = type_to_string(type); + const bool success = expected_value.compare(observed_value) == 0; + gcc_assert(success); + +} +void test_simple_to_string() +{ + test_generic_to_string(VOID_TYPE, "0:void_type"); + test_generic_to_string(INTEGER_TYPE, "0:integer_type"); + test_generic_to_string(REAL_TYPE, "0:real_type"); + test_generic_to_string(FIXED_POINT_TYPE, "0:fixed_point_type"); + test_generic_to_string(COMPLEX_TYPE, "0:complex_type"); + test_generic_to_string(ENUMERAL_TYPE, "0:enumeral_type"); + test_generic_to_string(BOOLEAN_TYPE, "0:boolean_type"); + test_generic_to_string(OFFSET_TYPE, "0:offset_type"); +} + +void run_tests() +{ + test_simple_to_string(); +} +}; diff --git a/gcc/name-types.h b/gcc/name-types.h new file mode 100644 index 00000000000..b127bef17ac --- /dev/null +++ b/gcc/name-types.h @@ -0,0 +1,7 @@ +#pragma once + +#include "tree.h" +#include <string> + +const std::string type_to_string(const_tree type, const unsigned field_offset=0, const bool add_prelude=true); +const std::string get_type_identifier(const_tree type); diff --git a/gcc/passes.def b/gcc/passes.def index d642cc662b7..08a863fe617 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -151,6 +151,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_ipa_devirt); NEXT_PASS (pass_ipa_type_escape_analysis); NEXT_PASS (pass_ipa_hello_world); + NEXT_PASS (pass_ipa_type_collector); NEXT_PASS (pass_ipa_cp); NEXT_PASS (pass_ipa_sra); NEXT_PASS (pass_ipa_cdtor_merge); @@ -174,6 +175,7 @@ along with GCC; see the file COPYING3. If not see INSERT_PASSES_AFTER (all_late_ipa_passes) NEXT_PASS (pass_materialize_all_clones); 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/testsuite/gcc.dg/ipa/type-playground-00.c b/gcc/testsuite/gcc.dg/ipa/type-playground-00.c new file mode 100644 index 00000000000..b94c4c0d643 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-00.c @@ -0,0 +1,21 @@ +/* { dg-do link } */ +/* { dg-options "-flto -fipa-type-collector -fdump-ipa-type-collector -ftp-comparison-functions=EQ_POINTER -ftp-types-compared=int " } */ + +int +main () +{ + int a = 0; + const int b = 0; + return 0; +} + +// This is proof that comparing trees using only +// pointer equality yields different trees +// when types have different attributes. +// i.e. +// TREE_TYPE(a) == TREE_TYPE(b) +// evaluates to false + + +/* { dg-final { scan-wpa-ipa-dump "0,32:integer_type x 0,32:integer_type = f," "hello-world" } } */ + diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-01.c b/gcc/testsuite/gcc.dg/ipa/type-playground-01.c new file mode 100644 index 00000000000..d8c69aef4db --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-01.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-type-collector -fdump-ipa-type-collector -ftp-comparison-functions=EQ_STRUCTURAL -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type cannot be compared +// via structural equality. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "type-collector" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-02.c b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c new file mode 100644 index 00000000000..1101bb51d8a --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-02.c @@ -0,0 +1,19 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-type-collector -fdump-ipa-type-collector -ftp-comparison-functions=EQ_MAIN_VARIANT -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type cannot be compared +// via main variant equality. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "type-collector" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-03.c b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c new file mode 100644 index 00000000000..5de12a31158 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-03.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-type-collector -fdump-ipa-type-collector -ftp-comparison-functions=EQ_IDENTIFIER -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type **CAN** be compared +// via identifier identity. +// Intuitevely, identifier identity may give false positives (and maybe false negatives too?) +// So, it must be the last resort comparisons. +// +// If we say that an identifier comparison may give false positives and false negatives +// then maybe it would be useful to documents attempts to explicitly produce false positives +// and false negatives to better understand what causes them. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = t, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = t," "type-collector" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/type-playground-04.c b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c new file mode 100644 index 00000000000..f6f32c09d4f --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/type-playground-04.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-flto -fipa-type-collector -fdump-ipa-type-collector -ftp-comparison-functions=EQ_CANONICAL -ftp-types-compared=astruct_s" } */ + +struct astruct_s { + struct astruct_s* a; +}; + +int +main(int argc, char* argv) +{ + struct astruct_s a; +} + +// This is proof that an incomplete type **CAN** be compared +// via identifier identity. +// Intuitevely, identifier identity may give false positives (and maybe false negatives too?) +// So, it must be the last resort comparisons. +// +// If we say that an identifier comparison may give false positives and false negatives +// then maybe it would be useful to documents attempts to explicitly produce false positives +// and false negatives to better understand what causes them. + +// 0,64:astruct_s {0,64:astruct_s {}*;} x 0,0:astruct_s {} = f, +// I am not an expert on regex +/* { dg-final { scan-wpa-ipa-dump "0,64:astruct_s .0,64:astruct_s ..... x 0,0:astruct_s .. = f," "type-collector" } } */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 439c4657696..bdb349b398c 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -504,6 +504,8 @@ extern simple_ipa_opt_pass *make_pass_ipa_free_lang_data (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_free_fn_summary (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_type_escape_analysis (gcc::context *ctxt); extern simple_ipa_opt_pass *make_pass_ipa_hello_world (gcc::context *ctxt); +extern simple_ipa_opt_pass *make_pass_ipa_type_collector (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); diff --git a/gcc/type-collector.c b/gcc/type-collector.c new file mode 100644 index 00000000000..3def624c4ac --- /dev/null +++ b/gcc/type-collector.c @@ -0,0 +1,245 @@ +#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(ptrset && t); + + if (!ptr.empty()) + { + TypeStringifier stringifier; + std::string in_name = stringifier.stringify(t); + log("in %s size = %d\n", in_name.c_str(), ptr.size()); + gcc_unreachable(); + } + walk(t); +} + +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_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_void_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_integer_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_integer_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_real_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_real_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_fixed_point_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_fixed_point_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_complex_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_complex_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_enumeral_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_enumeral_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_boolean_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_boolean_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_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_array_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_pointer_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_pointer_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_reference_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_reference_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_record_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_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_union_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_union_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_function_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_function_pre(const_tree t) +{ + ptr[t] = false; +} + +void +TypeCollector::_walk_method_post(const_tree t) +{ + _collect_simple(t); +} + +void +TypeCollector::_walk_method_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..98b08d99f83 --- /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() {}; + + static ptrset_t* ptrset; +private: + std::map<const_tree, bool> ptr; + + void _collect_simple(const_tree t); + virtual bool is_memoized(const_tree t); + + virtual void _walk_void_pre(const_tree t); + virtual void _walk_void_post(const_tree t); + virtual void _walk_integer_pre(const_tree t); + virtual void _walk_integer_post(const_tree t); + virtual void _walk_real_pre(const_tree t); + virtual void _walk_real_post(const_tree t); + virtual void _walk_fixed_point_pre(const_tree t); + virtual void _walk_fixed_point_post(const_tree t); + virtual void _walk_complex_pre(const_tree t); + virtual void _walk_complex_post(const_tree t); + virtual void _walk_enumeral_pre(const_tree t); + virtual void _walk_enumeral_post(const_tree t); + virtual void _walk_boolean_pre(const_tree t); + virtual void _walk_boolean_post(const_tree t); + virtual void _walk_array_pre(const_tree t); + virtual void _walk_array_post(const_tree t); + virtual void _walk_pointer_pre(const_tree t); + virtual void _walk_pointer_post(const_tree t); + virtual void _walk_reference_pre(const_tree t); + virtual void _walk_reference_post(const_tree t); + virtual void _walk_record_pre(const_tree t); + virtual void _walk_record_post(const_tree t); + virtual void _walk_union_pre(const_tree t); + virtual void _walk_union_post(const_tree t); + virtual void _walk_function_pre(const_tree t); + virtual void _walk_function_post(const_tree t); + virtual void _walk_method_pre(const_tree t); + virtual void _walk_method_post(const_tree t); +}; + diff --git a/gcc/type-escaper.hpp b/gcc/type-escaper.hpp new file mode 100644 index 00000000000..c0bea8383fa --- /dev/null +++ b/gcc/type-escaper.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include "ipa-prototype.h" + +class TypeEscaper : public TypeWalker +{ +public: + TypeEscaper() : _inside_union(0) {}; + void update(const_tree t, Reason r); + static ptrset_t *types; + static typemap calc; +private: + virtual void _walk_pointer_pre(const_tree t); + virtual void _walk_reference_pre(const_tree t); + virtual void _walk_array_pre(const_tree t); + virtual void _walk_record_pre(const_tree t); + virtual void _walk_union_pre(const_tree t); + virtual void _walk_union_post(const_tree t); + virtual void _walk_method_pre(const_tree t); + virtual void _walk_function_pre(const_tree t); + virtual bool is_memoized(const_tree t); + unsigned _inside_union; + Reason _reason; + void _update(const_tree t); +}; + +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; +} + +void +TypeEscaper::update(const_tree t, Reason r) +{ + gcc_assert(t && types); + _reason = r; + walk(t); +} + +void +TypeEscaper::_update(const_tree t) +{ + gcc_assert(t); + // assert type is in universe + const bool already_in_typemap = calc.find(t) != calc.end(); + already_in_typemap ? calc[t] |= _reason : calc[t] = _reason; +} + +void +TypeEscaper::_walk_array_pre(const_tree t) +{ + _update(t); +} + +void +TypeEscaper::_walk_pointer_pre(const_tree t) +{ + _update(t); +} + +void +TypeEscaper::_walk_reference_pre(const_tree t) +{ + _update(t); +} + +void +TypeEscaper::_walk_record_pre(const_tree t) +{ + _update(t); +} + +void +TypeEscaper::_walk_union_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; + _reason.is_escaping |= is_escaping; +} + +void +TypeEscaper::_walk_union_post(const_tree t) +{ + _inside_union--; + Reason prev = calc[t]; + _update(t); + _reason = prev; +} + +void +TypeEscaper::_walk_function_pre(const_tree t) +{ + _update(t); +} + +void +TypeEscaper::_walk_method_pre(const_tree t) +{ + _update(t); +} diff --git a/gcc/type-stringifier.c b/gcc/type-stringifier.c new file mode 100644 index 00000000000..3b2a50604e0 --- /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_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_integer_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_real_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_fixed_point_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_complex_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_offset_pre(const_tree t) +{ + _stringify_simple(t); +} + +void +TypeStringifier::_walk_boolean_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_post(const_tree t) +{ + this->_stringification += std::string("*"); +} + +void +TypeStringifier::_walk_array_post(const_tree t) +{ + this->_stringification += std::string("[]"); +} + +void +TypeStringifier::_walk_reference_post(const_tree t) +{ + this->_stringification += std::string("&"); +} + +void +TypeStringifier::_walk_union_pre(const_tree t) +{ + this->_stringification += std::string(" union "); + _stringify_aggregate_pre(t); +} + +void +TypeStringifier::_walk_union_post(const_tree t) +{ + _stringify_aggregate_post(t); +} + +void +TypeStringifier::_walk_record_pre(const_tree t) +{ + this->_stringification += std::string(" record "); + _stringify_aggregate_pre(t); +} + +void +TypeStringifier::_walk_record_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(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_pre(const_tree t) +{ + _stringify_fm_pre(t); +} + +void +TypeStringifier::_walk_method_post(const_tree t) +{ + _stringify_fm_post(t); +} + +void +TypeStringifier::_walk_function_pre(const_tree t) +{ + _stringify_fm_pre(t); +} + +void +TypeStringifier::_walk_function_post(const_tree t) +{ + _stringify_fm_post(t); +} + +void +TypeStringifier::_stringify_fm_pre(const_tree t) +{ + this->_stringification += std::string("function { "); +} + +void +TypeStringifier::_stringify_fm_post(const_tree t) +{ + this->_stringification += std::string("}"); +} + +void +TypeStringifier::_walk_return_pre(const_tree t) +{ + this->_stringification += std::string("("); +} + +void +TypeStringifier::_walk_return_post(const_tree t) +{ + this->_stringification += std::string(")"); +} + +void +TypeStringifier::_walk_args_pre(const_tree t) +{ + this->_stringification += std::string("("); +} + +void +TypeStringifier::_walk_args_post(const_tree t) +{ + this->_stringification += std::string(")"); +} + +void +TypeStringifier::_walk_arg_post(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..49e9054ab5e --- /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; + + static std::string get_type_identifier(const_tree t); + static std::string get_field_identifier(const_tree t); + + 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_pre(const_tree t); + virtual void _walk_integer_pre(const_tree t); + virtual void _walk_real_pre(const_tree t); + virtual void _walk_fixed_point_pre(const_tree t); + virtual void _walk_complex_pre(const_tree t); + virtual void _walk_boolean_pre(const_tree t); + virtual void _walk_offset_pre(const_tree t); + virtual void _walk_pointer_post(const_tree t); + virtual void _walk_reference_post(const_tree t); + virtual void _walk_array_post(const_tree t); + virtual void _walk_record_pre(const_tree t); + virtual void _walk_record_post(const_tree t); + virtual void _walk_union_pre(const_tree t); + virtual void _walk_union_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_pre(const_tree t); + virtual void _walk_method_post(const_tree t); + virtual void _walk_function_pre(const_tree t); + virtual void _walk_function_post(const_tree t); +public: + std::string stringify(const_tree t); + TypeStringifier() {}; +}; + diff --git a/gcc/type-walker.c b/gcc/type-walker.c new file mode 100644 index 00000000000..b74db433ee9 --- /dev/null +++ b/gcc/type-walker.c @@ -0,0 +1,406 @@ +#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, this->tset); +} + +void +TypeWalker::_walk(const_tree type, tset_t &tset) +{ + 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, tset); + break; + case INTEGER_TYPE: + this->walk_integer(type, tset); + break; + case REAL_TYPE: + this->walk_real(type, tset); + break; + case FIXED_POINT_TYPE: + this->walk_fixed_point(type, tset); + break; + case COMPLEX_TYPE: + this->walk_complex(type, tset); + break; + case ENUMERAL_TYPE: + this->walk_enumeral(type, tset); + break; + case BOOLEAN_TYPE: + this->walk_boolean(type, tset); + break; + case OFFSET_TYPE: + this->walk_offset(type, tset); + break; + case RECORD_TYPE: + this->walk_record(type, tset); + break; + case POINTER_TYPE: + this->walk_pointer(type, tset); + break; + case REFERENCE_TYPE: + this->walk_reference(type, tset); + break; + case ARRAY_TYPE: + this->walk_array(type, tset); + break; + case UNION_TYPE: + this->walk_union(type, tset); + break; + case FUNCTION_TYPE: + this->walk_function(type, tset); + break; + case METHOD_TYPE: + this->walk_method(type, tset); + break; + case QUAL_UNION_TYPE: + case LANG_TYPE: + default: + { + log("missing %s\n", get_tree_code_name(code)); + gcc_unreachable(); + } + break; + } + + tset.erase(type); +} + +void +TypeWalker::walk_void(const_tree t, tset_t &tset) +{ + assert_is_type(t, VOID_TYPE); + _walk_void_pre(t); + _walk_void(t, tset); + _walk_void_post(t); +} + +void +TypeWalker::_walk_void(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_integer(const_tree t, tset_t &tset) +{ + assert_is_type(t, INTEGER_TYPE); + _walk_integer_pre(t); + _walk_integer(t, tset); + _walk_integer_post(t); +} + +void +TypeWalker::_walk_integer(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_real(const_tree t, tset_t &tset) +{ + assert_is_type(t, REAL_TYPE); + _walk_real_pre(t); + _walk_real(t, tset); + _walk_real_post(t); +} + +void +TypeWalker::_walk_real(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_boolean(const_tree t, tset_t &tset) +{ + assert_is_type(t, BOOLEAN_TYPE); + _walk_boolean_pre(t); + _walk_boolean(t, tset); + _walk_boolean_post(t); +} + +void +TypeWalker::_walk_boolean(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_offset(const_tree t, tset_t &tset) +{ + assert_is_type(t, OFFSET_TYPE); + _walk_offset_pre(t); + _walk_offset(t, tset); + _walk_offset_post(t); +} + +void +TypeWalker::_walk_offset(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_fixed_point(const_tree t, tset_t &tset) +{ + assert_is_type(t, FIXED_POINT_TYPE); + _walk_fixed_point_pre(t); + _walk_fixed_point(t, tset); + _walk_fixed_point_post(t); +} + +void +TypeWalker::_walk_fixed_point(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_complex(const_tree t, tset_t &tset) +{ + assert_is_type(t, COMPLEX_TYPE); + _walk_complex_pre(t); + _walk_complex(t, tset); + _walk_complex_post(t); +} + +void +TypeWalker::_walk_complex(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_enumeral(const_tree t, tset_t &tset) +{ + assert_is_type(t, ENUMERAL_TYPE); + _walk_enumeral_pre(t); + _walk_enumeral(t, tset); + _walk_enumeral_post(t); +} + +void +TypeWalker::_walk_enumeral(const_tree t, tset_t &tset) {}; + +void +TypeWalker::walk_pointer(const_tree t, tset_t &tset) +{ + assert_is_type(t, POINTER_TYPE); + _walk_pointer_pre(t); + _walk_pointer(t, tset); + _walk_pointer_post(t); +} + +void +TypeWalker::_walk_pointer(const_tree t, tset_t &tset) +{ + _walk_wrapper(t, tset); +} + +void +TypeWalker::walk_reference(const_tree t, tset_t &tset) +{ + assert_is_type(t, REFERENCE_TYPE); + _walk_reference_pre(t); + _walk_reference(t, tset); + _walk_reference_post(t); +} + +void +TypeWalker::_walk_reference(const_tree t, tset_t &tset) +{ + _walk_wrapper(t, tset); +} + +void +TypeWalker::walk_array(const_tree t, tset_t &tset) +{ + assert_is_type(t, ARRAY_TYPE); + _walk_array_pre(t); + _walk_array(t, tset); + _walk_array_post(t); +} + +void +TypeWalker::_walk_array(const_tree t, tset_t &tset) +{ + _walk_wrapper(t, tset); +} + +void +TypeWalker::_walk_wrapper(const_tree t, tset_t &tset) +{ + const_tree inner_type = TREE_TYPE(t); + gcc_assert(inner_type); + _walk(inner_type, tset); +} + +void +TypeWalker::walk_record(const_tree t, tset_t &tset) +{ + assert_is_type(t, RECORD_TYPE); + _walk_record_pre(t); + _walk_record(t, tset); + _walk_record_post(t); +} + +void +TypeWalker::_walk_record(const_tree t, tset_t &tset) +{ + _walk_record_or_union(t, tset); +} + +void +TypeWalker::walk_union(const_tree t, tset_t &tset) +{ + assert_is_type(t, UNION_TYPE); + _walk_union_pre(t); + _walk_union(t, tset); + _walk_union_post(t); +} + +void +TypeWalker::_walk_union(const_tree t, tset_t &tset) +{ + _walk_record_or_union(t, tset); +} + +void +TypeWalker::_walk_record_or_union(const_tree t, tset_t &tset) +{ + for (tree field = TYPE_FIELDS(t); field; field = DECL_CHAIN(field)) + { + gcc_assert(field); + walk_field(field, tset); + } +} + +void +TypeWalker::walk_field(const_tree t, tset_t &tset) +{ + _walk_field_pre(t); + _walk_field(t, tset); + _walk_field_post(t); +} + +void +TypeWalker::_walk_field(const_tree t, tset_t &tset) +{ + const_tree inner_type = TREE_TYPE(t); + gcc_assert(inner_type); + _walk(inner_type, tset); +} + +void +TypeWalker::walk_function(const_tree t, tset_t &tset) +{ + assert_is_type(t, FUNCTION_TYPE); + _walk_function_pre(t); + _walk_function(t, tset); + _walk_function_post(t); +} + +void +TypeWalker::_walk_function(const_tree t, tset_t &tset) +{ + _walk_function_or_method(t, tset); +} + +void +TypeWalker::walk_method(const_tree t, tset_t &tset) +{ + assert_is_type(t, METHOD_TYPE); + _walk_method_pre(t); + _walk_method(t, tset); + _walk_method_post(t); +} + +void +TypeWalker::_walk_method(const_tree t, tset_t &tset) +{ + _walk_function_or_method(t, tset); +} + +void +TypeWalker::_walk_function_or_method(const_tree t, tset_t &tset) +{ + const_tree ret_type = TREE_TYPE(t); + walk_return(ret_type, tset); + walk_args(t, tset); +} + +void +TypeWalker::walk_return(const_tree t, tset_t &tset) +{ + _walk_return_pre(t); + _walk_return(t, tset); + _walk_return_post(t); +} + +void +TypeWalker::_walk_return(const_tree t, tset_t &tset) +{ + _walk(t, tset); +} + +void +TypeWalker::walk_args(const_tree t, tset_t &tset) +{ + _walk_args_pre(t); + _walk_args(t, tset); + _walk_args_post(t); +} + +void +TypeWalker::_walk_args(const_tree t, tset_t &tset) +{ + assert_is_type(t, FUNCTION_TYPE); + for (tree arg_node = TYPE_ARG_TYPES(t); NULL_TREE != arg_node; arg_node = TREE_CHAIN(arg_node)) + { + tree arg_node_type = TREE_VALUE(arg_node); + gcc_assert(arg_node_type); + walk_arg(arg_node_type, tset); + } +} + +void +TypeWalker::walk_arg(const_tree t, tset_t &tset) +{ + _walk_arg_pre(t); + _walk_arg(t, tset); + _walk_arg_post(t); +} + +void +TypeWalker::_walk_arg(const_tree t, tset_t &tset) +{ + _walk(t, tset); +} diff --git a/gcc/type-walker.hpp b/gcc/type-walker.hpp new file mode 100644 index 00000000000..0f775d170e8 --- /dev/null +++ b/gcc/type-walker.hpp @@ -0,0 +1,97 @@ +#pragma once + +#include <set> + +class TypeWalker { +protected: + typedef std::set<const_tree> tset_t; +private: + tset_t tset; + + void _walk(const_tree t, tset_t &tset); + void _walk_wrapper(const_tree t, tset_t &tset); + void _walk_record_or_union(const_tree t, tset_t &tset); + void _walk_function_or_method(const_tree t, tset_t &tset); + virtual bool is_memoized(const_tree t) { return false; }; + + virtual void _walk_void_pre(const_tree t) {}; + void walk_void(const_tree t, tset_t &tset); + void _walk_void(const_tree t, tset_t &tset); + virtual void _walk_void_post(const_tree t) {}; + virtual void _walk_integer_pre(const_tree t) {}; + void walk_integer(const_tree t, tset_t &tset); + void _walk_integer(const_tree t, tset_t &tset); + virtual void _walk_integer_post(const_tree t) {}; + virtual void _walk_real_pre(const_tree t) {}; + void walk_real(const_tree t, tset_t &tset); + void _walk_real(const_tree t, tset_t &tset); + virtual void _walk_real_post(const_tree t) {}; + virtual void _walk_fixed_point_pre(const_tree t) {}; + void walk_fixed_point(const_tree t, tset_t &tset); + void _walk_fixed_point(const_tree t, tset_t &tset); + virtual void _walk_fixed_point_post(const_tree t) {}; + virtual void _walk_complex_pre(const_tree t) {}; + void _walk_complex(const_tree t, tset_t &tset); + void walk_complex(const_tree t, tset_t &tset); + virtual void _walk_complex_post(const_tree t) {}; + virtual void _walk_enumeral_pre(const_tree t) {}; + void walk_enumeral(const_tree t, tset_t &tset); + void _walk_enumeral(const_tree t, tset_t &tset); + virtual void _walk_enumeral_post(const_tree t) {}; + virtual void _walk_boolean_pre(const_tree t) {}; + void walk_boolean(const_tree t, tset_t &tset); + void _walk_boolean(const_tree t, tset_t &tset); + virtual void _walk_boolean_post(const_tree t) {}; + virtual void _walk_offset_pre(const_tree t) {}; + void walk_offset(const_tree t, tset_t &tset); + void _walk_offset(const_tree t, tset_t &tset); + virtual void _walk_offset_post(const_tree t) {}; + virtual void _walk_record_pre(const_tree t) {}; + void walk_record(const_tree t, tset_t &tset); + void _walk_record(const_tree t, tset_t &tset); + virtual void _walk_record_post(const_tree t) {}; + virtual void _walk_pointer_pre(const_tree t) {}; + void walk_pointer(const_tree t, tset_t &tset); + void _walk_pointer(const_tree t, tset_t &tset); + virtual void _walk_pointer_post(const_tree t) {}; + virtual void _walk_reference_pre(const_tree t) {}; + void walk_reference(const_tree t, tset_t &tset); + void _walk_reference(const_tree t, tset_t &tset); + virtual void _walk_reference_post(const_tree t) {}; + virtual void _walk_array_pre(const_tree t) {}; + void walk_array(const_tree t, tset_t &tset); + void _walk_array(const_tree t, tset_t &tset); + virtual void _walk_array_post(const_tree t) {}; + virtual void _walk_union_pre(const_tree t) {}; + void walk_union(const_tree t, tset_t &tset); + void _walk_union(const_tree t, tset_t &tset); + virtual void _walk_union_post(const_tree t) {}; + virtual void _walk_field_pre(const_tree) {}; + void walk_field(const_tree t, tset_t &tset); + void _walk_field(const_tree t, tset_t &tset); + virtual void _walk_field_post(const_tree t) {}; + virtual void _walk_return_pre(const_tree t) {}; + void walk_return(const_tree, tset_t &tset); + void _walk_return(const_tree, tset_t &tset); + virtual void _walk_return_post(const_tree t) {}; + virtual void _walk_args_pre(const_tree t) {}; + void walk_args(const_tree t, tset_t &tset); + void _walk_args(const_tree t, tset_t &tset); + virtual void _walk_args_post(const_tree t) {}; + virtual void _walk_arg_pre(const_tree t) {}; + void walk_arg(const_tree t, tset_t &tset); + void _walk_arg(const_tree t, tset_t &tset); + virtual void _walk_arg_post(const_tree t) {}; + virtual void _walk_function_pre(const_tree t) {}; + void walk_function(const_tree t, tset_t &tset); + void _walk_function(const_tree t, tset_t &tset); + virtual void _walk_function_post(const_tree t) {}; + virtual void _walk_method_pre(const_tree t) {}; + void walk_method(const_tree t, tset_t &tset); + void _walk_method(const_tree t, tset_t &tset); + virtual void _walk_method_post(const_tree t) {}; +public: + void walk(const_tree t); + TypeWalker() {}; +}; + diff --git a/gcc/types-inlines.h b/gcc/types-inlines.h new file mode 100644 index 00000000000..40ff45c491b --- /dev/null +++ b/gcc/types-inlines.h @@ -0,0 +1,67 @@ +#pragma once + + + +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 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); +} |