This patch to the Go frontend by Cherry Zhang avoids a copy for a
string([]byte) conversion used as a map key.  If a string([]byte)
conversion is used immediately as a key for a map read, we don't need
to copy the backing store of the byte slice, as mapaccess does not
keep a reference to it.

The gc compiler does more than this: it also avoids the copy if the
map key is a composite literal that contains the conversion as a
field, like, T{ ... { ..., string(b), ... }, ... }. For now, we just
optimize the simple case, which is probably most common.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

2019-05-09  Cherry Zhang  <cherr...@google.com>

* go.dg/mapstring.go: New test.
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 271021)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-9c8581187b1c1a30036263728370f31cb846a274
+3dbf51c01c5d0acbf9ae47f77166fa9935881749
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 271021)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -12158,6 +12158,13 @@ Map_index_expression::do_flatten(Gogo* g
       return Expression::make_error(loc);
     }
 
+  // Avoid copy for string([]byte) conversions used in map keys.
+  // mapaccess doesn't keep the reference, so this is safe.
+  Type_conversion_expression* ce = this->index_->conversion_expression();
+  if (ce != NULL && ce->type()->is_string_type()
+      && ce->expr()->type()->is_slice_type())
+    ce->set_no_copy(true);
+
   if (!Type::are_identical(mt->key_type(), this->index_->type(),
                           Type::COMPARE_ERRORS | Type::COMPARE_TAGS,
                           NULL))
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc     (revision 270993)
+++ gcc/go/gofrontend/statements.cc     (working copy)
@@ -1307,6 +1307,13 @@ Tuple_map_assignment_statement::do_lower
   if (map_type == NULL)
     return Statement::make_error_statement(loc);
 
+  // Avoid copy for string([]byte) conversions used in map keys.
+  // mapaccess doesn't keep the reference, so this is safe.
+  Type_conversion_expression* ce = map_index->index()->conversion_expression();
+  if (ce != NULL && ce->type()->is_string_type()
+      && ce->expr()->type()->is_slice_type())
+    ce->set_no_copy(true);
+
   Block* b = new Block(enclosing, loc);
 
   // Move out any subexpressions to make sure that functions are
Index: gcc/testsuite/go.dg/mapstring.go
===================================================================
--- gcc/testsuite/go.dg/mapstring.go    (nonexistent)
+++ gcc/testsuite/go.dg/mapstring.go    (working copy)
@@ -0,0 +1,11 @@
+// { dg-do compile }
+// { dg-options "-fgo-debug-optimization" }
+
+package p
+
+func F(m map[string]int, a, b []byte) int {
+       x := m[string(a)]     // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+       y, ok := m[string(b)] // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+       _ = ok
+       return x + y
+}

Reply via email to