This patch to the Go frontend discards global sink variables with
static initializers.  This is specifically for the test issue23781.go,
which builds a large static array.  The code does compile and work
without this change, but it takes a long time and generates a large
object file.  Discarding the unnecessary static initializer makes this
test much faster.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
8a5b8fc719f5c5bd6bd732d95646193238343f39
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 1bada25300d..a596b241a4e 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-8b913a1865e36d4bd105f29aa0b12264a4e03515
+85c390ec75c6c3f3fbfe08f6dac58585588c6211
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index e31a038dbd3..fbf8935bb06 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1558,6 +1558,17 @@ Gogo::write_globals()
          || (no->is_const() && no->const_value()->is_sink()))
         continue;
 
+      // Skip global sink variables with static initializers.  With
+      // non-static initializers we have to evaluate for side effects,
+      // and we wind up initializing a dummy variable.  That is not
+      // ideal but it works and it's a rare case.
+      if (no->is_variable()
+         && no->var_value()->is_global_sink()
+         && !no->var_value()->has_pre_init()
+         && (no->var_value()->init() == NULL
+             || no->var_value()->init()->is_static_initializer()))
+       continue;
+
       // There is nothing useful we can output for constants which
       // have ideal or non-integral type.
       if (no->is_const())
@@ -7447,7 +7458,7 @@ Variable::Variable(Type* type, Expression* init, bool 
is_global,
   : type_(type), init_(init), preinit_(NULL), location_(location),
     backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
     is_closure_(false), is_receiver_(is_receiver),
-    is_varargs_parameter_(false), is_used_(false),
+    is_varargs_parameter_(false), is_global_sink_(false), is_used_(false),
     is_address_taken_(false), is_non_escaping_address_taken_(false),
     seen_(false), init_is_lowered_(false), init_is_flattened_(false),
     type_from_init_tuple_(false), type_from_range_index_(false),
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 49d7bd9b98a..bdb3166006d 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -2113,6 +2113,20 @@ class Variable
   is_varargs_parameter() const
   { return this->is_varargs_parameter_; }
 
+  // Return whether this is a global sink variable, created only to
+  // run an initializer.
+  bool
+  is_global_sink() const
+  { return this->is_global_sink_; }
+
+  // Record that this is a global sink variable.
+  void
+  set_is_global_sink()
+  {
+    go_assert(this->is_global_);
+    this->is_global_sink_ = true;
+  }
+
   // Whether this variable's address is taken.
   bool
   is_address_taken() const
@@ -2340,6 +2354,9 @@ class Variable
   bool is_receiver_ : 1;
   // Whether this is the varargs parameter of a function.
   bool is_varargs_parameter_ : 1;
+  // Whether this is a global sink variable created to run an
+  // initializer.
+  bool is_global_sink_ : 1;
   // Whether this variable is ever referenced.
   bool is_used_ : 1;
   // Whether something takes the address of this variable.  For a
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index a4740cfad0e..3b2e5a7aa86 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -2075,6 +2075,7 @@ Parse::create_dummy_global(Type* type, Expression* init,
   if (type == NULL && init == NULL)
     type = Type::lookup_bool_type();
   Variable* var = new Variable(type, init, true, false, false, location);
+  var->set_is_global_sink();
   static int count;
   char buf[30];
   snprintf(buf, sizeof buf, "_.%d", count);

Reply via email to