compiler: add escape analysis debug hash
authorCherry Zhang <cherryyz@google.com>
Tue, 9 Jan 2018 20:42:08 +0000 (20:42 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 9 Jan 2018 20:42:08 +0000 (20:42 +0000)
    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

gcc/go/ChangeLog
gcc/go/gccgo.texi
gcc/go/go-c.h
gcc/go/go-lang.c
gcc/go/gofrontend/escape.cc
gcc/go/gofrontend/go.cc
gcc/go/gofrontend/gogo.h
gcc/go/lang.opt

index 17b6e3e0115e0f06ec9afe94e38658333609b6a7..4cd75f319ddf3af71fc2b00c616043e669b57242 100644 (file)
@@ -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
index f54cc1030035464b59a7d038ec9b45a2e9141b7d..48e69d42ddfdaeeb176c574c35c1cce90e9f2a58 100644 (file)
@@ -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.
index 5b3b459183bbc02adf59bfc5e1d0f3a4e9cea2da..139c233aab4e5f3299cc491e3b43a04d290fda6a 100644 (file)
@@ -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;
 };
 
index e47036f608147d3e0c9ce2da3419fc27ec6b71e7..b5d8224a54e27c2b07c8c99f31a103f85d08e46b 100644 (file)
@@ -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();
index 50878ff9bfc1b9dd3fe3ec3207e894f9d9d5d503..5ba0b630b3ea1e55157c1db1635bbb3e2510fb33 100644 (file)
@@ -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.
index a2b8cecb3fe9eab2b54c99ea74249c0d5098dbe3..62a8a65609c254660ff0535d186e2bc7eb5a1da6 100644 (file)
@@ -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);
 }
 
index 58d873230ea6bb0a852a7d0ab7a2dcaaa3478403..ed044d413cfb7f8926731f4d17b1d7e74a6400df 100644 (file)
@@ -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.
index 3cc8f3311b2f2e48ad35539f1b5a12d34917acdc..6dbb54298d7e5f03f6fff791797056a8e2e3eee2 100644 (file)
@@ -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