1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:14:46 -07:00

cmd/compile: allow R11 to be allocated on s390x

R11 is only used as a temporary by a very small set of instructions
(DIV, MOD, MULH and extended MVC/XC instructions). By marking these
instructions as clobbering R11 we can allocate R11 in the general
case.

Change-Id: I0d4ffe80e57c164d42a5ea5ef6308756a5b0f742
Reviewed-on: https://go-review.googlesource.com/110255
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Michael Munday 2018-04-30 16:55:13 +01:00
parent d29ec40e19
commit 5d9c78201f
4 changed files with 406 additions and 408 deletions

View File

@ -110,12 +110,13 @@ func init() {
// Common individual register masks
var (
sp = buildReg("SP")
sb = buildReg("SB")
r0 = buildReg("R0")
sp = buildReg("SP")
sb = buildReg("SB")
r0 = buildReg("R0")
tmp = buildReg("R11") // R11 is used as a temporary in a small number of instructions.
// R10 and R11 are reserved by the assembler.
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14")
// R10 is reserved by the assembler.
gp = buildReg("R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14")
gpg = gp | buildReg("g")
gpsp = gp | sp
@ -135,11 +136,12 @@ func init() {
// Common regInfo
var (
gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp01 = regInfo{inputs: []regMask{}, outputs: gponly}
gp11 = regInfo{inputs: []regMask{gp}, outputs: gponly}
gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: gponly}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: gponly}
gp21sp = regInfo{inputs: []regMask{gpsp, gp}, outputs: gponly}
gp21tmp = regInfo{inputs: []regMask{gp &^ tmp, gp &^ tmp}, outputs: []regMask{gp &^ tmp}, clobbers: tmp}
// R0 evaluates to 0 when used as the number of bits to shift
// so we need to exclude it from that operand.
@ -255,19 +257,19 @@ func init() {
{name: "MULLDload", argLength: 3, reg: gpopload, asm: "MULLD", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem
{name: "MULLWload", argLength: 3, reg: gpopload, asm: "MULLW", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * *arg1. arg2=mem
{name: "MULHD", argLength: 2, reg: gp21, asm: "MULHD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
{name: "MULHDU", argLength: 2, reg: gp21, asm: "MULHDU", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
{name: "MULHD", argLength: 2, reg: gp21tmp, asm: "MULHD", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
{name: "MULHDU", argLength: 2, reg: gp21tmp, asm: "MULHDU", typ: "Int64", commutative: true, resultInArg0: true, clobberFlags: true}, // (arg0 * arg1) >> width
{name: "DIVD", argLength: 2, reg: gp21, asm: "DIVD", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVW", argLength: 2, reg: gp21, asm: "DIVW", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVDU", argLength: 2, reg: gp21, asm: "DIVDU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVWU", argLength: 2, reg: gp21, asm: "DIVWU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVD", argLength: 2, reg: gp21tmp, asm: "DIVD", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVW", argLength: 2, reg: gp21tmp, asm: "DIVW", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVDU", argLength: 2, reg: gp21tmp, asm: "DIVDU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "DIVWU", argLength: 2, reg: gp21tmp, asm: "DIVWU", resultInArg0: true, clobberFlags: true}, // arg0 / arg1
{name: "MODD", argLength: 2, reg: gp21, asm: "MODD", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODW", argLength: 2, reg: gp21, asm: "MODW", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODD", argLength: 2, reg: gp21tmp, asm: "MODD", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODW", argLength: 2, reg: gp21tmp, asm: "MODW", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODDU", argLength: 2, reg: gp21, asm: "MODDU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODWU", argLength: 2, reg: gp21, asm: "MODWU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODDU", argLength: 2, reg: gp21tmp, asm: "MODDU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "MODWU", argLength: 2, reg: gp21tmp, asm: "MODWU", resultInArg0: true, clobberFlags: true}, // arg0 % arg1
{name: "AND", argLength: 2, reg: gp21, asm: "AND", commutative: true, clobberFlags: true}, // arg0 & arg1
{name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW", commutative: true, clobberFlags: true}, // arg0 & arg1

File diff suppressed because it is too large Load Diff

View File

@ -589,7 +589,7 @@ func (s *regAllocState) init(f *Func) {
// in the rewrite rules so we always have a free register
// available for global load/stores. See gen/386.rules (search for Flag_shared).
case "s390x":
// nothing to do, R10 & R11 already reserved
s.allocatable &^= 1 << 11 // R11
default:
s.f.fe.Fatalf(src.NoXPos, "arch %s not implemented", s.f.Config.arch)
}

View File

@ -825,30 +825,29 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1
// gcWriteBarrier does NOT follow the Go ABI. It takes two arguments:
// - R2 is the destination of the write
// - R3 is the value being written at R2.
// It clobbers R10 and R11 (the linker temp registers).
// It clobbers R10 (the temp register).
// It does not clobber any other general-purpose registers,
// but may clobber others (e.g., floating point registers).
TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$88
TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$104
// Save the registers clobbered by the fast path.
MOVD R1, 80(R15)
MOVD R4, 88(R15)
MOVD R1, 96(R15)
MOVD R4, 104(R15)
MOVD g_m(g), R1
MOVD m_p(R1), R1
MOVD (p_wbBuf+wbBuf_next)(R1), R4
// Increment wbBuf.next position.
ADD $16, R4
MOVD $16, R4
ADD (p_wbBuf+wbBuf_next)(R1), R4
MOVD R4, (p_wbBuf+wbBuf_next)(R1)
MOVD (p_wbBuf+wbBuf_end)(R1), R1
MOVD R1, R10 // R10 is linker temp register
// Record the write.
MOVD R3, -16(R4) // Record value
MOVD (R2), R1 // TODO: This turns bad writes into bad reads.
MOVD R1, -8(R4) // Record *slot
MOVD R3, -16(R4) // Record value
MOVD (R2), R10 // TODO: This turns bad writes into bad reads.
MOVD R10, -8(R4) // Record *slot
// Is the buffer full?
CMPBEQ R4, R10, flush
CMPBEQ R4, R1, flush
ret:
MOVD 80(R15), R1
MOVD 88(R15), R4
MOVD 96(R15), R1
MOVD 104(R15), R4
// Do the write.
MOVD R3, (R2)
RET
@ -856,18 +855,11 @@ ret:
flush:
// Save all general purpose registers since these could be
// clobbered by wbBufFlush and were not saved by the caller.
MOVD R2, 8(R15) // Also first argument to wbBufFlush
MOVD R3, 16(R15) // Also second argument to wbBufFlush
STMG R2, R3, 8(R15) // set R2 and R3 as arguments for wbBufFlush
MOVD R0, 24(R15)
// R1 already saved.
// R4 already saved.
MOVD R5, 32(R15)
MOVD R6, 40(R15)
MOVD R7, 48(R15)
MOVD R8, 56(R15)
MOVD R9, 64(R15)
// R10 and R11 are linker temp registers.
MOVD R12, 72(R15)
STMG R5, R12, 32(R15) // save R5 - R12
// R13 is g.
// R14 is LR.
// R15 is SP.
@ -875,13 +867,7 @@ flush:
// This takes arguments R2 and R3.
CALL runtime·wbBufFlush(SB)
MOVD 8(R15), R2
MOVD 16(R15), R3
MOVD 24(R15), R0
MOVD 32(R15), R5
MOVD 40(R15), R6
MOVD 48(R15), R7
MOVD 56(R15), R8
MOVD 64(R15), R9
MOVD 72(R15), R12
LMG 8(R15), R2, R3 // restore R2 - R3
MOVD 24(R15), R0 // restore R0
LMG 32(R15), R5, R12 // restore R5 - R12
JMP ret