Commit 79d05e75 authored by Keith Randall's avatar Keith Randall Committed by Keith Randall

runtime: restore arm assembly stubs for div/mod

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/45703Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent 90b7058e
...@@ -1480,10 +1480,10 @@ func buildop(ctxt *obj.Link) { ...@@ -1480,10 +1480,10 @@ func buildop(ctxt *obj.Link) {
deferreturn = ctxt.Lookup("runtime.deferreturn") deferreturn = ctxt.Lookup("runtime.deferreturn")
symdiv = ctxt.Lookup("_div") symdiv = ctxt.Lookup("runtime._div")
symdivu = ctxt.Lookup("_divu") symdivu = ctxt.Lookup("runtime._divu")
symmod = ctxt.Lookup("_mod") symmod = ctxt.Lookup("runtime._mod")
symmodu = ctxt.Lookup("_modu") symmodu = ctxt.Lookup("runtime._modu")
var n int var n int
......
...@@ -655,6 +655,10 @@ func sfloat2(pc uint32, regs *[15]uint32) uint32 { ...@@ -655,6 +655,10 @@ func sfloat2(pc uint32, regs *[15]uint32) uint32 {
} }
// Stubs to pacify vet. Not safe to call from Go. // 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 _sfloat()
func udiv() func udiv()
func _div()
func _divu()
func _mod()
func _modu()
...@@ -199,6 +199,118 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788 ...@@ -199,6 +199,118 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
GLOBL fast_udiv_tab<>(SB), RODATA, $64 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 // _mul64by32 and _div64by32 not implemented on arm
TEXT runtime·_mul64by32(SB), NOSPLIT, $0 TEXT runtime·_mul64by32(SB), NOSPLIT, $0
MOVW $0, R0 MOVW $0, R0
......
// 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
// +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)
}
// +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
...@@ -480,7 +480,7 @@ func (t *test) run() { ...@@ -480,7 +480,7 @@ func (t *test) run() {
action = "rundir" action = "rundir"
case "cmpout": case "cmpout":
action = "run" // the run case already looks for <dir>/<test>.out files 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 // nothing to do
case "errorcheckandrundir": case "errorcheckandrundir":
wantError = false // should be no error if also will run wantError = false // should be no error if also will run
...@@ -706,6 +706,63 @@ func (t *test) run() { ...@@ -706,6 +706,63 @@ func (t *test) run() {
t.err = err 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. 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 // TODO: not supported on NaCl
useTmp = true useTmp = true
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment