compiler: open code string equality
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 24 Jun 2019 17:54:07 +0000 (17:54 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 24 Jun 2019 17:54:07 +0000 (17:54 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/runtime.def
libgo/go/runtime/alg.go
libgo/go/runtime/stubs.go

index 89d401b6a3edd17ff00d97cf3b54bd590c608d54..ca68507906a96019965b9b2438c2fee559321a41 100644 (file)
@@ -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.
index 050da32c02f44be7099922588c6b5b6057cd64d7..2f33deeb4a1baaa0bd8e3d165c98a994214bf7ae 100644 (file)
@@ -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
index 7b66b166b77035e823900b29b04f0d02b16e095f..ec7ec769048d0726c9f542a555b3e70bb209bd24 100644 (file)
@@ -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))
 
index ec951e38cf51cabfab3b6ae5c88a0fff8dd03687..a2bb5bb0b9987043cdb6e00355f1c45fe2b552a1 100644 (file)
@@ -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.
index 530997b292e00060121208bb8ff879f95aa30168..e00d759b7061527db45c4731c1a25638f54c39f5 100644 (file)
@@ -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()