]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
compiler: open code string slice expressions
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 21 Jun 2019 14:14:58 +0000 (14:14 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 21 Jun 2019 14:14:58 +0000 (14:14 +0000)
    Currently a string slice expression is implemented with a runtime
    call __go_string_slice. Change it to open code it, which is more
    efficient, and allows the backend to further optimize it.

    Also omit the write barrier for length-only update (i.e.
    s = s[:n]).

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

From-SVN: r272549

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/runtime.def
gcc/go/gofrontend/statements.cc
libgo/Makefile.am
libgo/Makefile.in
libgo/runtime/go-strslice.c [deleted file]

index 3b0cff742ebeac6581cfd6036382a927faf1aede..10104a78197c45e6d710291ed3cab24bf258fcbc 100644 (file)
@@ -1,4 +1,4 @@
-7822080a6e226b1e5872e2fcefac30f666f4cc1e
+62e3a8cc0a862b0abd3d0b1ef6cf4b228992a137
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 864b62df3b1fd3a438be31e6226c56cdffa4a300..a764d06509c2fecd5e68577e4e1d2793ff27a67c 100644 (file)
@@ -13082,11 +13082,6 @@ Bexpression*
 String_index_expression::do_get_backend(Translate_context* context)
 {
   Location loc = this->location();
-  Expression* string_arg = this->string_;
-  if (this->string_->type()->points_to() != NULL)
-    string_arg = Expression::make_dereference(this->string_,
-                                              NIL_CHECK_NOT_NEEDED, loc);
-
   Expression* bad_index = Expression::check_bounds(this->start_, loc);
 
   int code = (this->end_ == NULL
@@ -13110,23 +13105,27 @@ String_index_expression::do_get_backend(Translate_context* context)
       return context->backend()->error_expression();
     }
 
+  go_assert(this->string_->is_variable());
+  go_assert(this->start_->is_variable());
+
   Expression* start = Expression::make_cast(int_type, this->start_, loc);
   Bfunction* bfn = context->function()->func_value()->get_decl();
 
+  Expression* length =
+    Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
+  Expression* bytes =
+    Expression::make_string_info(this->string_, STRING_INFO_DATA, loc);
+
+  Bexpression* bstart = start->get_backend(context);
+  Bexpression* ptr = bytes->get_backend(context);
+
   if (this->end_ == NULL)
     {
-      Expression* length =
-          Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
-
       Expression* start_too_large =
           Expression::make_binary(OPERATOR_GE, start, length, loc);
       bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
                                           bad_index, loc);
-      Expression* bytes =
-       Expression::make_string_info(this->string_, STRING_INFO_DATA, loc);
 
-      Bexpression* bstart = start->get_backend(context);
-      Bexpression* ptr = bytes->get_backend(context);
       ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
       Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo);
       Bexpression* index =
@@ -13141,20 +13140,53 @@ String_index_expression::do_get_backend(Translate_context* context)
 
   Expression* end = NULL;
   if (this->end_->is_nil_expression())
-    end = Expression::make_integer_sl(-1, int_type, loc);
+    end = length;
   else
     {
+      go_assert(this->end_->is_variable());
       Expression* bounds_check = Expression::check_bounds(this->end_, loc);
       bad_index =
           Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
       end = Expression::make_cast(int_type, this->end_, loc);
+
+      Expression* end_too_large =
+        Expression::make_binary(OPERATOR_GT, end, length, loc);
+      bad_index = Expression::make_binary(OPERATOR_OROR, end_too_large,
+                                          bad_index, loc);
     }
+  Expression* start_too_large =
+    Expression::make_binary(OPERATOR_GT, start->copy(), end->copy(), loc);
+  bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
+                                      bad_index, loc);
+
+  end = end->copy();
+  Bexpression* bend = end->get_backend(context);
+  Bexpression* new_length =
+    gogo->backend()->binary_expression(OPERATOR_MINUS, bend, bstart, loc);
 
-  Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3,
-                                            string_arg, start, end);
-  Bexpression* bstrslice = strslice->get_backend(context);
+  // If the new length is zero, don't change pointer.  Otherwise we can
+  // get a pointer to the next object in memory, keeping it live
+  // unnecessarily.  When the length is zero, the actual pointer
+  // value doesn't matter.
+  Btype* int_btype = int_type->get_backend(gogo);
+  Bexpression* zero =
+    Expression::make_integer_ul(0, int_type, loc)->get_backend(context);
+  Bexpression* cond =
+    gogo->backend()->binary_expression(OPERATOR_EQEQ, new_length, zero,
+                                       loc);
+  Bexpression* offset =
+    gogo->backend()->conditional_expression(bfn, int_btype, cond, zero,
+                                            bstart, loc);
+
+  ptr = gogo->backend()->pointer_offset_expression(ptr, offset, loc);
+
+  Btype* str_btype = this->type()->get_backend(gogo);
+  std::vector<Bexpression*> init;
+  init.push_back(ptr);
+  init.push_back(new_length);
+  Bexpression* bstrslice =
+    gogo->backend()->constructor_expression(str_btype, init, loc);
 
-  Btype* str_btype = strslice->type()->get_backend(gogo);
   Bexpression* index_error = bad_index->get_backend(context);
   return gogo->backend()->conditional_expression(bfn, str_btype, index_error,
                                                 crash, bstrslice, loc);
index 38dee04ca973e055a83e6838f1891fb0701229da..2c505a9743f61dd4f14c01f38be79f51d0eaea30 100644 (file)
@@ -3133,6 +3133,18 @@ class String_index_expression : public Expression
   string() const
   { return this->string_; }
 
+  // Return the index of a simple index expression, or the start index
+  // of a slice expression.
+  Expression*
+  start() const
+  { return this->start_; }
+
+  // Return the end index of a slice expression.  This is NULL for a
+  // simple index expression.
+  Expression*
+  end() const
+  { return this->end_; }
+
  protected:
   int
   do_traverse(Traverse*);
index c81ab79cc0f8a35601900bd6dcaf8315c22a7bc0..ffc747bb575af0a758fa215c6923bd8985e5c927 100644 (file)
@@ -45,10 +45,6 @@ DEF_GO_RUNTIME(EQSTRING, "runtime.eqstring", P2(STRING, STRING), R1(BOOL))
 // Compare two strings.
 DEF_GO_RUNTIME(CMPSTRING, "runtime.cmpstring", P2(STRING, STRING), R1(INT))
 
-// Take a slice of a string.
-DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT),
-              R1(STRING))
-
 // Convert an integer to a string.
 DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING))
 
index 7f424fd7b7af1447f3a012ef813e5ebb0ea38ecc..e8380be0bb00fc69ad6f6ac15b62d0ace465f37e 100644 (file)
@@ -1021,6 +1021,18 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
          && ival == 0)
        this->omit_write_barrier_ = true;
     }
+  String_index_expression* sie = this->rhs_->string_index_expression();
+  if (sie != NULL
+      && sie->end() != NULL
+      && Expression::is_same_variable(this->lhs_, sie->string()))
+    {
+      Numeric_constant nc;
+      unsigned long ival;
+      if (sie->start()->numeric_constant_value(&nc)
+         && nc.to_unsigned_long(&ival) == Numeric_constant::NC_UL_VALID
+         && ival == 0)
+        this->omit_write_barrier_ = true;
+    }
 
   return this;
 }
index 6324170816a705b37b21f54697c10d30d9071934..4bfed3facf75d792c8962fdd0a60ee8fdaa2823d 100644 (file)
@@ -468,7 +468,6 @@ runtime_files = \
        runtime/go-runtime-error.c \
        runtime/go-setenv.c \
        runtime/go-signal.c \
-       runtime/go-strslice.c \
        runtime/go-unsafe-pointer.c \
        runtime/go-unsetenv.c \
        runtime/go-unwind.c \
index 08a39266ccc81056d72ec56c41b93019e30d2566..837e1e8a621f25e66ec4cdb799acaef37862eee5 100644 (file)
@@ -248,12 +248,12 @@ am__objects_3 = runtime/aeshash.lo runtime/go-assert.lo \
        runtime/go-nanotime.lo runtime/go-now.lo runtime/go-nosys.lo \
        runtime/go-reflect-call.lo runtime/go-runtime-error.lo \
        runtime/go-setenv.lo runtime/go-signal.lo \
-       runtime/go-strslice.lo runtime/go-unsafe-pointer.lo \
-       runtime/go-unsetenv.lo runtime/go-unwind.lo \
-       runtime/go-varargs.lo runtime/env_posix.lo runtime/panic.lo \
-       runtime/print.lo runtime/proc.lo runtime/runtime_c.lo \
-       runtime/stack.lo runtime/yield.lo runtime/go-context.lo \
-       $(am__objects_1) $(am__objects_2)
+       runtime/go-unsafe-pointer.lo runtime/go-unsetenv.lo \
+       runtime/go-unwind.lo runtime/go-varargs.lo \
+       runtime/env_posix.lo runtime/panic.lo runtime/print.lo \
+       runtime/proc.lo runtime/runtime_c.lo runtime/stack.lo \
+       runtime/yield.lo runtime/go-context.lo $(am__objects_1) \
+       $(am__objects_2)
 am_libgo_llgo_la_OBJECTS = $(am__objects_3)
 libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -901,7 +901,6 @@ runtime_files = \
        runtime/go-runtime-error.c \
        runtime/go-setenv.c \
        runtime/go-signal.c \
-       runtime/go-strslice.c \
        runtime/go-unsafe-pointer.c \
        runtime/go-unsetenv.c \
        runtime/go-unwind.c \
@@ -1362,8 +1361,6 @@ runtime/go-setenv.lo: runtime/$(am__dirstamp) \
        runtime/$(DEPDIR)/$(am__dirstamp)
 runtime/go-signal.lo: runtime/$(am__dirstamp) \
        runtime/$(DEPDIR)/$(am__dirstamp)
-runtime/go-strslice.lo: runtime/$(am__dirstamp) \
-       runtime/$(DEPDIR)/$(am__dirstamp)
 runtime/go-unsafe-pointer.lo: runtime/$(am__dirstamp) \
        runtime/$(DEPDIR)/$(am__dirstamp)
 runtime/go-unsetenv.lo: runtime/$(am__dirstamp) \
@@ -1448,7 +1445,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-runtime-error.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-setenv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-signal.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-strslice.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-unsafe-pointer.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-unsetenv.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-unwind.Plo@am__quote@
diff --git a/libgo/runtime/go-strslice.c b/libgo/runtime/go-strslice.c
deleted file mode 100644 (file)
index d51c249..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* go-strslice.c -- the go string slice function.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include "runtime.h"
-
-String
-__go_string_slice (String s, intgo start, intgo end)
-{
-  intgo len;
-  String ret;
-
-  len = s.len;
-  if (end == -1)
-    end = len;
-  if (start > len || end < start || end > len)
-    runtime_panicstring ("string index out of bounds");
-  ret.len = end - start;
-  // If the length of the new string is zero, the str field doesn't
-  // matter, so just set it to nil.  This avoids the problem of
-  // s.str + start pointing just past the end of the string,
-  // which may keep the next memory block alive unnecessarily.
-  if (ret.len == 0)
-    ret.str = nil;
-  else
-    ret.str = s.str + start;
-  return ret;
-}