This patch to the Go frontend by Cherry Zhang avoids a copy for a string([]byte) conversion used in string concatenation. If a string([]byte) conversion is used immediately in a string concatenation, we don't need to copy the backing store of the byte slice, as the runtime function doesn't hold any reference to it. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian 2019-06-18 Cherry Zhang <cherr...@google.com> * go.dg/concatstring.go: New test.
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 272133) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -b1ae35965cadac235d7d218e689944286cccdd90 +62d1b667f3e85f72a186b04aad36d701160a4611 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 272133) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -7408,6 +7408,26 @@ String_concat_expression::do_flatten(Gog return this; Location loc = this->location(); Type* type = this->type(); + + // Mark string([]byte) operands to reuse the backing store. + // runtime.concatstrings does not keep the reference. + // + // Note: in the gc runtime, if all but one inputs are empty, + // concatstrings returns the only nonempty input without copy. + // So it is not safe to reuse the backing store if it is a + // string([]byte) conversion. So the gc compiler does the + // no-copy optimization only when there is at least one + // constant nonempty input. Currently the gccgo runtime + // doesn't do this, so we don't do the check. + for (Expression_list::iterator p = this->exprs_->begin(); + p != this->exprs_->end(); + ++p) + { + Type_conversion_expression* tce = (*p)->conversion_expression(); + if (tce != NULL) + tce->set_no_copy(true); + } + Expression* nil_arg = Expression::make_nil(loc); Expression* call; switch (this->exprs_->size()) Index: gcc/testsuite/go.dg/concatstring.go =================================================================== --- gcc/testsuite/go.dg/concatstring.go (nonexistent) +++ gcc/testsuite/go.dg/concatstring.go (working copy) @@ -0,0 +1,8 @@ +// { dg-do compile } +// { dg-options "-fgo-debug-optimization" } + +package p + +func F(b []byte, x string) string { + return "hello " + string(b) + x // { dg-error "no copy string\\(\\\[\\\]byte\\)" } +}