Commit c9b236e5 by Ian Lance Taylor

compiler: open code string slice expressions

    
    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
parent 050e182a
7822080a6e226b1e5872e2fcefac30f666f4cc1e 62e3a8cc0a862b0abd3d0b1ef6cf4b228992a137
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.
...@@ -13082,11 +13082,6 @@ Bexpression* ...@@ -13082,11 +13082,6 @@ Bexpression*
String_index_expression::do_get_backend(Translate_context* context) String_index_expression::do_get_backend(Translate_context* context)
{ {
Location loc = this->location(); 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); Expression* bad_index = Expression::check_bounds(this->start_, loc);
int code = (this->end_ == NULL int code = (this->end_ == NULL
...@@ -13110,23 +13105,27 @@ String_index_expression::do_get_backend(Translate_context* context) ...@@ -13110,23 +13105,27 @@ String_index_expression::do_get_backend(Translate_context* context)
return context->backend()->error_expression(); 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); Expression* start = Expression::make_cast(int_type, this->start_, loc);
Bfunction* bfn = context->function()->func_value()->get_decl(); 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) if (this->end_ == NULL)
{ {
Expression* length =
Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
Expression* start_too_large = Expression* start_too_large =
Expression::make_binary(OPERATOR_GE, start, length, loc); Expression::make_binary(OPERATOR_GE, start, length, loc);
bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large, bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
bad_index, loc); 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); ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo); Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo);
Bexpression* index = Bexpression* index =
...@@ -13141,20 +13140,53 @@ String_index_expression::do_get_backend(Translate_context* context) ...@@ -13141,20 +13140,53 @@ String_index_expression::do_get_backend(Translate_context* context)
Expression* end = NULL; Expression* end = NULL;
if (this->end_->is_nil_expression()) if (this->end_->is_nil_expression())
end = Expression::make_integer_sl(-1, int_type, loc); end = length;
else else
{ {
go_assert(this->end_->is_variable());
Expression* bounds_check = Expression::check_bounds(this->end_, loc); Expression* bounds_check = Expression::check_bounds(this->end_, loc);
bad_index = bad_index =
Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc); Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
end = Expression::make_cast(int_type, this->end_, 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, // If the new length is zero, don't change pointer. Otherwise we can
string_arg, start, end); // get a pointer to the next object in memory, keeping it live
Bexpression* bstrslice = strslice->get_backend(context); // 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); Bexpression* index_error = bad_index->get_backend(context);
return gogo->backend()->conditional_expression(bfn, str_btype, index_error, return gogo->backend()->conditional_expression(bfn, str_btype, index_error,
crash, bstrslice, loc); crash, bstrslice, loc);
......
...@@ -3133,6 +3133,18 @@ class String_index_expression : public Expression ...@@ -3133,6 +3133,18 @@ class String_index_expression : public Expression
string() const string() const
{ return this->string_; } { 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: protected:
int int
do_traverse(Traverse*); do_traverse(Traverse*);
......
...@@ -45,10 +45,6 @@ DEF_GO_RUNTIME(EQSTRING, "runtime.eqstring", P2(STRING, STRING), R1(BOOL)) ...@@ -45,10 +45,6 @@ DEF_GO_RUNTIME(EQSTRING, "runtime.eqstring", P2(STRING, STRING), R1(BOOL))
// Compare two strings. // Compare two strings.
DEF_GO_RUNTIME(CMPSTRING, "runtime.cmpstring", P2(STRING, STRING), R1(INT)) 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. // Convert an integer to a string.
DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING)) DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING))
......
...@@ -1021,6 +1021,18 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, ...@@ -1021,6 +1021,18 @@ Assignment_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing,
&& ival == 0) && ival == 0)
this->omit_write_barrier_ = true; 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; return this;
} }
......
...@@ -468,7 +468,6 @@ runtime_files = \ ...@@ -468,7 +468,6 @@ runtime_files = \
runtime/go-runtime-error.c \ runtime/go-runtime-error.c \
runtime/go-setenv.c \ runtime/go-setenv.c \
runtime/go-signal.c \ runtime/go-signal.c \
runtime/go-strslice.c \
runtime/go-unsafe-pointer.c \ runtime/go-unsafe-pointer.c \
runtime/go-unsetenv.c \ runtime/go-unsetenv.c \
runtime/go-unwind.c \ runtime/go-unwind.c \
......
...@@ -248,12 +248,12 @@ am__objects_3 = runtime/aeshash.lo runtime/go-assert.lo \ ...@@ -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-nanotime.lo runtime/go-now.lo runtime/go-nosys.lo \
runtime/go-reflect-call.lo runtime/go-runtime-error.lo \ runtime/go-reflect-call.lo runtime/go-runtime-error.lo \
runtime/go-setenv.lo runtime/go-signal.lo \ runtime/go-setenv.lo runtime/go-signal.lo \
runtime/go-strslice.lo runtime/go-unsafe-pointer.lo \ runtime/go-unsafe-pointer.lo runtime/go-unsetenv.lo \
runtime/go-unsetenv.lo runtime/go-unwind.lo \ runtime/go-unwind.lo runtime/go-varargs.lo \
runtime/go-varargs.lo runtime/env_posix.lo runtime/panic.lo \ runtime/env_posix.lo runtime/panic.lo runtime/print.lo \
runtime/print.lo runtime/proc.lo runtime/runtime_c.lo \ runtime/proc.lo runtime/runtime_c.lo runtime/stack.lo \
runtime/stack.lo runtime/yield.lo runtime/go-context.lo \ runtime/yield.lo runtime/go-context.lo $(am__objects_1) \
$(am__objects_1) $(am__objects_2) $(am__objects_2)
am_libgo_llgo_la_OBJECTS = $(am__objects_3) am_libgo_llgo_la_OBJECTS = $(am__objects_3)
libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS) libgo_llgo_la_OBJECTS = $(am_libgo_llgo_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@) AM_V_lt = $(am__v_lt_@AM_V@)
...@@ -901,7 +901,6 @@ runtime_files = \ ...@@ -901,7 +901,6 @@ runtime_files = \
runtime/go-runtime-error.c \ runtime/go-runtime-error.c \
runtime/go-setenv.c \ runtime/go-setenv.c \
runtime/go-signal.c \ runtime/go-signal.c \
runtime/go-strslice.c \
runtime/go-unsafe-pointer.c \ runtime/go-unsafe-pointer.c \
runtime/go-unsetenv.c \ runtime/go-unsetenv.c \
runtime/go-unwind.c \ runtime/go-unwind.c \
...@@ -1362,8 +1361,6 @@ runtime/go-setenv.lo: runtime/$(am__dirstamp) \ ...@@ -1362,8 +1361,6 @@ runtime/go-setenv.lo: runtime/$(am__dirstamp) \
runtime/$(DEPDIR)/$(am__dirstamp) runtime/$(DEPDIR)/$(am__dirstamp)
runtime/go-signal.lo: runtime/$(am__dirstamp) \ runtime/go-signal.lo: runtime/$(am__dirstamp) \
runtime/$(DEPDIR)/$(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/go-unsafe-pointer.lo: runtime/$(am__dirstamp) \
runtime/$(DEPDIR)/$(am__dirstamp) runtime/$(DEPDIR)/$(am__dirstamp)
runtime/go-unsetenv.lo: runtime/$(am__dirstamp) \ runtime/go-unsetenv.lo: runtime/$(am__dirstamp) \
...@@ -1448,7 +1445,6 @@ distclean-compile: ...@@ -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-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-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-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-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-unsetenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-unwind.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@runtime/$(DEPDIR)/go-unwind.Plo@am__quote@
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment