summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/gc/walk.go66
-rw-r--r--test/prove.go2
2 files changed, 51 insertions, 17 deletions
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index e53fd7ac97..2c873b8163 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -1371,20 +1371,7 @@ opswitch:
n = callnew(n.Type.Elem())
}
- // If one argument to the comparison is an empty string,
- // comparing the lengths instead will yield the same result
- // without the function call.
case OCMPSTR:
- if (Isconst(n.Left, CTSTR) && len(n.Left.Val().U.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
- // TODO(marvin): Fix Node.EType type union.
- r := Nod(Op(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
- r = typecheck(r, Erv)
- r = walkexpr(r, init)
- r.Type = n.Type
- n = r
- break
- }
-
// s + "badgerbadgerbadger" == "badgerbadgerbadger"
if (Op(n.Etype) == OEQ || Op(n.Etype) == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && n.Left.List.Len() == 2 && Isconst(n.Left.List.Second(), CTSTR) && strlit(n.Right) == strlit(n.Left.List.Second()) {
// TODO(marvin): Fix Node.EType type union.
@@ -1396,12 +1383,61 @@ opswitch:
break
}
+ // Rewrite comparisons to short constant strings as length+byte-wise comparisons.
+ var cs, ncs *Node // const string, non-const string
+ switch {
+ case Isconst(n.Left, CTSTR) && Isconst(n.Right, CTSTR):
+ // ignore; will be constant evaluated
+ case Isconst(n.Left, CTSTR):
+ cs = n.Left
+ ncs = n.Right
+ case Isconst(n.Right, CTSTR):
+ cs = n.Right
+ ncs = n.Left
+ }
+ if cs != nil {
+ cmp := Op(n.Etype)
+ // maxRewriteLen was chosen empirically.
+ // It is the value that minimizes cmd/go file size
+ // across most architectures.
+ // See the commit description for CL 26758 for details.
+ maxRewriteLen := 6
+ var and Op
+ switch cmp {
+ case OEQ:
+ and = OANDAND
+ case ONE:
+ and = OOROR
+ default:
+ // Don't do byte-wise comparisons for <, <=, etc.
+ // They're fairly complicated.
+ // Length-only checks are ok, though.
+ maxRewriteLen = 0
+ }
+ if s := cs.Val().U.(string); len(s) <= maxRewriteLen {
+ if len(s) > 0 {
+ ncs = safeexpr(ncs, init)
+ }
+ // TODO(marvin): Fix Node.EType type union.
+ r := Nod(cmp, Nod(OLEN, ncs, nil), Nodintconst(int64(len(s))))
+ for i := 0; i < len(s); i++ {
+ cb := Nodintconst(int64(s[i]))
+ ncb := Nod(OINDEX, ncs, Nodintconst(int64(i)))
+ r = Nod(and, r, Nod(cmp, ncb, cb))
+ }
+ r = typecheck(r, Erv)
+ r = walkexpr(r, init)
+ r.Type = n.Type
+ n = r
+ break
+ }
+ }
+
var r *Node
// TODO(marvin): Fix Node.EType type union.
if Op(n.Etype) == OEQ || Op(n.Etype) == ONE {
// prepare for rewrite below
n.Left = cheapexpr(n.Left, init)
-
n.Right = cheapexpr(n.Right, init)
r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
@@ -1415,7 +1451,6 @@ opswitch:
} else {
// len(left) != len(right) || !eqstring(left, right)
r = Nod(ONOT, r, nil)
-
r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
}
@@ -1424,7 +1459,6 @@ opswitch:
} else {
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
-
// TODO(marvin): Fix Node.EType type union.
r = Nod(Op(n.Etype), r, nodintconst(0))
}
diff --git a/test/prove.go b/test/prove.go
index 8bcc9ae614..65eed745cb 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -250,7 +250,7 @@ func f9(a, b bool) int {
func f10(a string) int {
n := len(a)
- if a[:n>>1] == "aaa" {
+ if a[:n>>1] == "aaaaaaaaaaaaaa" {
return 0
}
return 1