aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-06-21 14:14:58 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-06-21 14:14:58 +0000
commitc9b236e5cafaea9d09ff8102140c72eb3d70e302 (patch)
treedaa083891ba7e3c96f4ac7419562dc67146822a6 /gcc
parent050e182a757bdf227a7e2425f06f9e2fd4dff8cb (diff)
downloadgcc-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/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc66
-rw-r--r--gcc/go/gofrontend/expressions.h12
-rw-r--r--gcc/go/gofrontend/runtime.def4
-rw-r--r--gcc/go/gofrontend/statements.cc12
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;
}