]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: optimize string concatenations
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 19 Jun 2019 15:13:53 +0000 (15:13 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 19 Jun 2019 15:13:53 +0000 (15:13 +0000)
    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.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/182539

From-SVN: r272476

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/runtime.def
libgo/go/runtime/string.go

index e62501f4dfb4d2f243d37a83ee58aac3b1888a22..3b0cff742ebeac6581cfd6036382a927faf1aede 100644 (file)
@@ -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 766864a535dfd6ae76fe4bc4aff556ebb6edda16..864b62df3b1fd3a438be31e6226c56cdffa4a300 100644 (file)
@@ -7442,7 +7442,7 @@ String_concat_expression::do_check_types(Gogo*)
 
 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(Gogo*, Named_object*,
     }
   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 34c86e8aafcdd51a9b236eaac2e0688089ab0d64..c81ab79cc0f8a35601900bd6dcaf8315c22a7bc0 100644 (file)
@@ -36,16 +36,8 @@ DEF_GO_RUNTIME(DECODERUNE, "runtime.decoderune", P2(STRING, INT),
               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 eac94bf6a8a90993ee946674a69ca31165977ad3..9bcfc9961c824129dd1d148887f8ac0649c08bfc 100644 (file)
@@ -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 []string) string {
        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) {