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.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/176197

	* go.dg/mapstring.go: New test.

From-SVN: r271044
This commit is contained in:
Cherry Zhang 2019-05-09 21:24:56 +00:00 committed by Ian Lance Taylor
parent 08e113f4ae
commit 8743680541
5 changed files with 30 additions and 1 deletions

View File

@ -1,4 +1,4 @@
9c8581187b1c1a30036263728370f31cb846a274 3dbf51c01c5d0acbf9ae47f77166fa9935881749
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.

View File

@ -12158,6 +12158,13 @@ Map_index_expression::do_flatten(Gogo* gogo, Named_object*,
return Expression::make_error(loc); 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(), if (!Type::are_identical(mt->key_type(), this->index_->type(),
Type::COMPARE_ERRORS | Type::COMPARE_TAGS, Type::COMPARE_ERRORS | Type::COMPARE_TAGS,
NULL)) NULL))

View File

@ -1307,6 +1307,13 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
if (map_type == NULL) if (map_type == NULL)
return Statement::make_error_statement(loc); 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); Block* b = new Block(enclosing, loc);
// Move out any subexpressions to make sure that functions are // Move out any subexpressions to make sure that functions are

View File

@ -1,3 +1,7 @@
2019-05-09 Cherry Zhang <cherryyz@google.com>
* go.dg/mapstring.go: New test.
2019-05-09 Richard Earnshaw <rearnsha@arm.com> 2019-05-09 Richard Earnshaw <rearnsha@arm.com>
PR target/90405 PR target/90405

View File

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