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
This commit is contained in:
parent
d611cec3de
commit
609c7da9ab
@ -1,4 +1,4 @@
|
||||
338e4baf88a4ae676205dff601dbef2d31b19d2d
|
||||
89b442a0100286ee569b8d2562ce1b2ea602f7e7
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
@ -6226,10 +6226,27 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*,
|
||||
bool is_idiv_op = ((this->op_ == OPERATOR_DIV &&
|
||||
left_type->integer_type() != NULL)
|
||||
|| 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
|
||||
|| (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())
|
||||
{
|
||||
@ -7217,19 +7234,42 @@ 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);
|
||||
go_assert(left->is_variable() || left->is_constant());
|
||||
go_assert(right->is_variable() || right->is_constant());
|
||||
|
||||
if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
|
||||
{
|
||||
left = Runtime::make_call(Runtime::EQSTRING, location, 2,
|
||||
left, right);
|
||||
// (l.len == r.len
|
||||
// ? (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);
|
||||
}
|
||||
else
|
||||
|
@ -39,9 +39,6 @@ DEF_GO_RUNTIME(DECODERUNE, "runtime.decoderune", P2(STRING, INT),
|
||||
DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings",
|
||||
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.
|
||||
DEF_GO_RUNTIME(CMPSTRING, "runtime.cmpstring", P2(STRING, STRING), R1(INT))
|
||||
|
||||
|
@ -44,7 +44,6 @@ import (
|
||||
//go:linkname ifacevaleq runtime.ifacevaleq
|
||||
//go:linkname ifaceefaceeq runtime.ifaceefaceeq
|
||||
//go:linkname efacevaleq runtime.efacevaleq
|
||||
//go:linkname eqstring runtime.eqstring
|
||||
//go:linkname cmpstring runtime.cmpstring
|
||||
//
|
||||
// Temporary to be called from C code.
|
||||
|
@ -273,18 +273,6 @@ func checkASM() bool {
|
||||
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.
|
||||
func osyield()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user