compiler: avoid copy for string([]byte) conversion used in map keys

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.

A test could be added in the GCC testsuite:

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
+}

Change-Id: Iccb0dafa2780dfb398d2db946e86b2634984527c
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/176197
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/go/expressions.cc b/go/expressions.cc
index 2c1286c..929571b 100644
--- a/go/expressions.cc
+++ b/go/expressions.cc
@@ -12158,6 +12158,13 @@
       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))
diff --git a/go/statements.cc b/go/statements.cc
index 2e2d039..67ab184 100644
--- a/go/statements.cc
+++ b/go/statements.cc
@@ -1307,6 +1307,13 @@
   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