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
This commit is contained in:
parent
050e182a75
commit
c9b236e5ca
8 changed files with 80 additions and 63 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3,
|
||||
string_arg, start, end);
|
||||
Bexpression* bstrslice = strslice->get_backend(context);
|
||||
end = end->copy();
|
||||
Bexpression* bend = end->get_backend(context);
|
||||
Bexpression* new_length =
|
||||
gogo->backend()->binary_expression(OPERATOR_MINUS, bend, bstart, loc);
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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@
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue