aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2019-05-08 23:06:52 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-05-08 23:06:52 +0000
commit3407d1658f7d60cfb78293d61dfc21258efb0074 (patch)
tree8aab6b19727ef793d37cb592a45bd808a3419700
parent8238b660fb6204b3e6968e9a6ed550b16c86b25e (diff)
downloadgcc-3407d1658f7d60cfb78293d61dfc21258efb0074.zip
gcc-3407d1658f7d60cfb78293d61dfc21258efb0074.tar.gz
gcc-3407d1658f7d60cfb78293d61dfc21258efb0074.tar.bz2
compiler: avoid copy for string([]byte) conversion used in string comparison
If a string([]byte) conversion is used immediately in a string comparison, we don't need to copy the backing store of the byte slice, as the string comparison doesn't hold any reference to it. Instead, just create a string header from the byte slice and pass it for comparison. A new type of expression, String_value_expression, is introduced, for constructing string headers. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/170894 * go.dg/cmpstring.go: New test. From-SVN: r271021
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc118
-rw-r--r--gcc/go/gofrontend/expressions.h17
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/go.dg/cmpstring.go13
5 files changed, 148 insertions, 6 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 7c884a9..f6f28a3 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-f813c670deb8e0454c3f64de74bedb5dcedd10b4
+9c8581187b1c1a30036263728370f31cb846a274
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 707636a..2c1286c 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -2031,6 +2031,90 @@ Expression::make_string_info(Expression* string, String_info string_info,
return new String_info_expression(string, string_info, location);
}
+// An expression that represents an string value: a struct with value pointer
+// and length fields.
+
+class String_value_expression : public Expression
+{
+ public:
+ String_value_expression(Expression* valptr, Expression* len, Location location)
+ : Expression(EXPRESSION_STRING_VALUE, location),
+ valptr_(valptr), len_(len)
+ { }
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type()
+ { return Type::make_string_type(); }
+
+ void
+ do_determine_type(const Type_context*)
+ { go_unreachable(); }
+
+ Expression*
+ do_copy()
+ {
+ return new String_value_expression(this->valptr_->copy(),
+ this->len_->copy(),
+ this->location());
+ }
+
+ Bexpression*
+ do_get_backend(Translate_context* context);
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The value pointer.
+ Expression* valptr_;
+ // The length.
+ Expression* len_;
+};
+
+int
+String_value_expression::do_traverse(Traverse* traverse)
+{
+ if (Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+ || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ return TRAVERSE_CONTINUE;
+}
+
+Bexpression*
+String_value_expression::do_get_backend(Translate_context* context)
+{
+ std::vector<Bexpression*> vals(2);
+ vals[0] = this->valptr_->get_backend(context);
+ vals[1] = this->len_->get_backend(context);
+
+ Gogo* gogo = context->gogo();
+ Btype* btype = Type::make_string_type()->get_backend(gogo);
+ return gogo->backend()->constructor_expression(btype, vals, this->location());
+}
+
+void
+String_value_expression::do_dump_expression(
+ Ast_dump_context* ast_dump_context) const
+{
+ ast_dump_context->ostream() << "stringvalue(";
+ ast_dump_context->ostream() << "value: ";
+ this->valptr_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ", length: ";
+ this->len_->dump_expression(ast_dump_context);
+ ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_string_value(Expression* valptr, Expression* len,
+ Location location)
+{
+ return new String_value_expression(valptr, len, location);
+}
+
// Make an integer expression.
class Integer_expression : public Expression
@@ -3702,9 +3786,11 @@ Type_conversion_expression::do_check_types(Gogo*)
Expression*
Type_conversion_expression::do_copy()
{
- return new Type_conversion_expression(this->type_->copy_expressions(),
- this->expr_->copy(),
- this->location());
+ Expression* ret = new Type_conversion_expression(this->type_->copy_expressions(),
+ this->expr_->copy(),
+ this->location());
+ ret->conversion_expression()->set_no_copy(this->no_copy_);
+ return ret;
}
// Get the backend representation for a type conversion.
@@ -3764,7 +3850,22 @@ Type_conversion_expression::do_get_backend(Translate_context* context)
Runtime::Function code;
if (e->integer_type()->is_byte())
- code = Runtime::SLICEBYTETOSTRING;
+ {
+ if (this->no_copy_)
+ {
+ if (gogo->debug_optimization())
+ go_inform(loc, "no copy string([]byte)");
+ Expression* ptr = Expression::make_slice_info(this->expr_,
+ SLICE_INFO_VALUE_POINTER,
+ loc);
+ Expression* len = Expression::make_slice_info(this->expr_,
+ SLICE_INFO_LENGTH,
+ loc);
+ Expression* str = Expression::make_string_value(ptr, len, loc);
+ return str->get_backend(context);
+ }
+ code = Runtime::SLICEBYTETOSTRING;
+ }
else
{
go_assert(e->integer_type()->is_rune());
@@ -6805,6 +6906,15 @@ Expression::comparison(Translate_context* context, Type* result_type,
if (left_type->is_string_type() && right_type->is_string_type())
{
+ // Mark string([]byte) operands to reuse the backing store.
+ // String comparison does not keep the reference, so it is safe.
+ Type_conversion_expression* lce = left->conversion_expression();
+ if (lce != NULL && lce->expr()->type()->is_slice_type())
+ lce->set_no_copy(true);
+ Type_conversion_expression* rce = right->conversion_expression();
+ if (rce != NULL && rce->expr()->type()->is_slice_type())
+ rce->set_no_copy(true);
+
if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
{
left = Runtime::make_call(Runtime::EQSTRING, location, 2,
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 7d3cfd8..2cca824 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -102,6 +102,7 @@ class Expression
EXPRESSION_BOOLEAN,
EXPRESSION_STRING,
EXPRESSION_STRING_INFO,
+ EXPRESSION_STRING_VALUE,
EXPRESSION_INTEGER,
EXPRESSION_FLOAT,
EXPRESSION_COMPLEX,
@@ -248,6 +249,10 @@ class Expression
static Expression*
make_string_info(Expression* string, String_info, Location);
+ // Make an expression for a string value.
+ static Expression*
+ make_string_value(Expression* valptr, Expression* len, Location);
+
// Make a character constant expression. TYPE should be NULL for an
// abstract type.
static Expression*
@@ -1668,7 +1673,8 @@ class Type_conversion_expression : public Expression
Type_conversion_expression(Type* type, Expression* expr,
Location location)
: Expression(EXPRESSION_CONVERSION, location),
- type_(type), expr_(expr), may_convert_function_types_(false)
+ type_(type), expr_(expr), may_convert_function_types_(false),
+ no_copy_(false)
{ }
// Return the type to which we are converting.
@@ -1689,6 +1695,12 @@ class Type_conversion_expression : public Expression
this->may_convert_function_types_ = true;
}
+ // Mark string([]byte) conversion to reuse the backing store
+ // without copying.
+ void
+ set_no_copy(bool b)
+ { this->no_copy_ = b; };
+
// Import a type conversion expression.
static Expression*
do_import(Import_expression*, Location);
@@ -1751,6 +1763,9 @@ class Type_conversion_expression : public Expression
// True if this is permitted to convert function types. This is
// used internally for method expressions.
bool may_convert_function_types_;
+ // True if a string([]byte) conversion can reuse the backing store
+ // without copying. Only used in string([]byte) conversion.
+ bool no_copy_;
};
// An unsafe type conversion, used to pass values to builtin functions.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 797a370..270453f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2019-05-08 Cherry Zhang <cherryyz@google.com>
+
+ * go.dg/cmpstring.go: New test.
+
2019-05-08 Jakub Jelinek <jakub@redhat.com>
PR c++/59813
diff --git a/gcc/testsuite/go.dg/cmpstring.go b/gcc/testsuite/go.dg/cmpstring.go
new file mode 100644
index 0000000..81d8aee
--- /dev/null
+++ b/gcc/testsuite/go.dg/cmpstring.go
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-fgo-debug-optimization" }
+
+package p
+
+func F(x []byte, y string) bool {
+ return string(x) == y // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+}
+
+func BytesEqual(x, y []byte) bool {
+ return string(x) == // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+ string(y) // { dg-error "no copy string\\(\\\[\\\]byte\\)" }
+}