]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: restore arm assembly stubs for div/mod
authorKeith Randall <keithr@alum.mit.edu>
Wed, 14 Jun 2017 18:36:36 +0000 (11:36 -0700)
committerKeith Randall <khr@golang.org>
Thu, 15 Jun 2017 03:51:03 +0000 (03:51 +0000)
These are used by DIV[U] and MOD[U] assembly instructions.
Add a test in the stdlib so we actually exercise linking
to these routines.

Update #19507

Change-Id: I0d8e19a53e3744abc0c661ea95486f94ec67585e
Reviewed-on: https://go-review.googlesource.com/45703
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/internal/obj/arm/asm5.go
src/runtime/softfloat_arm.go
src/runtime/vlop_arm.s
test/fixedbugs/issue19507.dir/div_arm.s [new file with mode: 0644]
test/fixedbugs/issue19507.dir/main.go [new file with mode: 0644]
test/fixedbugs/issue19507.go [new file with mode: 0644]
test/run.go

index 04b1cb7442786d93546323449baf925534b2d826..417da4457417957a1c54d1f4bffb2cb80a55783e 100644 (file)
@@ -1480,10 +1480,10 @@ func buildop(ctxt *obj.Link) {
 
        deferreturn = ctxt.Lookup("runtime.deferreturn")
 
-       symdiv = ctxt.Lookup("_div")
-       symdivu = ctxt.Lookup("_divu")
-       symmod = ctxt.Lookup("_mod")
-       symmodu = ctxt.Lookup("_modu")
+       symdiv = ctxt.Lookup("runtime._div")
+       symdivu = ctxt.Lookup("runtime._divu")
+       symmod = ctxt.Lookup("runtime._mod")
+       symmodu = ctxt.Lookup("runtime._modu")
 
        var n int
 
index 8519f4cbd56a2a6a4704411ae5d7e43e7a7a852f..726699d7206bee17fa221083352b8efad8ef2b41 100644 (file)
@@ -655,6 +655,10 @@ func sfloat2(pc uint32, regs *[15]uint32) uint32 {
 }
 
 // Stubs to pacify vet. Not safe to call from Go.
-// Calls to these functions are inserted by the compiler.
+// Calls to these functions are inserted by the compiler or assembler.
 func _sfloat()
 func udiv()
+func _div()
+func _divu()
+func _mod()
+func _modu()
index 7489a65071831bd795884a42032c1dec1014aed1..6a602ffbb89f0c402662fb97936352ac0ff560d4 100644 (file)
@@ -199,6 +199,118 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
 GLOBL fast_udiv_tab<>(SB), RODATA, $64
 
+// The linker will pass numerator in R8
+#define Rn R8
+// The linker expects the result in RTMP
+#define RTMP R11
+
+TEXT runtime·_divu(SB), NOSPLIT, $16-0
+       // It's not strictly true that there are no local pointers.
+       // It could be that the saved registers Rq, Rr, Rs, and Rm
+       // contain pointers. However, the only way this can matter
+       // is if the stack grows (which it can't, udiv is nosplit)
+       // or if a fault happens and more frames are added to
+       // the stack due to deferred functions.
+       // In the latter case, the stack can grow arbitrarily,
+       // and garbage collection can happen, and those
+       // operations care about pointers, but in that case
+       // the calling frame is dead, and so are the saved
+       // registers. So we can claim there are no pointers here.
+       NO_LOCAL_POINTERS
+       MOVW    Rq, 4(R13)
+       MOVW    Rr, 8(R13)
+       MOVW    Rs, 12(R13)
+       MOVW    RM, 16(R13)
+
+       MOVW    Rn, Rr                  /* numerator */
+       MOVW    g_m(g), Rq
+       MOVW    m_divmod(Rq), Rq        /* denominator */
+       BL      runtime·udiv(SB)
+       MOVW    Rq, RTMP
+       MOVW    4(R13), Rq
+       MOVW    8(R13), Rr
+       MOVW    12(R13), Rs
+       MOVW    16(R13), RM
+       RET
+
+TEXT runtime·_modu(SB), NOSPLIT, $16-0
+       NO_LOCAL_POINTERS
+       MOVW    Rq, 4(R13)
+       MOVW    Rr, 8(R13)
+       MOVW    Rs, 12(R13)
+       MOVW    RM, 16(R13)
+
+       MOVW    Rn, Rr                  /* numerator */
+       MOVW    g_m(g), Rq
+       MOVW    m_divmod(Rq), Rq        /* denominator */
+       BL      runtime·udiv(SB)
+       MOVW    Rr, RTMP
+       MOVW    4(R13), Rq
+       MOVW    8(R13), Rr
+       MOVW    12(R13), Rs
+       MOVW    16(R13), RM
+       RET
+
+TEXT runtime·_div(SB),NOSPLIT,$16-0
+       NO_LOCAL_POINTERS
+       MOVW    Rq, 4(R13)
+       MOVW    Rr, 8(R13)
+       MOVW    Rs, 12(R13)
+       MOVW    RM, 16(R13)
+       MOVW    Rn, Rr                  /* numerator */
+       MOVW    g_m(g), Rq
+       MOVW    m_divmod(Rq), Rq        /* denominator */
+       CMP     $0, Rr
+       BGE     d1
+       RSB     $0, Rr, Rr
+       CMP     $0, Rq
+       BGE     d2
+       RSB     $0, Rq, Rq
+d0:
+       BL      runtime·udiv(SB)       /* none/both neg */
+       MOVW    Rq, RTMP
+       B       out1
+d1:
+       CMP     $0, Rq
+       BGE     d0
+       RSB     $0, Rq, Rq
+d2:
+       BL      runtime·udiv(SB)       /* one neg */
+       RSB     $0, Rq, RTMP
+out1:
+       MOVW    4(R13), Rq
+       MOVW    8(R13), Rr
+       MOVW    12(R13), Rs
+       MOVW    16(R13), RM
+       RET
+
+TEXT runtime·_mod(SB),NOSPLIT,$16-0
+       NO_LOCAL_POINTERS
+       MOVW    Rq, 4(R13)
+       MOVW    Rr, 8(R13)
+       MOVW    Rs, 12(R13)
+       MOVW    RM, 16(R13)
+       MOVW    Rn, Rr                  /* numerator */
+       MOVW    g_m(g), Rq
+       MOVW    m_divmod(Rq), Rq        /* denominator */
+       CMP     $0, Rq
+       RSB.LT  $0, Rq, Rq
+       CMP     $0, Rr
+       BGE     m1
+       RSB     $0, Rr, Rr
+       BL      runtime·udiv(SB)       /* neg numerator */
+       RSB     $0, Rr, RTMP
+       B       out
+m1:
+       BL      runtime·udiv(SB)       /* pos numerator */
+       MOVW    Rr, RTMP
+out:
+       MOVW    4(R13), Rq
+       MOVW    8(R13), Rr
+       MOVW    12(R13), Rs
+       MOVW    16(R13), RM
+       RET
+
 // _mul64by32 and _div64by32 not implemented on arm
 TEXT runtime·_mul64by32(SB), NOSPLIT, $0
        MOVW    $0, R0
diff --git a/test/fixedbugs/issue19507.dir/div_arm.s b/test/fixedbugs/issue19507.dir/div_arm.s
new file mode 100644 (file)
index 0000000..f67c3bb
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2017 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.
+
+TEXT main·f(SB),0,$0-8
+       MOVW    x+0(FP), R1
+       MOVW    x+4(FP), R2
+       DIVU    R1, R2
+       DIV     R1, R2
+       MODU    R1, R2
+       MOD     R1, R2
+       RET
diff --git a/test/fixedbugs/issue19507.dir/main.go b/test/fixedbugs/issue19507.dir/main.go
new file mode 100644 (file)
index 0000000..c115556
--- /dev/null
@@ -0,0 +1,16 @@
+// +build arm
+
+// Copyright 2017 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.
+
+// Make sure we can compile assembly with DIV and MOD in it.
+// They get rewritten to runtime calls on GOARM=5.
+
+package main
+
+func f(x, y uint32)
+
+func main() {
+       f(5, 8)
+}
diff --git a/test/fixedbugs/issue19507.go b/test/fixedbugs/issue19507.go
new file mode 100644 (file)
index 0000000..543e17e
--- /dev/null
@@ -0,0 +1,8 @@
+// +build arm
+// builddir
+
+// Copyright 2017 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.
+
+package ignored
index dc86ab743891f0f3901d731930709e0af32321be..2fa206746bee56c0e102e43f30c0b1d4b08d8ddf 100644 (file)
@@ -480,7 +480,7 @@ func (t *test) run() {
                action = "rundir"
        case "cmpout":
                action = "run" // the run case already looks for <dir>/<test>.out files
-       case "compile", "compiledir", "build", "run", "buildrun", "runoutput", "rundir":
+       case "compile", "compiledir", "build", "builddir", "run", "buildrun", "runoutput", "rundir":
                // nothing to do
        case "errorcheckandrundir":
                wantError = false // should be no error if also will run
@@ -706,6 +706,63 @@ func (t *test) run() {
                        t.err = err
                }
 
+       case "builddir":
+               // Build an executable from all the .go and .s files in a subdirectory.
+               useTmp = true
+               longdir := filepath.Join(cwd, t.goDirName())
+               files, dirErr := ioutil.ReadDir(longdir)
+               if dirErr != nil {
+                       t.err = dirErr
+                       break
+               }
+               var gos []os.FileInfo
+               var asms []os.FileInfo
+               for _, file := range files {
+                       switch filepath.Ext(file.Name()) {
+                       case ".go":
+                               gos = append(gos, file)
+                       case ".s":
+                               asms = append(asms, file)
+                       }
+
+               }
+               var objs []string
+               cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", ".", "-o", "go.o"}
+               for _, file := range gos {
+                       cmd = append(cmd, filepath.Join(longdir, file.Name()))
+               }
+               _, err := runcmd(cmd...)
+               if err != nil {
+                       t.err = err
+                       break
+               }
+               objs = append(objs, "go.o")
+               if len(asms) > 0 {
+                       cmd = []string{"go", "tool", "asm", "-e", "-I", ".", "-o", "asm.o"}
+                       for _, file := range asms {
+                               cmd = append(cmd, filepath.Join(longdir, file.Name()))
+                       }
+                       _, err = runcmd(cmd...)
+                       if err != nil {
+                               t.err = err
+                               break
+                       }
+                       objs = append(objs, "asm.o")
+               }
+               cmd = []string{"go", "tool", "pack", "c", "all.a"}
+               cmd = append(cmd, objs...)
+               _, err = runcmd(cmd...)
+               if err != nil {
+                       t.err = err
+                       break
+               }
+               cmd = []string{"go", "tool", "link", "all.a"}
+               _, err = runcmd(cmd...)
+               if err != nil {
+                       t.err = err
+                       break
+               }
+
        case "buildrun": // build binary, then run binary, instead of go run. Useful for timeout tests where failure mode is infinite loop.
                // TODO: not supported on NaCl
                useTmp = true