cmd/compile/internal/gc: refactor range/memclr optimization
No functional change and passes toolstash/buildall, but eliminates a
13-deep nesting of if statements.
Change-Id: I32e63dcf358c6eb521935f4ee07fbe749278e5ef
Reviewed-on: https://go-review.googlesource.com/15901
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
index dbfd674..59f7d40 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -167,87 +167,10 @@
default:
Fatalf("walkrange")
- // Lower n into runtime·memclr if possible, for
- // fast zeroing of slices and arrays (issue 5373).
- // Look for instances of
- //
- // for i := range a {
- // a[i] = zero
- // }
- //
- // in which the evaluation of a is side-effect-free.
case TARRAY:
- if Debug['N'] == 0 {
- if flag_race == 0 {
- if v1 != nil {
- if v2 == nil {
- if n.Nbody != nil {
- if n.Nbody.N != nil { // at least one statement in body
- if n.Nbody.Next == nil { // at most one statement in body
- tmp := n.Nbody.N // first statement of body
- if tmp.Op == OAS {
- if tmp.Left.Op == OINDEX {
- if samesafeexpr(tmp.Left.Left, a) {
- if samesafeexpr(tmp.Left.Right, v1) {
- if t.Type.Width > 0 {
- if iszero(tmp.Right) {
- // Convert to
- // if len(a) != 0 {
- // hp = &a[0]
- // hn = len(a)*sizeof(elem(a))
- // memclr(hp, hn)
- // i = len(a) - 1
- // }
- n.Op = OIF
-
- n.Nbody = nil
- n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
-
- // hp = &a[0]
- hp := temp(Ptrto(Types[TUINT8]))
-
- tmp := Nod(OINDEX, a, Nodintconst(0))
- tmp.Bounded = true
- tmp = Nod(OADDR, tmp, nil)
- tmp = Nod(OCONVNOP, tmp, nil)
- tmp.Type = Ptrto(Types[TUINT8])
- n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
-
- // hn = len(a) * sizeof(elem(a))
- hn := temp(Types[TUINTPTR])
-
- tmp = Nod(OLEN, a, nil)
- tmp = Nod(OMUL, tmp, Nodintconst(t.Type.Width))
- tmp = conv(tmp, Types[TUINTPTR])
- n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
-
- // memclr(hp, hn)
- fn := mkcall("memclr", nil, nil, hp, hn)
-
- n.Nbody = list(n.Nbody, fn)
-
- // i = len(a) - 1
- v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
-
- n.Nbody = list(n.Nbody, v1)
-
- typecheck(&n.Left, Erv)
- typechecklist(n.Nbody, Etop)
- walkstmt(&n)
- lineno = int32(lno)
- return
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
+ if memclrrange(n, v1, v2, a) {
+ lineno = int32(lno)
+ return
}
// orderstmt arranged for a copy of the array/slice variable if needed.
@@ -404,3 +327,82 @@
lineno = int32(lno)
}
+
+// Lower n into runtime·memclr if possible, for
+// fast zeroing of slices and arrays (issue 5373).
+// Look for instances of
+//
+// for i := range a {
+// a[i] = zero
+// }
+//
+// in which the evaluation of a is side-effect-free.
+//
+// Parameters are as in walkrange: "for v1, v2 = range a".
+func memclrrange(n, v1, v2, a *Node) bool {
+ if Debug['N'] != 0 || flag_race != 0 {
+ return false
+ }
+ if v1 == nil || v2 != nil {
+ return false
+ }
+ if n.Nbody == nil || n.Nbody.N == nil || n.Nbody.Next != nil {
+ return false
+ }
+ stmt := n.Nbody.N // only stmt in body
+ if stmt.Op != OAS || stmt.Left.Op != OINDEX {
+ return false
+ }
+ if !samesafeexpr(stmt.Left.Left, a) || !samesafeexpr(stmt.Left.Right, v1) {
+ return false
+ }
+ elemsize := n.Type.Type.Width
+ if elemsize <= 0 || !iszero(stmt.Right) {
+ return false
+ }
+
+ // Convert to
+ // if len(a) != 0 {
+ // hp = &a[0]
+ // hn = len(a)*sizeof(elem(a))
+ // memclr(hp, hn)
+ // i = len(a) - 1
+ // }
+ n.Op = OIF
+
+ n.Nbody = nil
+ n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
+
+ // hp = &a[0]
+ hp := temp(Ptrto(Types[TUINT8]))
+
+ tmp := Nod(OINDEX, a, Nodintconst(0))
+ tmp.Bounded = true
+ tmp = Nod(OADDR, tmp, nil)
+ tmp = Nod(OCONVNOP, tmp, nil)
+ tmp.Type = Ptrto(Types[TUINT8])
+ n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
+
+ // hn = len(a) * sizeof(elem(a))
+ hn := temp(Types[TUINTPTR])
+
+ tmp = Nod(OLEN, a, nil)
+ tmp = Nod(OMUL, tmp, Nodintconst(elemsize))
+ tmp = conv(tmp, Types[TUINTPTR])
+ n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
+
+ // memclr(hp, hn)
+ fn := mkcall("memclr", nil, nil, hp, hn)
+
+ n.Nbody = list(n.Nbody, fn)
+
+ // i = len(a) - 1
+ v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
+
+ n.Nbody = list(n.Nbody, v1)
+
+ typecheck(&n.Left, Erv)
+ typechecklist(n.Nbody, Etop)
+ walkstmt(&n)
+ return true
+}