aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2018-01-09 20:42:08 +0000
committerIan Lance Taylor <iant@golang.org>2018-01-09 20:42:08 +0000
commitfdf9876c9acf17527dad7fd852a2a1c2568cc3f4 (patch)
tree970992e35310a150831f81a3e2b91149653faa35
parentd2c04370a6d781a2af10bdf1da4e7940ddcc5090 (diff)
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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@256393 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/ChangeLog8
-rw-r--r--gcc/go/gccgo.texi7
-rw-r--r--gcc/go/go-c.h1
-rw-r--r--gcc/go/go-lang.c1
-rw-r--r--gcc/go/gofrontend/escape.cc69
-rw-r--r--gcc/go/gofrontend/go.cc2
-rw-r--r--gcc/go/gofrontend/gogo.h14
-rw-r--r--gcc/go/lang.opt4
8 files changed, 106 insertions, 0 deletions
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 <cherryyz@google.com>
+
+ * 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 <iant@golang.org>
* 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<Analysis_set>::iterator p = this->analysis_sets_.begin();
p != this->analysis_sets_.end();
++p)
{
std::vector<Named_object*> stack = p->first;
+
+ if (!this->debug_escape_hash().empty())
+ {
+ bool match = false;
+ for (std::vector<Named_object*>::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<Named_object*>::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<Named_object*>::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=<string> Hash value to debug escape analysis.
+
o
Go Joined Separate
; Documented in common.opt