From: Cherry Zhang Date: Tue, 9 Jan 2018 20:42:08 +0000 (+0000) Subject: compiler: add escape analysis debug hash X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=594d0e51b75c83cec9be74a304217e3f0c49da6c;p=gcc.git compiler: add escape analysis debug hash Add a flag -fgo-debug-escape-hash for debugging escape analysis. It takes a binary string, optionally led by a "-", as argument. When specified, the escape analysis runs only on functions whose name is hashed to a value with matching suffix. The "-" sign negates the match, i.e. the analysis runs only on functions with non-matching hash. Reviewed-on: https://go-review.googlesource.com/83878 * lang.opt (fgo-debug-escape-hash): New option. * go-c.h (struct go_create_gogo_args): Add debug_escape_hash field. * go-lang.c (go_langhook_init): Set debug_escape_hash field. * gccgo.texi (Invoking gccgo): Document -fgo-debug-escape-hash. From-SVN: r256393 --- diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 17b6e3e0115..4cd75f319dd 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,11 @@ +2018-01-09 Cherry Zhang + + * lang.opt (fgo-debug-escape-hash): New option. + * go-c.h (struct go_create_gogo_args): Add debug_escape_hash + field. + * go-lang.c (go_langhook_init): Set debug_escape_hash field. + * gccgo.texi (Invoking gccgo): Document -fgo-debug-escape-hash. + 2018-01-05 Ian Lance Taylor * go-gcc.cc (Gcc_backend::Gcc_backend): Correct diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi index f54cc103003..48e69d42ddf 100644 --- a/gcc/go/gccgo.texi +++ b/gcc/go/gccgo.texi @@ -239,6 +239,13 @@ heap when possible. In the future this may be the default. Output escape analysis debugging information. Larger values of @var{n} generate more information. +@item -fgo-debug-escape-hash=@var{n} +@cindex @option{-fgo-debug-escape-hash} +A hash value to debug escape analysis. @var{n} is a binary string. +This runs escape analysis only on functions whose names hash to values +that match the given suffix @var{n}. This can be used to binary +search across functions to uncover escape analysis bugs. + @item -fgo-c-header=@var{file} @cindex @option{-fgo-c-header} Write top-level named Go struct definitions to @var{file} as C code. diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index 5b3b459183b..139c233aab4 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -47,6 +47,7 @@ struct go_create_gogo_args bool check_divide_overflow; bool compiling_runtime; int debug_escape_level; + const char* debug_escape_hash; int64_t nil_check_size_threshold; }; diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c index e47036f6081..b5d8224a54e 100644 --- a/gcc/go/go-lang.c +++ b/gcc/go/go-lang.c @@ -116,6 +116,7 @@ go_langhook_init (void) args.check_divide_overflow = go_check_divide_overflow; args.compiling_runtime = go_compiling_runtime; args.debug_escape_level = go_debug_escape_level; + args.debug_escape_hash = go_debug_escape_hash; args.nil_check_size_threshold = TARGET_AIX ? -1 : 4096; args.linemap = go_get_linemap(); args.backend = go_get_backend(); diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index 50878ff9bfc..5ba0b630b3e 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -19,6 +19,7 @@ #include "ast-dump.h" #include "go-optimize.h" #include "go-diagnostics.h" +#include "go-sha1.h" // class Node. @@ -821,6 +822,39 @@ Escape_note::parse_tag(std::string* tag) Go_optimize optimize_allocation_flag("allocs"); +// A helper function to compute whether a function name has a +// matching hash value. + +static bool +escape_hash_match(std::string suffix, std::string name) +{ + if (suffix.empty()) + return true; + if (suffix.at(0) == '-') + return !escape_hash_match(suffix.substr(1), name); + + const char* p = name.c_str(); + Go_sha1_helper* sha1_helper = go_create_sha1_helper(); + sha1_helper->process_bytes(p, strlen(p)); + std::string s = sha1_helper->finish(); + delete sha1_helper; + + int j = suffix.size() - 1; + for (int i = s.size() - 1; i >= 0; i--) + { + char c = s.at(i); + for (int k = 0; k < 8; k++, j--, c>>=1) + { + if (j < 0) + return true; + char bit = suffix.at(j) - '0'; + if ((c&1) != bit) + return false; + } + } + return false; +} + // Analyze the program flow for escape information. void @@ -839,11 +873,46 @@ Gogo::analyze_escape() // information in this package. this->discover_analysis_sets(); + if (!this->debug_escape_hash().empty()) + std::cerr << "debug-escape-hash " << this->debug_escape_hash() << "\n"; + for (std::vector::iterator p = this->analysis_sets_.begin(); p != this->analysis_sets_.end(); ++p) { std::vector stack = p->first; + + if (!this->debug_escape_hash().empty()) + { + bool match = false; + for (std::vector::const_iterator fn = stack.begin(); + fn != stack.end(); + ++fn) + match = match || escape_hash_match(this->debug_escape_hash(), (*fn)->message_name()); + if (!match) + { + // Escape analysis won't run on these functions, but still + // need to tag them, so the caller knows. + for (std::vector::iterator fn = stack.begin(); + fn != stack.end(); + ++fn) + if ((*fn)->is_function()) + { + Function_type* fntype = (*fn)->func_value()->type(); + fntype->set_is_tagged(); + + std::cerr << "debug-escape-hash disables " << debug_function_name(*fn) << "\n"; + } + + continue; + } + for (std::vector::const_iterator fn = stack.begin(); + fn != stack.end(); + ++fn) + if ((*fn)->is_function()) + std::cerr << "debug-escape-hash triggers " << debug_function_name(*fn) << "\n"; + } + Escape_context* context = new Escape_context(this, p->second); // Analyze the flow of each function; build the connection graph. diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index a2b8cecb3fe..62a8a65609c 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -41,6 +41,8 @@ go_create_gogo(const struct go_create_gogo_args* args) if (args->c_header != NULL) ::gogo->set_c_header(args->c_header); ::gogo->set_debug_escape_level(args->debug_escape_level); + if (args->debug_escape_hash != NULL) + ::gogo->set_debug_escape_hash(args->debug_escape_hash); ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold); } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 58d873230ea..ed044d413cf 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -318,6 +318,16 @@ class Gogo set_debug_escape_level(int level) { this->debug_escape_level_ = level; } + // Return the hash for debug escape analysis. + std::string + debug_escape_hash() const + { return this->debug_escape_hash_; } + + // Set the hash value for debug escape analysis. + void + set_debug_escape_hash(const std::string& s) + { this->debug_escape_hash_ = s; } + // Return the size threshold used to determine whether to issue // a nil-check for a given pointer dereference. A threshold of -1 // implies that all potentially faulting dereference ops should @@ -1035,6 +1045,10 @@ class Gogo // The level of escape analysis debug information to emit, from the // -fgo-debug-escape option. int debug_escape_level_; + // A hash value for debug escape analysis, from the + // -fgo-debug-escape-hash option. The analysis is run only on + // functions with names that hash to the matching value. + std::string debug_escape_hash_; // Nil-check size threshhold. int64_t nil_check_size_threshold_; // A list of types to verify. diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt index 3cc8f3311b2..6dbb54298d7 100644 --- a/gcc/go/lang.opt +++ b/gcc/go/lang.opt @@ -81,6 +81,10 @@ fgo-debug-escape Go Joined UInteger Var(go_debug_escape_level) Init(0) Emit debugging information related to the escape analysis pass when run with -fgo-optimize-allocs. +fgo-debug-escape-hash= +Go Joined RejectNegative Var(go_debug_escape_hash) Init(0) +-fgo-debug-escape-hash= Hash value to debug escape analysis. + o Go Joined Separate ; Documented in common.opt