]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: add async preemption support on S390X
authorCherry Zhang <cherryyz@google.com>
Wed, 30 Oct 2019 00:42:00 +0000 (20:42 -0400)
committerCherry Zhang <cherryyz@google.com>
Thu, 7 Nov 2019 20:45:45 +0000 (20:45 +0000)
This CL adds support of call injection and async preemption on
S390X.

Like ARM64, we need to clobber one register (REGTMP) for
returning from the injected call. Previous CLs have marked code
sequences that use REGTMP async-nonpreemtible.

Change-Id: I78adbc5fd70ca245da390f6266623385b45c9dfc
Reviewed-on: https://go-review.googlesource.com/c/go/+/204106
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/gen/S390XOps.go
src/runtime/mkpreempt.go
src/runtime/preempt_s390x.s
src/runtime/signal_linux_s390x.go

index 4adaeae24200f7e6e7d8deff87213cb05c7a0d0e..dc9d3286414fcb57bd47eb7273f0514454f94097 100644 (file)
@@ -83,6 +83,8 @@ var regNamesS390X = []string{
        "F14",
        "F15",
 
+       // If you add registers, update asyncPreempt in runtime.
+
        //pseudo-registers
        "SB",
 }
index 76637e8a01b4c4eed5658b1b599b225d7af7499f..2f022971fd77da81b13e02dbce6723cbd47000a4 100644 (file)
@@ -83,7 +83,7 @@ var arches = map[string]func(){
        "mips64x": notImplemented,
        "mipsx":   notImplemented,
        "ppc64x":  notImplemented,
-       "s390x":   notImplemented,
+       "s390x":   genS390X,
        "wasm":    genWasm,
 }
 var beLe = map[string]bool{"mips64x": true, "mipsx": true, "ppc64x": true}
@@ -356,6 +356,39 @@ func genARM64() {
        p("JMP (R27)")
 }
 
+func genS390X() {
+       // Add integer registers R0-R12
+       // R13 (g), R14 (LR), R15 (SP) are special, and not saved here.
+       // Saving R10 (REGTMP) is not necessary, but it is saved anyway.
+       var l = layout{sp: "R15", stack: 16} // add slot to save PC of interrupted instruction and flags
+       l.addSpecial(
+               "STMG R0, R12, %d(R15)",
+               "LMG %d(R15), R0, R12",
+               13*8)
+       // Add floating point registers F0-F31.
+       for i := 0; i <= 15; i++ {
+               reg := fmt.Sprintf("F%d", i)
+               l.add("FMOVD", reg, 8)
+       }
+
+       // allocate frame, save PC of interrupted instruction (in LR) and flags (condition code)
+       p("IPM R10") // save flags upfront, as ADD will clobber flags
+       p("MOVD R14, -%d(R15)", l.stack)
+       p("ADD $-%d, R15", l.stack)
+       p("MOVW R10, 8(R15)") // save flags
+
+       l.save()
+       p("CALL ·asyncPreempt2(SB)")
+       l.restore()
+
+       p("MOVD %d(R15), R14", l.stack)    // sigctxt.pushCall has pushed LR (at interrupt) on stack, restore it
+       p("ADD $%d, R15", l.stack+8)       // pop frame (including the space pushed by sigctxt.pushCall)
+       p("MOVWZ -%d(R15), R10", l.stack)  // load flags to REGTMP
+       p("TMLH R10, $(3<<12)")            // restore flags
+       p("MOVD -%d(R15), R10", l.stack+8) // load PC to REGTMP
+       p("JMP (R10)")
+}
+
 func genWasm() {
        p("// No async preemption on wasm")
        p("UNDEF")
index 5697268ce1612e5a8a0b19e4d86d4c924b8e63d4..ca9e47cde1791340c6df2b7ef2740ccb6fb6c225 100644 (file)
@@ -4,5 +4,48 @@
 #include "textflag.h"
 
 TEXT ·asyncPreempt(SB),NOSPLIT|NOFRAME,$0-0
-       // Not implemented yet
-       JMP ·abort(SB)
+       IPM R10
+       MOVD R14, -248(R15)
+       ADD $-248, R15
+       MOVW R10, 8(R15)
+       STMG R0, R12, 16(R15)
+       FMOVD F0, 120(R15)
+       FMOVD F1, 128(R15)
+       FMOVD F2, 136(R15)
+       FMOVD F3, 144(R15)
+       FMOVD F4, 152(R15)
+       FMOVD F5, 160(R15)
+       FMOVD F6, 168(R15)
+       FMOVD F7, 176(R15)
+       FMOVD F8, 184(R15)
+       FMOVD F9, 192(R15)
+       FMOVD F10, 200(R15)
+       FMOVD F11, 208(R15)
+       FMOVD F12, 216(R15)
+       FMOVD F13, 224(R15)
+       FMOVD F14, 232(R15)
+       FMOVD F15, 240(R15)
+       CALL ·asyncPreempt2(SB)
+       FMOVD 240(R15), F15
+       FMOVD 232(R15), F14
+       FMOVD 224(R15), F13
+       FMOVD 216(R15), F12
+       FMOVD 208(R15), F11
+       FMOVD 200(R15), F10
+       FMOVD 192(R15), F9
+       FMOVD 184(R15), F8
+       FMOVD 176(R15), F7
+       FMOVD 168(R15), F6
+       FMOVD 160(R15), F5
+       FMOVD 152(R15), F4
+       FMOVD 144(R15), F3
+       FMOVD 136(R15), F2
+       FMOVD 128(R15), F1
+       FMOVD 120(R15), F0
+       LMG 16(R15), R0, R12
+       MOVD 248(R15), R14
+       ADD $256, R15
+       MOVWZ -248(R15), R10
+       TMLH R10, $(3<<12)
+       MOVD -256(R15), R10
+       JMP (R10)
index 390ff5db48c22a0489eb51ca1619d5dcc0f16642..424dc59c9e8f2de69b19191b70e2e2f90fa3cd80 100644 (file)
@@ -110,8 +110,18 @@ func (c *sigctxt) preparePanic(sig uint32, gp *g) {
        c.set_pc(uint64(funcPC(sigpanic)))
 }
 
-const pushCallSupported = false
+const pushCallSupported = true
 
 func (c *sigctxt) pushCall(targetPC uintptr) {
-       throw("not implemented")
+       // Push the LR to stack, as we'll clobber it in order to
+       // push the call. The function being pushed is responsible
+       // for restoring the LR and setting the SP back.
+       // This extra slot is known to gentraceback.
+       sp := c.sp() - 8
+       c.set_sp(sp)
+       *(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+       // Set up PC and LR to pretend the function being signaled
+       // calls targetPC at the faulting PC.
+       c.set_link(c.pc())
+       c.set_pc(uint64(targetPC))
 }