This patch to the Go frontend and libgo by Cherry Zhang optimizes
string concatenations.  runtime.concatstring{2,3,4,5} are just
wrappers of concatstrings.  These wrappers don't provide any benefit,
at least in the C calling convention we use, where passing arrays by
value isn't an efficient thing.  Change it to always use
concatstrings.

Also, the cap field of the slice passed to concatstrings is not
necessary.  So change it to pass a pointer and a length directly,
which is more efficient than passing a slice header by value.

Bootstrapped and tested on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 272468)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-0e4aa31b26a20b6a6a2ca102b85ba8c8b8cdf876
+7822080a6e226b1e5872e2fcefac30f666f4cc1e
 
 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 272468)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -7442,7 +7442,7 @@ String_concat_expression::do_check_types
 
 Expression*
 String_concat_expression::do_flatten(Gogo*, Named_object*,
-                                    Statement_inserter*)
+                                    Statement_inserter* inserter)
 {
   if (this->is_error_expression())
     return this;
@@ -7497,56 +7497,22 @@ String_concat_expression::do_flatten(Gog
     }
   if (buf == NULL)
     buf = Expression::make_nil(loc);
-  Expression* call;
-  switch (this->exprs_->size())
-    {
-    case 0: case 1:
-      go_unreachable();
-
-    case 2: case 3: case 4: case 5:
-      {
-       Expression* len = Expression::make_integer_ul(this->exprs_->size(),
-                                                     NULL, loc);
-       Array_type* arg_type = Type::make_array_type(type, len);
-       arg_type->set_is_array_incomparable();
-       Expression* arg =
-         Expression::make_array_composite_literal(arg_type, this->exprs_,
-                                                  loc);
-       Runtime::Function code;
-       switch (this->exprs_->size())
-         {
-         default:
-           go_unreachable();
-         case 2:
-           code = Runtime::CONCATSTRING2;
-           break;
-         case 3:
-           code = Runtime::CONCATSTRING3;
-           break;
-         case 4:
-           code = Runtime::CONCATSTRING4;
-           break;
-         case 5:
-           code = Runtime::CONCATSTRING5;
-           break;
-         }
-       call = Runtime::make_call(code, loc, 2, buf, arg);
-      }
-      break;
-
-    default:
-      {
-       Type* arg_type = Type::make_array_type(type, NULL);
-       Slice_construction_expression* sce =
-         Expression::make_slice_composite_literal(arg_type, this->exprs_,
-                                                  loc);
-       sce->set_storage_does_not_escape();
-       call = Runtime::make_call(Runtime::CONCATSTRINGS, loc, 2, buf,
-                                 sce);
-      }
-      break;
-    }
-
+  go_assert(this->exprs_->size() > 1);
+  Expression* len =
+    Expression::make_integer_ul(this->exprs_->size(), NULL, loc);
+  Array_type* array_type = Type::make_array_type(type, len);
+  array_type->set_is_array_incomparable();
+  Expression* array =
+    Expression::make_array_composite_literal(array_type, this->exprs_,
+                                             loc);
+  Temporary_statement* ts =
+    Statement::make_temporary(array_type, array, loc);
+  inserter->insert(ts);
+  Expression* ref = Expression::make_temporary_reference(ts, loc);
+  ref = Expression::make_unary(OPERATOR_AND, ref, loc);
+       Expression* call =
+    Runtime::make_call(Runtime::CONCATSTRINGS, loc, 3, buf,
+                       ref, len->copy());
   return Expression::make_cast(type, call, loc);
 }
 
Index: gcc/go/gofrontend/runtime.def
===================================================================
--- gcc/go/gofrontend/runtime.def       (revision 272127)
+++ gcc/go/gofrontend/runtime.def       (working copy)
@@ -36,16 +36,8 @@ DEF_GO_RUNTIME(DECODERUNE, "runtime.deco
               R2(RUNE, INT))
 
 // Concatenate strings.
-DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings", P2(POINTER, SLICE),
-              R1(STRING))
-DEF_GO_RUNTIME(CONCATSTRING2, "runtime.concatstring2",
-              P2(POINTER, ARRAY2STRING), R1(STRING))
-DEF_GO_RUNTIME(CONCATSTRING3, "runtime.concatstring3",
-              P2(POINTER, ARRAY3STRING), R1(STRING))
-DEF_GO_RUNTIME(CONCATSTRING4, "runtime.concatstring4",
-              P2(POINTER, ARRAY4STRING), R1(STRING))
-DEF_GO_RUNTIME(CONCATSTRING5, "runtime.concatstring5",
-              P2(POINTER, ARRAY5STRING), R1(STRING))
+DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings",
+               P3(POINTER, POINTER, INT), R1(STRING))
 
 // Compare two strings for equality.
 DEF_GO_RUNTIME(EQSTRING, "runtime.eqstring", P2(STRING, STRING), R1(BOOL))
Index: libgo/go/runtime/string.go
===================================================================
--- libgo/go/runtime/string.go  (revision 272127)
+++ libgo/go/runtime/string.go  (working copy)
@@ -13,10 +13,6 @@ import (
 // themselves, so that the compiler will export them.
 //
 //go:linkname concatstrings runtime.concatstrings
-//go:linkname concatstring2 runtime.concatstring2
-//go:linkname concatstring3 runtime.concatstring3
-//go:linkname concatstring4 runtime.concatstring4
-//go:linkname concatstring5 runtime.concatstring5
 //go:linkname slicebytetostring runtime.slicebytetostring
 //go:linkname slicebytetostringtmp runtime.slicebytetostringtmp
 //go:linkname stringtoslicebyte runtime.stringtoslicebyte
@@ -38,7 +34,9 @@ type tmpBuf [tmpStringBufSize]byte
 // If buf != nil, the compiler has determined that the result does not
 // escape the calling function, so the string data can be stored in buf
 // if small enough.
-func concatstrings(buf *tmpBuf, a []string) string {
+func concatstrings(buf *tmpBuf, p *string, n int) string {
+       var a []string
+       *(*slice)(unsafe.Pointer(&a)) = slice{unsafe.Pointer(p), n, n}
        // idx := 0
        l := 0
        count := 0
@@ -73,22 +71,6 @@ func concatstrings(buf *tmpBuf, a []stri
        return s
 }
 
-func concatstring2(buf *tmpBuf, a [2]string) string {
-       return concatstrings(buf, a[:])
-}
-
-func concatstring3(buf *tmpBuf, a [3]string) string {
-       return concatstrings(buf, a[:])
-}
-
-func concatstring4(buf *tmpBuf, a [4]string) string {
-       return concatstrings(buf, a[:])
-}
-
-func concatstring5(buf *tmpBuf, a [5]string) string {
-       return concatstrings(buf, a[:])
-}
-
 // Buf is a fixed-size buffer for the result,
 // it is not nil if the result does not escape.
 func slicebytetostring(buf *tmpBuf, b []byte) (str string) {

Reply via email to