]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.power64] 9g: fix under-zeroing in clearfat
authorAustin Clements <austin@google.com>
Fri, 31 Oct 2014 15:08:27 +0000 (11:08 -0400)
committerAustin Clements <austin@google.com>
Fri, 31 Oct 2014 15:08:27 +0000 (11:08 -0400)
All three cases of clearfat were wrong on power64x.

The cases that handle 1032 bytes and up and 32 bytes and up
both use MOVDU (one directly generated in a loop and the other
via duffzero), which leaves the pointer register pointing at
the *last written* address.  The generated code was not
accounting for this, so the byte fill loop was re-zeroing the
last zeroed dword, rather than the bytes following the last
zeroed dword.  Fix this by simply adding an additional 8 byte
offset to the byte zeroing loop.

The case that handled under 32 bytes was also wrong.  It
didn't update the pointer register at all, so the byte zeroing
loop was simply re-zeroing the beginning of region.  Again,
the fix is to add an offset to the byte zeroing loop to
account for this.

LGTM=dave, bradfitz
R=rsc, dave, bradfitz
CC=golang-codereviews
https://golang.org/cl/168870043

src/cmd/9g/ggen.c
src/runtime/asm_power64x.s
test/clearfat.go [new file with mode: 0644]

index c41d8eb414fc4abd6a35362d4882eeb756e90a05..7d9cf5050d2cb6ceab0a20999fe2b2128696b93b 100644 (file)
@@ -900,7 +900,7 @@ ret:
 void
 clearfat(Node *nl)
 {
-       uint64 w, c, q, t;
+       uint64 w, c, q, t, boff;
        Node dst, end, r0, *f;
        Prog *p, *pl;
 
@@ -944,6 +944,8 @@ clearfat(Node *nl)
                patch(gbranch(ABNE, T, 0), pl);
 
                regfree(&end);
+               // The loop leaves R3 on the last zeroed dword
+               boff = 8;
        } else if(q >= 4) {
                p = gins(ASUB, N, &dst);
                p->from.type = D_CONST;
@@ -953,17 +955,21 @@ clearfat(Node *nl)
                afunclit(&p->to, f);
                // 4 and 128 = magic constants: see ../../runtime/asm_power64x.s
                p->to.offset = 4*(128-q);
-       } else
-       for(t = 0; t < q; t++) {
-               p = gins(AMOVD, &r0, &dst);
-               p->to.type = D_OREG;
-               p->to.offset = 8*t;
+               // duffzero leaves R3 on the last zeroed dword
+               boff = 8;
+       } else {
+               for(t = 0; t < q; t++) {
+                       p = gins(AMOVD, &r0, &dst);
+                       p->to.type = D_OREG;
+                       p->to.offset = 8*t;
+               }
+               boff = 8*q;
        }
 
        for(t = 0; t < c; t++) {
                p = gins(AMOVB, &r0, &dst);
                p->to.type = D_OREG;
-               p->to.offset = t;
+               p->to.offset = t+boff;
        }
        reg[REGRT1]--;
 }
index ab2db061c251b294c66a762c06ec33e99b5071d1..2ad3e56e94f9dab5cd5c2fdd16111636ef18d9d9 100644 (file)
@@ -829,7 +829,7 @@ notfound:
 // in ../../cmd/9g/ggen.c:/^clearfat.
 // R0: always zero
 // R3 (aka REGRT1): ptr to memory to be zeroed - 8
-// R3 is updated as a side effect.
+// On return, R3 points to the last zeroed dword.
 TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
        MOVDU   R0, 8(R3)
        MOVDU   R0, 8(R3)
diff --git a/test/clearfat.go b/test/clearfat.go
new file mode 100644 (file)
index 0000000..45d5393
--- /dev/null
@@ -0,0 +1,68 @@
+// runoutput
+
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check that {5,6,8,9}g/ggen.c:clearfat is zeroing the entire object.
+
+package main
+
+import (
+       "bytes"
+       "fmt"
+       "strconv"
+       "strings"
+)
+
+const ntest = 1100
+
+func main() {
+       var decls, calls bytes.Buffer
+
+       for i := 1; i <= ntest; i++ {
+               s := strconv.Itoa(i)
+               decls.WriteString(strings.Replace(decl, "$", s, -1))
+               calls.WriteString(strings.Replace("poison$()\n\tclearfat$()\n\t", "$", s, -1))
+       }
+
+       program = strings.Replace(program, "$DECLS", decls.String(), 1)
+       program = strings.Replace(program, "$CALLS", calls.String(), 1)
+       fmt.Print(program)
+}
+
+var program = `package main
+
+var count int
+
+$DECLS
+
+func main() {
+       $CALLS
+       if count != 0 {
+               println("failed", count, "case(s)")
+       }
+}
+`
+
+const decl = `
+func poison$() {
+       // Grow and poison the stack space that will be used by clearfat$
+       var t [2*$]byte
+       for i := range t {
+               t[i] = 0xff
+       }
+}
+
+func clearfat$() {
+       var t [$]byte
+
+       for _, x := range t {
+               if x != 0 {
+//                     println("clearfat$: index", i, "expected 0, got", x)
+                       count++
+                       break
+               }
+       }
+}
+`