Commit 609c7da9 by Ian Lance Taylor

compiler: open code string equality

    
    Open code string equality with builtin memcmp. This allows
    further optimizations in the backend.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/183538

From-SVN: r272624
parent d611cec3
338e4baf88a4ae676205dff601dbef2d31b19d2d 89b442a0100286ee569b8d2562ce1b2ea602f7e7
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.
...@@ -6226,10 +6226,27 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, ...@@ -6226,10 +6226,27 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*,
bool is_idiv_op = ((this->op_ == OPERATOR_DIV && bool is_idiv_op = ((this->op_ == OPERATOR_DIV &&
left_type->integer_type() != NULL) left_type->integer_type() != NULL)
|| this->op_ == OPERATOR_MOD); || this->op_ == OPERATOR_MOD);
bool is_string_op = (left_type->is_string_type()
&& this->right_->type()->is_string_type());
if (is_string_op)
{
// Mark string([]byte) operands to reuse the backing store.
// String comparison does not keep the reference, so it is safe.
Type_conversion_expression* lce =
this->left_->conversion_expression();
if (lce != NULL && lce->expr()->type()->is_slice_type())
lce->set_no_copy(true);
Type_conversion_expression* rce =
this->right_->conversion_expression();
if (rce != NULL && rce->expr()->type()->is_slice_type())
rce->set_no_copy(true);
}
if (is_shift_op if (is_shift_op
|| (is_idiv_op || (is_idiv_op
&& (gogo->check_divide_by_zero() || gogo->check_divide_overflow()))) && (gogo->check_divide_by_zero() || gogo->check_divide_overflow()))
|| is_string_op)
{ {
if (!this->left_->is_variable() && !this->left_->is_constant()) if (!this->left_->is_variable() && !this->left_->is_constant())
{ {
...@@ -7217,19 +7234,42 @@ Expression::comparison(Translate_context* context, Type* result_type, ...@@ -7217,19 +7234,42 @@ Expression::comparison(Translate_context* context, Type* result_type,
if (left_type->is_string_type() && right_type->is_string_type()) if (left_type->is_string_type() && right_type->is_string_type())
{ {
// Mark string([]byte) operands to reuse the backing store. go_assert(left->is_variable() || left->is_constant());
// String comparison does not keep the reference, so it is safe. go_assert(right->is_variable() || right->is_constant());
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) if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
{ {
left = Runtime::make_call(Runtime::EQSTRING, location, 2, // (l.len == r.len
left, right); // ? (l.ptr == r.ptr ? true : memcmp(l.ptr, r.ptr, r.len) == 0)
// : false)
Expression* llen = Expression::make_string_info(left,
STRING_INFO_LENGTH,
location);
Expression* rlen = Expression::make_string_info(right,
STRING_INFO_LENGTH,
location);
Expression* leneq = Expression::make_binary(OPERATOR_EQEQ, llen, rlen,
location);
Expression* lptr = Expression::make_string_info(left->copy(),
STRING_INFO_DATA,
location);
Expression* rptr = Expression::make_string_info(right->copy(),
STRING_INFO_DATA,
location);
Expression* ptreq = Expression::make_binary(OPERATOR_EQEQ, lptr, rptr,
location);
Expression* btrue = Expression::make_boolean(true, location);
Expression* call = Runtime::make_call(Runtime::MEMCMP, location, 3,
lptr->copy(), rptr->copy(),
rlen->copy());
Type* int32_type = Type::lookup_integer_type("int32");
Expression* zero = Expression::make_integer_ul(0, int32_type, location);
Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, call, zero,
location);
Expression* cond = Expression::make_conditional(ptreq, btrue, cmp,
location);
Expression* bfalse = Expression::make_boolean(false, location);
left = Expression::make_conditional(leneq, cond, bfalse, location);
right = Expression::make_boolean(true, location); right = Expression::make_boolean(true, location);
} }
else else
......
...@@ -39,9 +39,6 @@ DEF_GO_RUNTIME(DECODERUNE, "runtime.decoderune", P2(STRING, INT), ...@@ -39,9 +39,6 @@ DEF_GO_RUNTIME(DECODERUNE, "runtime.decoderune", P2(STRING, INT),
DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings", DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings",
P3(POINTER, POINTER, INT), R1(STRING)) P3(POINTER, POINTER, INT), R1(STRING))
// Compare two strings for equality.
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))
......
...@@ -44,7 +44,6 @@ import ( ...@@ -44,7 +44,6 @@ import (
//go:linkname ifacevaleq runtime.ifacevaleq //go:linkname ifacevaleq runtime.ifacevaleq
//go:linkname ifaceefaceeq runtime.ifaceefaceeq //go:linkname ifaceefaceeq runtime.ifaceefaceeq
//go:linkname efacevaleq runtime.efacevaleq //go:linkname efacevaleq runtime.efacevaleq
//go:linkname eqstring runtime.eqstring
//go:linkname cmpstring runtime.cmpstring //go:linkname cmpstring runtime.cmpstring
// //
// Temporary to be called from C code. // Temporary to be called from C code.
......
...@@ -273,18 +273,6 @@ func checkASM() bool { ...@@ -273,18 +273,6 @@ func checkASM() bool {
return true return true
} }
func eqstring(x, y string) bool {
a := stringStructOf(&x)
b := stringStructOf(&y)
if a.len != b.len {
return false
}
if a.str == b.str {
return true
}
return memequal(a.str, b.str, uintptr(a.len))
}
// For gccgo this is in the C code. // For gccgo this is in the C code.
func osyield() func osyield()
......
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