diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-06-21 14:14:58 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2019-06-21 14:14:58 +0000 |
commit | c9b236e5cafaea9d09ff8102140c72eb3d70e302 (patch) | |
tree | daa083891ba7e3c96f4ac7419562dc67146822a6 /gcc | |
parent | 050e182a757bdf227a7e2425f06f9e2fd4dff8cb (diff) | |
download | gcc-c9b236e5cafaea9d09ff8102140c72eb3d70e302.zip gcc-c9b236e5cafaea9d09ff8102140c72eb3d70e302.tar.gz gcc-c9b236e5cafaea9d09ff8102140c72eb3d70e302.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 66 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 12 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 12 |
5 files changed, 74 insertions, 22 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 3b0cff7..10104a7 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 864b62d..a764d06 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 38dee04..2c505a9 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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*); diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index c81ab79..ffc747b 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -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)) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 7f424fd..e8380be 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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; } |