diff options
author | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-10 08:31:15 +0200 |
---|---|---|
committer | Erick Ochoa <erick.ochoa@theobroma-systems.com> | 2020-06-10 11:48:31 +0200 |
commit | 6772b81536fe5f5a1852cf090d6847c961a4d73e (patch) | |
tree | 86df5488848a611868c11494ea7e1da3f0b3a2ab | |
parent | ea839b8d57733aecc413b4b91935fb59d04a3303 (diff) |
Adds GimpleAccessor and ExprAccessor
These classes will determine whether either READ or WRITE accesses
occur to fields in structures. Tests for determining accesses are passing
-rw-r--r-- | gcc/Makefile.in | 2 | ||||
-rw-r--r-- | gcc/common.opt | 4 | ||||
-rw-r--r-- | gcc/expr-accessor.c | 82 | ||||
-rw-r--r-- | gcc/expr-accessor.hpp | 27 | ||||
-rw-r--r-- | gcc/gimple-accesser.c | 105 | ||||
-rw-r--r-- | gcc/gimple-accesser.hpp | 24 | ||||
-rw-r--r-- | gcc/gimple-caster.c | 61 | ||||
-rw-r--r-- | gcc/gimple-caster.hpp | 5 | ||||
-rw-r--r-- | gcc/gimple-escaper.c | 3 | ||||
-rw-r--r-- | gcc/gimple-escaper.hpp | 2 | ||||
-rw-r--r-- | gcc/gimple-walker.c | 2 | ||||
-rw-r--r-- | gcc/ipa-prototype.h | 2 | ||||
-rw-r--r-- | gcc/ipa-type-escape-analysis.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c | 17 | ||||
-rw-r--r-- | gcc/type-incomplete-equality.c | 6 | ||||
-rw-r--r-- | gcc/type-walker.c | 2 |
22 files changed, 372 insertions, 33 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 1f7a349a4c6..bf0623be999 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1412,6 +1412,8 @@ OBJS = \ type-walker.o \ expr-walker.o \ gimple-walker.o \ + gimple-accesser.o \ + expr-accessor.o \ type-collector.o \ expr-collector.o \ gimple-collector.o \ diff --git a/gcc/common.opt b/gcc/common.opt index ec351e2f96f..ddc872e8c5b 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -3466,4 +3466,8 @@ fprint-cast-analysis Common Report Var(flag_print_cast_analysis) Optimization This flag is used to print the escape analysis including type casting. +fprint-access-analysis +Common Report Var(flag_print_access_analysis) Optimization +This flag is used to print the access analysis (if field is read or written to). + ; This comment is to ensure we retain the blank line above. diff --git a/gcc/expr-accessor.c b/gcc/expr-accessor.c new file mode 100644 index 00000000000..594c8d553d6 --- /dev/null +++ b/gcc/expr-accessor.c @@ -0,0 +1,82 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple-expr.h" +#include "predict.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "fold-const.h" +#include "gimple-fold.h" +#include "symbol-summary.h" +#include "tree-vrp.h" +#include "ipa-prop.h" +#include "tree-pretty-print.h" +#include "tree-inline.h" +#include "ipa-fnsummary.h" +#include "ipa-utils.h" +#include "tree-ssa-ccp.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-ssa-alias.h" +#include "tree-ssanames.h" +#include "gimple.h" +#include "cfg.h" // needed for gimple-iterator.h +#include "gimple-iterator.h" +#include "gimple-ssa.h" +#include <stdbool.h> + + +#include "types-inlines.h" +#include "type-stringifier.hpp" +#include "expr-accessor.hpp" +#include "expr-walker.hpp" + +void +ExprAccessor::update(const_tree e, unsigned access) +{ + _access = access; + walk(e); +} + +void +ExprAccessor::_walk_COMPONENT_REF_pre(const_tree e) +{ + assert_is_type(e, COMPONENT_REF); + const_tree op0 = TREE_OPERAND(e, 0); + gcc_assert(op0); + const_tree op0_t = TREE_TYPE(op0); + gcc_assert(op0_t); + const_tree op1 = TREE_OPERAND(e, 1); + assert_is_type(op1, FIELD_DECL); + const bool record_already_in_map = record_field_map.find(op0_t) != record_field_map.end(); + field_access_map_t field_map; + field_map = record_already_in_map ? record_field_map[op0_t] : field_map; + const bool field_already_in_map = field_map.find(op1) != field_map.end(); + unsigned prev_access = field_already_in_map ? field_map[op1] : Empty; + + prev_access |= _access; + field_map[op1] = prev_access; + record_field_map[op0_t] = field_map; +} + +void +ExprAccessor::print_accesses() +{ + for (auto i = record_field_map.cbegin(), e = record_field_map.cend(); i != e; ++i) + { + const_tree record = i->first; + field_access_map_t field_map = i->second; + for (auto j = field_map.cbegin(), f = field_map.cend(); j != f; ++j) + { + const_tree field = j->first; + const std::string name_r = TypeStringifier::get_type_identifier(record); + const std::string name_f = TypeStringifier::get_field_identifier(field); + unsigned access = j->second; + log("%s.%s = 0x%04x\n", name_r.c_str(), name_f.c_str(), access); + } + } +} diff --git a/gcc/expr-accessor.hpp b/gcc/expr-accessor.hpp new file mode 100644 index 00000000000..c3a0b4ecef7 --- /dev/null +++ b/gcc/expr-accessor.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "ipa-prototype.h" +#include "expr-walker.hpp" +#include "type-escaper.hpp" +#include "collect-types.h" +#include <tuple> +#include <map> + +constexpr unsigned Empty = 0x0u; +constexpr unsigned Read = 0x01u; +constexpr unsigned Write = 0x02u; + +typedef std::map<const_tree, unsigned> field_access_map_t; +typedef std::map<const_tree, field_access_map_t> record_field_map_t; + +class ExprAccessor : public ExprWalker +{ +public: + ExprAccessor() {}; + void update(const_tree e, unsigned a); + void print_accesses(); +private: + unsigned _access; + record_field_map_t record_field_map; + virtual void _walk_COMPONENT_REF_pre(const_tree e); +}; diff --git a/gcc/gimple-accesser.c b/gcc/gimple-accesser.c new file mode 100644 index 00000000000..18d74f499c0 --- /dev/null +++ b/gcc/gimple-accesser.c @@ -0,0 +1,105 @@ +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "tree.h" +#include "gimple-expr.h" +#include "predict.h" +#include "alloc-pool.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "diagnostic.h" +#include "fold-const.h" +#include "gimple-fold.h" +#include "symbol-summary.h" +#include "tree-vrp.h" +#include "ipa-prop.h" +#include "tree-pretty-print.h" +#include "tree-inline.h" +#include "ipa-fnsummary.h" +#include "ipa-utils.h" +#include "tree-ssa-ccp.h" +#include "stringpool.h" +#include "attribs.h" +#include "tree-ssa-alias.h" +#include "tree-ssanames.h" +#include "gimple.h" +#include "cfg.h" +#include "gimple-iterator.h" +#include "gimple-ssa.h" + +#include "types-inlines.h" +#include "gimple-accesser.hpp" + + +void +GimpleAccesser::_walk_pre(gassign *s) +{ + // There seems to be quite a bit of code duplication here... + const enum gimple_rhs_class code = gimple_assign_rhs_class(s); + switch (code) + { + case GIMPLE_TERNARY_RHS: + { + const_tree rhs3 = gimple_assign_rhs3(s); + gcc_assert(rhs3); + exprAccessor.update(rhs3, Read); + } + /* fall-through */ + case GIMPLE_BINARY_RHS: + { + const_tree rhs2 = gimple_assign_rhs2(s); + gcc_assert(rhs2); + exprAccessor.update(rhs2, Read); + } + /* fall-through */ + case GIMPLE_UNARY_RHS: + case GIMPLE_SINGLE_RHS: + { + const_tree rhs1 = gimple_assign_rhs1(s); + exprAccessor.update(rhs1, Read); + const_tree lhs = gimple_assign_lhs(s); + if (!lhs) break; + exprAccessor.update(lhs, Write); + break; + } + default: + gcc_unreachable(); + break; + } +} + +void +GimpleAccesser::_walk_pre(gcall *s) +{ + tree fndecl = gimple_call_fndecl(s); + unsigned n = gimple_call_num_args(s); + for (unsigned i = 0; i < n; i++) + { + const_tree a = gimple_call_arg(s, i); + gcc_assert(a); + exprAccessor.update(a, Read); + } + + const_tree lhs = gimple_call_lhs(s); + if (!lhs) return; + exprAccessor.update(lhs, Write); +} + +void +GimpleAccesser::_walk_pre(greturn *s) +{ + const_tree val = gimple_return_retval(s); + if (!val) return; + exprAccessor.update(val, Read); +} + +void +GimpleAccesser::_walk_pre(gcond *s) +{ + const_tree lhs = gimple_cond_lhs(s); + const_tree rhs = gimple_cond_rhs(s); + gcc_assert(lhs && rhs); + exprAccessor.update(lhs, Read); + exprAccessor.update(rhs, Read); +} diff --git a/gcc/gimple-accesser.hpp b/gcc/gimple-accesser.hpp new file mode 100644 index 00000000000..69bed4839a2 --- /dev/null +++ b/gcc/gimple-accesser.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include "gimple-walker.hpp" +#include "expr-accessor.hpp" + +/* + * GimpleAccesser is intended to walk gimple + * and update a map that will hold information + * on whether a type was casted or not. + */ +class GimpleAccesser : public GimpleWalker +{ +public: + GimpleAccesser() : GimpleWalker() {}; + void print_accesses() { exprAccessor.print_accesses(); }; +private: + ExprAccessor exprAccessor; + virtual void _walk_pre(gcall *s) final; + virtual void _walk_pre(gassign *s) final; + virtual void _walk_pre(greturn *s) final; + virtual void _walk_pre(gcond *s) final; + // Do we need a glabel? I don't think so... + // But we might need a gswitch. +}; diff --git a/gcc/gimple-caster.c b/gcc/gimple-caster.c index 747d60920aa..299bbf6abfb 100644 --- a/gcc/gimple-caster.c +++ b/gcc/gimple-caster.c @@ -22,9 +22,68 @@ GimpleCaster::_walk_pre(gassign *s) const_tree t_lhs = TREE_TYPE(lhs); const_tree t_rhs = TREE_TYPE(rhs); gcc_assert(t_lhs && t_rhs); - const bool is_cast = equality.equal(t_lhs, t_rhs); + const bool is_cast = !equality.equal(t_lhs, t_rhs); reason.is_escaping = is_cast; reason.type_is_casted = is_cast; exprEscaper.update(lhs, reason); exprEscaper.update(rhs, reason); + // TODO: + // I think this will re-do the work... But it might be necessary? + GimpleEscaper::_walk_pre(s); +} + +void +GimpleCaster::_walk_pre(gcall *s) +{ + GimpleEscaper::_walk_pre(s); + + const_tree fn = gimple_call_fndecl(s); + cgraph_node *node = cgraph_node::get(fn); + const bool known_function = GimpleEscaper::filter_known_function(node); + if (known_function) return; + + const_tree f_t = TREE_TYPE(fn); + TypeIncompleteEquality equality; + TypeStringifier stringifier; + + unsigned i = 0; + unsigned n = gimple_call_num_args(s); + for (tree a = TYPE_ARG_TYPES(f_t); NULL_TREE != a; a = TREE_CHAIN(a)) + { + // There seems to be a final VOID_TYPE at the end of the chain + if (i == n) break; + const_tree formal_t = TREE_VALUE(a); + const_tree real = gimple_call_arg(s, i); + const_tree real_t = TREE_TYPE(real); + const bool is_casted = !equality.equal(formal_t, real_t); + const std::string name_r = stringifier.stringify(real_t); + const std::string name_f = stringifier.stringify(formal_t); + log("looking at casted argument %s == %s ? %s\n", name_r.c_str(), name_f.c_str(), is_casted ? "t" : "f"); + Reason arg_reason; + arg_reason.is_escaping = is_casted; + arg_reason.type_is_casted = is_casted; + exprEscaper.update(real, arg_reason); + i++; + } + + /* + unsigned n = gimple_call_num_args(s); + for (unsigned i = 0; i < n; i++) + { + const_tree a = gimple_call_arg(s, i); + gcc_assert(a); + exprEscaper.update(a, reason); + } + */ + + const_tree lhs = gimple_call_lhs(s); + if (!lhs) return; + + const_tree r_t = TREE_TYPE(f_t); + const_tree l_t TREE_TYPE(lhs); + const bool is_casted = !equality.equal(r_t, l_t); + Reason ret_reason; + ret_reason.is_escaping = is_casted; + ret_reason.type_is_casted = is_casted; + exprEscaper.update(lhs, ret_reason); } diff --git a/gcc/gimple-caster.hpp b/gcc/gimple-caster.hpp index 2495d537649..74086606862 100644 --- a/gcc/gimple-caster.hpp +++ b/gcc/gimple-caster.hpp @@ -12,9 +12,8 @@ class GimpleCaster : public GimpleEscaper public: GimpleCaster(ptrset_t &types) : GimpleEscaper(types) {}; private: - // We don't need this from parent... - virtual void _walk_pre(gcall *s) final {}; + virtual void _walk_pre(gcall *s) final; // Find out which structs are casted. // Technically we could find this out on parent - virtual void _walk_pre(gassign *s); + virtual void _walk_pre(gassign *s) final; }; diff --git a/gcc/gimple-escaper.c b/gcc/gimple-escaper.c index ed879123cc1..3f80d6cd868 100644 --- a/gcc/gimple-escaper.c +++ b/gcc/gimple-escaper.c @@ -175,7 +175,7 @@ GimpleEscaper::_walk_pre(gcond *s) void GimpleEscaper::_walk_pre(gcall *s) { - tree fn = gimple_call_fndecl(s); + const_tree fn = gimple_call_fndecl(s); cgraph_node *node = cgraph_node::get(fn); const bool _is_function_escaping = is_function_escaping(node); const bool is_undefined = undefined.find(fn) != undefined.end(); @@ -186,7 +186,6 @@ GimpleEscaper::_walk_pre(gcall *s) // TODO: Consider this... //exprEscaper.update(fn, function_type_reason); - Reason arg_reason; arg_reason.is_escaping = _is_escaping; arg_reason.parameter_is_visible = _is_escaping; diff --git a/gcc/gimple-escaper.hpp b/gcc/gimple-escaper.hpp index b6f77111007..d589a3eec01 100644 --- a/gcc/gimple-escaper.hpp +++ b/gcc/gimple-escaper.hpp @@ -11,7 +11,7 @@ public: ExprEscaper exprEscaper; ptrset_t get_sets() { return exprEscaper.get_sets(); }; void print_reasons() { exprEscaper.print_reasons(); }; -private: +protected: typedef std::set<const_tree> undefset; undefset undefined; void _init(); diff --git a/gcc/gimple-walker.c b/gcc/gimple-walker.c index 9259c0d9438..e61b49f0a98 100644 --- a/gcc/gimple-walker.c +++ b/gcc/gimple-walker.c @@ -60,7 +60,7 @@ GimpleWalker::walk() cgraph_node *node = NULL; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(node) { - // print_function(node); + print_function(node); node->get_untransformed_body(); _walk_cnode(node); } diff --git a/gcc/ipa-prototype.h b/gcc/ipa-prototype.h index 77413d5c218..a75efaa2e48 100644 --- a/gcc/ipa-prototype.h +++ b/gcc/ipa-prototype.h @@ -13,7 +13,7 @@ struct Reason { 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) {}; + Reason() : is_escaping(0), global_is_visible(0), parameter_is_visible(0), return_is_visible(0), type_is_casted(0), type_is_volatile(0), type_is_in_union(0) {}; }; diff --git a/gcc/ipa-type-escape-analysis.c b/gcc/ipa-type-escape-analysis.c index 0f548bf4943..a88602054db 100644 --- a/gcc/ipa-type-escape-analysis.c +++ b/gcc/ipa-type-escape-analysis.c @@ -25,6 +25,7 @@ #include "gimple-collector.hpp" #include "gimple-escaper.hpp" #include "gimple-caster.hpp" +#include "gimple-accesser.hpp" static unsigned int iphw_execute(); @@ -104,8 +105,12 @@ collect_types() GimpleEscaper gimpleEscaper(types); gimpleEscaper.walk(); if (flag_print_escape_analysis) gimpleEscaper.print_reasons(); - types = gimpleEscaper.get_sets(); + ptrset_t escaping = gimpleEscaper.get_sets(); GimpleCaster caster(types); caster.walk(); if (flag_print_cast_analysis) caster.print_reasons(); + ptrset_t casting = caster.get_sets(); + GimpleAccesser accesser; + accesser.walk(); + if (flag_print_access_analysis) accesser.print_accesses(); } diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c index 88f96ea3be4..390f73a6cc3 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-00-simple-read-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */ +/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */ #include <stdio.h> @@ -14,6 +14,5 @@ main () printf("%d\n", astruct.a); } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 2" "hello-world" } } */ +// This means a read. +/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c index 6e7b3236294..d809ed31df8 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-01-simple-write-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */ +/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */ #include <stdio.h> @@ -14,6 +14,5 @@ main () astruct.a = 3; } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 1" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 2" "hello-world" } } */ +// This means that this is only a write and not a read. +/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0003" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c index 1b6755565ff..59f7707e5af 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-02-pointer-read-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */ +/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */ #include <stdio.h> @@ -14,6 +14,5 @@ main () printf("%d\n", astruct->a); } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 2" "hello-world" } } */ +// So, even if we have a pointer COMPONENT_REF counter still works... +/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c index 68e2f40a12a..17ad02529ee 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-03-pointer-write-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */ +/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */ #include <stdio.h> @@ -14,6 +14,5 @@ main () astruct->a = 3; } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 1" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a write 2" "hello-world" } } */ +// This says that only writes are happening even if astruct is a pointer +/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0003" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c index 0dd152a2783..29f0fcfda4d 100644 --- a/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c +++ b/gcc/testsuite/gcc.dg/ipa/ipa-access-counter-04-gimple-cond-0.c @@ -1,5 +1,5 @@ /* { dg-do link } */ -/* { dg-options "-flto -fipa-hello-world -fdump-ipa-hello-world" } */ +/* { dg-options "-fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-access-analysis " } */ #include <stdio.h> @@ -15,5 +15,5 @@ main () } } -/* { dg-final { scan-wpa-ipa-dump "collected,astruct_s" "hello-world" } } */ -/* { dg-final { scan-wpa-ipa-dump "astruct_s.a read 1" "hello-world" } } */ +// This says that astruct_s.a is read in a conditional +/* { dg-final { scan-wpa-ipa-dump "astruct_s.a = 0x0001" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c new file mode 100644 index 00000000000..623a8c0af00 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-16-parameter-cast-0.c @@ -0,0 +1,20 @@ +/* { dg-do link } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-cast-analysis -Wno-incompatible-pointer-types" } */ + +#include <stddef.h> +#include <stdio.h> + +struct astruct_s { _Bool a; _Bool b; _Bool c; }; +struct bstruct_s { _Bool a; _Bool b; _Bool c; }; +void foo(struct bstruct_s *s) { }; + +int main(int argc, char** argv) +{ + struct astruct_s astruct; + foo(&astruct); +} + +// This says that astruct_s is casted +/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ +// This says that the pointer is casted +/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;.. reason: g=0 p=0 r=0 c=1 v=0 u=0" "type-escape-analysis" } } */ diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c b/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c new file mode 100644 index 00000000000..94e96701f96 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-ea-17-malloc-0.c @@ -0,0 +1,17 @@ +/* { dg-do link } */ +/* { dg-options "-flto -fipa-type-escape-analysis -fdump-ipa-type-escape-analysis -fprint-cast-analysis -Wno-incompatible-pointer-types" } */ + +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +struct astruct_s { _Bool a; _Bool b; _Bool c; }; + +int main(int argc, char** argv) +{ + struct astruct_s *a = malloc(sizeof(struct astruct_s)); +} + +// This says that astruct_s is not casted +/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;. reason: g=0 p=0 r=0 c=0 v=0 u=0" "type-escape-analysis" } } */ +/* { dg-final { scan-wpa-ipa-dump " record astruct_s .boolean_type a;boolean_type b;boolean_type c;.. reason: g=0 p=0 r=0 c=0 v=0 u=0" "type-escape-analysis" } } */ diff --git a/gcc/type-incomplete-equality.c b/gcc/type-incomplete-equality.c index 9ce7eed1413..bf9047a98c7 100644 --- a/gcc/type-incomplete-equality.c +++ b/gcc/type-incomplete-equality.c @@ -44,9 +44,9 @@ TypeIncompleteEquality::_equal(const_tree l, const_tree r) if (!valid_inputs) return l == r; // if any of these are incomplete, then we can only compare using identifiers... - const bool incomplete_l = is_incomplete(l); - const bool incomplete_r = is_incomplete(r); - const bool can_compare_structurally = incomplete_l && incomplete_r; + const bool complete_l = is_complete(l); + const bool complete_r = is_complete(r); + const bool can_compare_structurally = complete_l && complete_r; if (can_compare_structurally) return TypeStructuralEquality::_equal(l, r); const std::string n_l = TypeStringifier::get_type_identifier(l); diff --git a/gcc/type-walker.c b/gcc/type-walker.c index 54d547d3fd6..b79daef043d 100644 --- a/gcc/type-walker.c +++ b/gcc/type-walker.c @@ -260,7 +260,7 @@ TypeWalker::_walk_args(const_tree t) { 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); + const_tree arg_node_type = TREE_VALUE(arg_node); gcc_assert(arg_node_type); walk_arg(arg_node_type); } |