[dev.simd] all: merge master (02d1f3a) into dev.simd

Merge List:

+ 2025-11-24 02d1f3a06b runtime: respect GOTRACEBACK for user-triggered runtime panics
+ 2025-11-24 a593ca9d65 runtime/cgo: add support for `any` param and return type
+ 2025-11-24 89552911b3 cmd/compile, internal/buildcfg: enable regABI on s390x, and add s390x
+ 2025-11-24 2fe0ba8d52 internal/bytealg: port bytealg functions to reg ABI on s390x
+ 2025-11-24 4529c8fba6 runtime: port memmove, memclr to register ABI on s390x
+ 2025-11-24 58a48a3e3b internal/runtime/syscall: Syscall changes for s390x regabi
+ 2025-11-24 2a185fae7e reflect, runtime: add reflect support for regabi on s390x
+ 2025-11-24 e92d2964fa runtime: mark race functions on s390x as ABIInternal
+ 2025-11-24 41af98eb83 runtime: add runtime changes for register ABI on s390x
+ 2025-11-24 85e6080089 cmd/internal/obj: set morestack arg spilling and regabi prologue on s390x
+ 2025-11-24 24697419c5 cmd/compile: update s390x CALL* ops
+ 2025-11-24 81242d034c cmd/compile/internal/s390x: add initial spill support
+ 2025-11-24 73b6aa0fec cmd/compile/internal: add register ABI information for s390x
+ 2025-11-24 1036f6f485 internal/abi: define s390x ABI constants
+ 2025-11-24 2e5d12a277 cmd/compile: document register-based ABI for s390x

Change-Id: I57b4ae6f9b65d99958b9fe5974205770e18f7788
This commit is contained in:
Cherry Mui 2025-11-24 15:29:27 -05:00
commit afd1721fc5
33 changed files with 715 additions and 251 deletions

View file

@ -1121,6 +1121,9 @@ func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
if t.Name == "error" {
return true
}
if t.Name == "any" {
return true
}
if goTypes[t.Name] != nil {
return false
}

View file

@ -106,6 +106,7 @@ func TestSetEnv(t *testing.T) { testSetEnv(t) }
func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
func TestUnsignedInt(t *testing.T) { testUnsignedInt(t) }
func TestZeroArgCallback(t *testing.T) { testZeroArgCallback(t) }
func Test76340(t *testing.T) { test76340(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
func BenchmarkGoString(b *testing.B) { benchGoString(b) }

View file

@ -959,6 +959,18 @@ char * const issue75751p = &issue75751v;
#define issue75751m issue75751p
char * const volatile issue75751p2 = &issue75751v;
#define issue75751m2 issue75751p2
typedef struct { void *t; void *v; } GoInterface;
extern int exportAny76340Param(GoInterface);
extern GoInterface exportAny76340Return(int);
int issue76340testFromC(GoInterface obj) {
return exportAny76340Param(obj);
}
GoInterface issue76340returnFromC(int val) {
return exportAny76340Return(val);
}
*/
import "C"
@ -2407,3 +2419,22 @@ func test69086(t *testing.T) {
func test75751() int {
return int(*C.issue75751m) + int(*C.issue75751m2)
}
// Issue 76340.
func test76340(t *testing.T) {
var emptyInterface C.GoInterface
r1 := C.issue76340testFromC(emptyInterface)
if r1 != 0 {
t.Errorf("issue76340testFromC with nil interface: got %d, want 0", r1)
}
r2 := C.issue76340returnFromC(42)
if r2.t == nil && r2.v == nil {
t.Error("issue76340returnFromC(42) returned nil interface")
}
r3 := C.issue76340returnFromC(0)
if r3.t != nil || r3.v != nil {
t.Errorf("issue76340returnFromC(0) returned non-nil interface: got %v, want nil", r3)
}
}

View file

@ -595,3 +595,21 @@ func test49633(t *testing.T) {
t.Errorf("msg = %q, want 'hello'", v.msg)
}
}
//export exportAny76340Param
func exportAny76340Param(obj any) C.int {
if obj == nil {
return 0
}
return 1
}
//export exportAny76340Return
func exportAny76340Return(val C.int) any {
if val == 0 {
return nil
}
return int(val)
}

View file

@ -1558,6 +1558,9 @@ func (p *Package) doCgoType(e ast.Expr, m map[ast.Expr]bool) *Type {
if t.Name == "error" {
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
}
if t.Name == "any" {
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
}
if r, ok := goTypes[t.Name]; ok {
return goTypesFixup(r)
}

View file

@ -833,6 +833,51 @@ The riscv64 has Zicsr extension for control and status register (CSR) and
treated as scratch register.
All bits in CSR are system flags and are not modified by Go.
### s390x architecture
The s390x architecture uses R2 R9 for integer arguments and integer results.
It uses F0 F15 for floating-point arguments and results.
Special-purpose registers used within Go generated code and Go assembly code
are as follows:
| Register | Call meaning | Return meaning | Body meaning |
| --- | --- | --- | --- |
| R0 | Zero value | Same | Same |
| R1 | Scratch | Scratch | Scratch |
| R10, R11 | used by the assembler | Same | Same |
| R12 | Closure context pointer | Same | Same |
| R13 | Current goroutine | Same | Same |
| R14 | Link register | Link register | Scratch |
| R15 | Stack pointer | Same | Same |
*Rationale*: These register meanings are compatible with Gos stack-based
calling convention.
#### Stack layout
The stack pointer, R15, grows down and is aligned to 8 bytes.
A function's stack frame, after the frame is created, is laid out as
follows:
+------------------------------+
| ... locals ... |
| ... outgoing arguments ... |
| return PC | ← R15 points to
+------------------------------+ ↓ lower addresses
This stack layout is used by both register-based (ABIInternal) and
stack-based (ABI0) calling conventions.
The "return PC" is loaded to the link register R14, as part of the
s390x `BL` operation.
#### Flags
The s390x architecture maintains a single condition code (CC) field in the Program Status Word (PSW).
Go-generated code sets and tests this condition code to control conditional branches.
## Future directions
### Spill path improvements

View file

@ -20,4 +20,6 @@ func Init(arch *ssagen.ArchInfo) {
arch.SSAMarkMoves = ssaMarkMoves
arch.SSAGenValue = ssaGenValue
arch.SSAGenBlock = ssaGenBlock
arch.LoadRegResult = loadRegResult
arch.SpillArgReg = spillArgReg
}

View file

@ -10,6 +10,7 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/objw"
"cmd/compile/internal/ssa"
"cmd/compile/internal/ssagen"
"cmd/compile/internal/types"
@ -540,6 +541,19 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
ssagen.AddrAuto(&p.To, v)
case ssa.OpArgIntReg, ssa.OpArgFloatReg:
// The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill
// The loop only runs once.
for _, a := range v.Block.Func.RegArgs {
// Pass the spill/unspill information along to the assembler, offset by size of
// the saved LR slot.
addr := ssagen.SpillSlotAddr(a, s390x.REGSP, base.Ctxt.Arch.FixedFrameSize)
s.FuncInfo().AddSpill(
obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)})
}
v.Block.Func.RegArgs = nil
ssagen.CheckArgReg(v)
case ssa.OpS390XLoweredGetClosurePtr:
// Closure pointer is R12 (already)
ssagen.CheckLoweredGetClosurePtr(v)
@ -1029,3 +1043,22 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
s.Br(s390x.ABR, succs[1])
}
}
func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
p := s.Prog(loadByType(t))
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_AUTO
p.From.Sym = n.Linksym()
p.From.Offset = n.FrameOffset() + off
p.To.Type = obj.TYPE_REG
p.To.Reg = reg
return p
}
func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog {
p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off)
p.To.Name = obj.NAME_PARAM
p.To.Sym = n.Linksym()
p.Pos = p.Pos.WithNotStmt()
return p
}

View file

@ -484,10 +484,10 @@ func init() {
{name: "CLEAR", argLength: 2, reg: regInfo{inputs: []regMask{ptr, 0}}, asm: "CLEAR", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Write"},
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
{name: "CALLtail", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). arg0=mem, auxint=argsize, returns mem
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
{name: "CALLstatic", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
{name: "CALLtail", argLength: -1, reg: regInfo{clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true, tailCall: true}, // tail call static function aux.(*obj.LSym). last arg=mem, auxint=argsize, returns mem
{name: "CALLclosure", argLength: -1, reg: regInfo{inputs: []regMask{ptrsp, buildReg("R12"), 0}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem
{name: "CALLinter", argLength: -1, reg: regInfo{inputs: []regMask{ptr}, clobbers: callerSave}, aux: "CallOff", clobberFlags: true, call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem
// (InvertFlags (CMP a b)) == (CMP b a)
// InvertFlags is a pseudo-op which can't appear in assembly output.
@ -812,16 +812,18 @@ func init() {
}
archs = append(archs, arch{
name: "S390X",
pkg: "cmd/internal/obj/s390x",
genfile: "../../s390x/ssa.go",
ops: S390Xops,
blocks: S390Xblocks,
regnames: regNamesS390X,
gpregmask: gp,
fpregmask: fp,
framepointerreg: -1, // not used
linkreg: int8(num["R14"]),
name: "S390X",
pkg: "cmd/internal/obj/s390x",
genfile: "../../s390x/ssa.go",
ops: S390Xops,
blocks: S390Xblocks,
regnames: regNamesS390X,
ParamIntRegNames: "R2 R3 R4 R5 R6 R7 R8 R9",
ParamFloatRegNames: "F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15",
gpregmask: gp,
fpregmask: fp,
framepointerreg: -1, // not used
linkreg: int8(num["R14"]),
imports: []string{
"cmd/internal/obj/s390x",
},

View file

@ -313,6 +313,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo
c.registers = registersS390X[:]
c.gpRegMask = gpRegMaskS390X
c.fpRegMask = fpRegMaskS390X
c.intParamRegs = paramIntRegS390X
c.floatParamRegs = paramFloatRegS390X
c.FPReg = framepointerRegS390X
c.LinkReg = linkRegS390X
c.hasGReg = true

View file

@ -45,7 +45,7 @@ func testGoArch() string {
func hasRegisterABI() bool {
switch testGoArch() {
case "amd64", "arm64", "loong64", "ppc64", "ppc64le", "riscv":
case "amd64", "arm64", "loong64", "ppc64", "ppc64le", "riscv", "s390x":
return true
}
return false

View file

@ -81087,7 +81087,7 @@ var opcodeTable = [...]opInfo{
{
name: "CALLstatic",
auxType: auxCallOff,
argLen: 1,
argLen: -1,
clobberFlags: true,
call: true,
reg: regInfo{
@ -81097,7 +81097,7 @@ var opcodeTable = [...]opInfo{
{
name: "CALLtail",
auxType: auxCallOff,
argLen: 1,
argLen: -1,
clobberFlags: true,
call: true,
tailCall: true,
@ -81108,7 +81108,7 @@ var opcodeTable = [...]opInfo{
{
name: "CALLclosure",
auxType: auxCallOff,
argLen: 3,
argLen: -1,
clobberFlags: true,
call: true,
reg: regInfo{
@ -81122,7 +81122,7 @@ var opcodeTable = [...]opInfo{
{
name: "CALLinter",
auxType: auxCallOff,
argLen: 2,
argLen: -1,
clobberFlags: true,
call: true,
reg: regInfo{
@ -93219,8 +93219,8 @@ var registersS390X = [...]Register{
{31, s390x.REG_F15, "F15"},
{32, 0, "SB"},
}
var paramIntRegS390X = []int8(nil)
var paramFloatRegS390X = []int8(nil)
var paramIntRegS390X = []int8{2, 3, 4, 5, 6, 7, 8, 9}
var paramFloatRegS390X = []int8{16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}
var gpRegMaskS390X = regMask(23551)
var fpRegMaskS390X = regMask(4294901760)
var specialRegMaskS390X = regMask(0)

View file

@ -139,8 +139,8 @@ const (
REG_RESERVED // end of allocated registers
REGARG = -1 // -1 disables passing the first argument in register
REGRT1 = REG_R3 // used during zeroing of the stack - not reserved
REGRT2 = REG_R4 // used during zeroing of the stack - not reserved
REGRT1 = REG_R1 // used during zeroing of the stack - not reserved
REGRT2 = REG_R10 // used during zeroing of the stack - not reserved
REGTMP = REG_R10 // scratch register used in the assembler and linker
REGTMP2 = REG_R11 // scratch register used in the assembler and linker
REGCTXT = REG_R12 // context for closures

View file

@ -506,7 +506,13 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCh
// Save LR and REGCTXT
const frameSize = 16
p = c.ctxt.StartUnsafePoint(p, c.newprog)
// Spill arguments. This has to happen before we open
// any more frame space.
p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
// MOVD LR, -16(SP)
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
@ -549,10 +555,12 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCh
p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
p.Spadj = -frameSize
// Unspill arguments
p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
}
// MOVD g_stackguard(g), R3
// MOVD g_stackguard(g), R10
p = obj.Appendp(p, c.newprog)
// Jump back to here after morestack returns.
pCheck = p
@ -565,7 +573,7 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCh
p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
}
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R3
p.To.Reg = REG_R10
// Mark the stack bound check and morestack call async nonpreemptible.
// If we get preempted here, when resumed the preemption request is
@ -579,7 +587,7 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCh
p = obj.Appendp(p, c.newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.From.Reg = REG_R10
p.Reg = REGSP
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
@ -598,40 +606,40 @@ func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCh
// stack guard to incorrectly succeed. We explicitly
// guard against underflow.
//
// MOVD $(framesize-StackSmall), R4
// CMPUBLT SP, R4, label-of-call-to-morestack
// MOVD $(framesize-StackSmall), R11
// CMPUBLT SP, R11, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_CONST
p.From.Offset = offset
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p.To.Reg = REG_R11
p = obj.Appendp(p, c.newprog)
pPreempt = p
p.As = ACMPUBLT
p.From.Type = obj.TYPE_REG
p.From.Reg = REGSP
p.Reg = REG_R4
p.Reg = REG_R11
p.To.Type = obj.TYPE_BRANCH
}
// Check against the stack guard. We've ensured this won't underflow.
// ADD $-(framesize-StackSmall), SP, R4
// CMPUBGE stackguard, R4, label-of-call-to-morestack
// ADD $-(framesize-StackSmall), SP, R11
// CMPUBGE stackguard, R11, label-of-call-to-morestack
p = obj.Appendp(p, c.newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = -offset
p.Reg = REGSP
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4
p.To.Reg = REG_R11
p = obj.Appendp(p, c.newprog)
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_R3
p.Reg = REG_R4
p.From.Reg = REG_R10
p.Reg = REG_R11
p.As = ACMPUBGE
p.To.Type = obj.TYPE_BRANCH
@ -654,18 +662,22 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, fr
pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
if pPreempt != nil {
pPreempt.To.SetTarget(pcdata)
}
pPre.To.SetTarget(pcdata)
// Spill the register args that could be clobbered by the
// morestack code.
spill := c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
// MOVD LR, R5
p = obj.Appendp(pcdata, c.newprog)
pPre.To.SetTarget(p)
p = obj.Appendp(spill, c.newprog)
p.As = AMOVD
p.From.Type = obj.TYPE_REG
p.From.Reg = REG_LR
p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R5
if pPreempt != nil {
pPreempt.To.SetTarget(p)
}
// BL runtime.morestack(SB)
p = obj.Appendp(p, c.newprog)
@ -680,10 +692,12 @@ func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, fr
p.To.Sym = c.ctxt.Lookup("runtime.morestack")
}
// The instructions which unspill regs should be preemptible.
p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
// BR pCheck
p = obj.Appendp(p, c.newprog)
p = obj.Appendp(unspill, c.newprog)
p.As = ABR
p.To.Type = obj.TYPE_BRANCH

View file

@ -0,0 +1,19 @@
// Copyright 2025 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.
//go:build goexperiment.regabiargs
package abi
const (
// See abi_generic.go.
// R2 - R9.
IntArgRegs = 8
// F0 - F15
FloatArgRegs = 16
EffectiveFloatRegSize = 8
)

View file

@ -65,6 +65,8 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) {
case "amd64", "arm64", "loong64", "ppc64le", "ppc64", "riscv64":
regabiAlwaysOn = true
regabiSupported = true
case "s390x":
regabiSupported = true
}
// Older versions (anything before V16) of dsymutil don't handle
@ -141,7 +143,7 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) {
flags.RegabiWrappers = true
flags.RegabiArgs = true
}
// regabi is only supported on amd64, arm64, loong64, riscv64, ppc64 and ppc64le.
// regabi is only supported on amd64, arm64, loong64, riscv64, s390x, ppc64 and ppc64le.
if !regabiSupported {
flags.RegabiWrappers = false
flags.RegabiArgs = false

View file

@ -5,65 +5,93 @@
#include "go_asm.h"
#include "textflag.h"
TEXT ·Compare(SB),NOSPLIT|NOFRAME,$0-56
MOVD a_base+0(FP), R3
MOVD a_len+8(FP), R4
MOVD b_base+24(FP), R5
MOVD b_len+32(FP), R6
LA ret+48(FP), R7
TEXT ·Compare<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-56
#ifndef GOEXPERIMENT_regabiargs
MOVD a_base+0(FP), R2
MOVD a_len+8(FP), R3
MOVD b_base+24(FP), R4
MOVD b_len+32(FP), R5
LA ret+48(FP), R6
#else
// R2 = a_base
// R3 = a_len
// R4 = a_cap (unused)
// R5 = b_base (want in R4)
// R6 = b_len (want in R5)
// R7 = b_cap (unused)
MOVD R5, R4
MOVD R6, R5
#endif
BR cmpbody<>(SB)
TEXT runtime·cmpstring(SB),NOSPLIT|NOFRAME,$0-40
MOVD a_base+0(FP), R3
MOVD a_len+8(FP), R4
MOVD b_base+16(FP), R5
MOVD b_len+24(FP), R6
LA ret+32(FP), R7
TEXT runtime·cmpstring<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
#ifndef GOEXPERIMENT_regabiargs
MOVD a_base+0(FP), R2
MOVD a_len+8(FP), R3
MOVD b_base+16(FP), R4
MOVD b_len+24(FP), R5
LA ret+32(FP), R6
#endif
// R2 = a_base
// R3 = a_len
// R4 = b_base
// R5 = b_len
BR cmpbody<>(SB)
// input:
// R3 = a
// R4 = alen
// R5 = b
// R6 = blen
// R7 = address of output word (stores -1/0/1 here)
// R2 = a
// R3 = alen
// R4 = b
// R5 = blen
// For regabiargs output value( -1/0/1 ) stored in R2
// For !regabiargs address of output word( stores -1/0/1 ) stored in R6
TEXT cmpbody<>(SB),NOSPLIT|NOFRAME,$0-0
CMPBEQ R3, R5, cmplengths
MOVD R4, R8
CMPBLE R4, R6, amin
MOVD R6, R8
CMPBEQ R2, R4, cmplengths
MOVD R3, R7
CMPBLE R3, R5, amin
MOVD R5, R7
amin:
CMPBEQ R8, $0, cmplengths
CMP R8, $256
CMPBEQ R7, $0, cmplengths
CMP R7, $256
BLE tail
loop:
CLC $256, 0(R3), 0(R5)
CLC $256, 0(R2), 0(R4)
BGT gt
BLT lt
SUB $256, R8
MOVD $256(R3), R3
MOVD $256(R5), R5
CMP R8, $256
SUB $256, R7
MOVD $256(R2), R2
MOVD $256(R4), R4
CMP R7, $256
BGT loop
tail:
SUB $1, R8
EXRL $cmpbodyclc<>(SB), R8
SUB $1, R7
EXRL $cmpbodyclc<>(SB), R7
BGT gt
BLT lt
cmplengths:
CMP R4, R6
CMP R3, R5
BEQ eq
BLT lt
gt:
MOVD $1, 0(R7)
MOVD $1, R2
#ifndef GOEXPERIMENT_regabiargs
MOVD R2, 0(R6)
#endif
RET
lt:
MOVD $-1, 0(R7)
MOVD $-1, R2
#ifndef GOEXPERIMENT_regabiargs
MOVD R2, 0(R6)
#endif
RET
eq:
MOVD $0, 0(R7)
MOVD $0, R2
#ifndef GOEXPERIMENT_regabiargs
MOVD R2, 0(R6)
#endif
RET
TEXT cmpbodyclc<>(SB),NOSPLIT|NOFRAME,$0-0
CLC $1, 0(R3), 0(R5)
CLC $1, 0(R2), 0(R4)
RET

View file

@ -6,80 +6,92 @@
#include "textflag.h"
// memequal(a, b unsafe.Pointer, size uintptr) bool
TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25
MOVD a+0(FP), R3
MOVD b+8(FP), R5
MOVD size+16(FP), R6
LA ret+24(FP), R7
TEXT runtime·memequal<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-25
#ifndef GOEXPERIMENT_regabiargs
MOVD a+0(FP), R2
MOVD b+8(FP), R3
MOVD size+16(FP), R4
LA ret+24(FP), R5
#endif
BR memeqbody<>(SB)
// memequal_varlen(a, b unsafe.Pointer) bool
TEXT runtime·memequal_varlen(SB),NOSPLIT|NOFRAME,$0-17
MOVD a+0(FP), R3
MOVD b+8(FP), R5
MOVD 8(R12), R6 // compiler stores size at offset 8 in the closure
LA ret+16(FP), R7
TEXT runtime·memequal_varlen<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-17
#ifndef GOEXPERIMENT_regabiargs
MOVD a+0(FP), R2
MOVD b+8(FP), R3
LA ret+16(FP), R5
#endif
MOVD 8(R12), R4 // compiler stores size at offset 8 in the closure
BR memeqbody<>(SB)
// input:
// R3 = a
// R5 = b
// R6 = len
// R7 = address of output byte (stores 0 or 1 here)
// R2 = a
// R3 = b
// R4 = len
// For regabiargs output value( 0/1 ) stored in R2
// For !regabiargs address of output byte( stores 0/1 ) stored in R5
// a and b have the same length
TEXT memeqbody<>(SB),NOSPLIT|NOFRAME,$0-0
CMPBEQ R3, R5, equal
CMPBEQ R2, R3, equal
loop:
CMPBEQ R6, $0, equal
CMPBLT R6, $32, tiny
CMP R6, $256
CMPBEQ R4, $0, equal
CMPBLT R4, $32, tiny
CMP R4, $256
BLT tail
CLC $256, 0(R3), 0(R5)
CLC $256, 0(R2), 0(R3)
BNE notequal
SUB $256, R6
SUB $256, R4
LA 256(R2), R2
LA 256(R3), R3
LA 256(R5), R5
BR loop
tail:
SUB $1, R6, R8
SUB $1, R4, R8
EXRL $memeqbodyclc<>(SB), R8
BEQ equal
notequal:
MOVB $0, 0(R7)
MOVD $0, R2
#ifndef GOEXPERIMENT_regabiargs
MOVB R2, 0(R5)
#endif
RET
equal:
MOVB $1, 0(R7)
MOVD $1, R2
#ifndef GOEXPERIMENT_regabiargs
MOVB R2, 0(R5)
#endif
RET
tiny:
MOVD $0, R2
CMPBLT R6, $16, lt16
MOVD 0(R3), R8
MOVD 0(R5), R9
MOVD $0, R1
CMPBLT R4, $16, lt16
MOVD 0(R2), R8
MOVD 0(R3), R9
CMPBNE R8, R9, notequal
MOVD 8(R3), R8
MOVD 8(R5), R9
MOVD 8(R2), R8
MOVD 8(R3), R9
CMPBNE R8, R9, notequal
LA 16(R2), R2
SUB $16, R6
LA 16(R1), R1
SUB $16, R4
lt16:
CMPBLT R6, $8, lt8
MOVD 0(R3)(R2*1), R8
MOVD 0(R5)(R2*1), R9
CMPBLT R4, $8, lt8
MOVD 0(R2)(R1*1), R8
MOVD 0(R3)(R1*1), R9
CMPBNE R8, R9, notequal
LA 8(R2), R2
SUB $8, R6
LA 8(R1), R1
SUB $8, R4
lt8:
CMPBLT R6, $4, lt4
MOVWZ 0(R3)(R2*1), R8
MOVWZ 0(R5)(R2*1), R9
CMPBLT R4, $4, lt4
MOVWZ 0(R2)(R1*1), R8
MOVWZ 0(R3)(R1*1), R9
CMPBNE R8, R9, notequal
LA 4(R2), R2
SUB $4, R6
LA 4(R1), R1
SUB $4, R4
lt4:
#define CHECK(n) \
CMPBEQ R6, $n, equal \
MOVB n(R3)(R2*1), R8 \
MOVB n(R5)(R2*1), R9 \
CMPBEQ R4, $n, equal \
MOVB n(R2)(R1*1), R8 \
MOVB n(R3)(R1*1), R9 \
CMPBNE R8, R9, notequal
CHECK(0)
CHECK(1)
@ -88,5 +100,5 @@ lt4:
BR equal
TEXT memeqbodyclc<>(SB),NOSPLIT|NOFRAME,$0-0
CLC $1, 0(R3), 0(R5)
CLC $1, 0(R2), 0(R3)
RET

View file

@ -5,104 +5,134 @@
#include "go_asm.h"
#include "textflag.h"
TEXT ·IndexByte(SB),NOSPLIT|NOFRAME,$0-40
MOVD b_base+0(FP), R3// b_base => R3
MOVD b_len+8(FP), R4 // b_len => R4
MOVBZ c+24(FP), R5 // c => R5
MOVD $ret+32(FP), R2 // &ret => R9
BR indexbytebody<>(SB)
TEXT ·IndexByteString(SB),NOSPLIT|NOFRAME,$0-32
MOVD s_base+0(FP), R3// s_base => R3
MOVD s_len+8(FP), R4 // s_len => R4
MOVBZ c+16(FP), R5 // c => R5
MOVD $ret+24(FP), R2 // &ret => R9
BR indexbytebody<>(SB)
TEXT ·IndexByte<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-40
#ifndef GOEXPERIMENT_regabiargs
MOVD b_base+0(FP), R2// b_base => R2
MOVD b_len+8(FP), R3 // b_len => R3
MOVBZ c+24(FP), R4 // c => R4
MOVD $ret+32(FP), R5 // &ret => R5
#else
MOVD R5, R4
AND $0xff, R4
#endif
BR indexbytebody<>(SB)
TEXT ·IndexByteString<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-32
#ifndef GOEXPERIMENT_regabiargs
MOVD s_base+0(FP), R2 // s_base => R2
MOVD s_len+8(FP), R3 // s_len => R3
MOVBZ c+16(FP), R4 // c => R4
MOVD $ret+24(FP), R5 // &ret => R5
#else
AND $0xff, R4
#endif
BR indexbytebody<>(SB)
// input:
// R3: s
// R4: s_len
// R5: c -- byte sought
// R2: &ret -- address to put index into
// R2: s
// R3: s_len
// R4: c -- byte sought
// For regabiargs output value(index) stored in R2
// For !regabiargs address of output value(index) stored in R5
TEXT indexbytebody<>(SB),NOSPLIT|NOFRAME,$0
CMPBEQ R4, $0, notfound
MOVD R3, R6 // store base for later
ADD R3, R4, R8 // the address after the end of the string
//if the length is small, use loop; otherwise, use vector or srst search
CMPBGE R4, $16, large
CMPBEQ R3, $0, notfound
MOVD R2, R6 // store base for later
ADD R2, R3, R8 // the address after the end of the string
//if the length is small, use loop; otherwise, use vector or srst search
CMPBGE R3, $16, large
residual:
CMPBEQ R3, R8, notfound
MOVBZ 0(R3), R7
LA 1(R3), R3
CMPBNE R7, R5, residual
CMPBEQ R2, R8, notfound
MOVBZ 0(R2), R7
LA 1(R2), R2
CMPBNE R7, R4, residual
found:
SUB R6, R3
SUB $1, R3
MOVD R3, 0(R2)
RET
SUB R6, R2
SUB $1, R2
#ifndef GOEXPERIMENT_regabiargs
MOVD R2, 0(R5)
#endif
RET
notfound:
MOVD $-1, 0(R2)
RET
#ifndef GOEXPERIMENT_regabiargs
MOVD $-1, 0(R5)
#else
MOVD $-1, R2
#endif
RET
large:
MOVBZ internalcpu·S390X+const_offsetS390xHasVX(SB), R1
CMPBNE R1, $0, vectorimpl
MOVBZ internalcpu·S390X+const_offsetS390xHasVX(SB), R1
CMPBNE R1, $0, vectorimpl
srstimpl: // no vector facility
MOVBZ R5, R0 // c needs to be in R0, leave until last minute as currently R0 is expected to be 0
MOVBZ R4, R0 // c needs to be in R0, leave until last minute as currently R0 is expected to be 0
srstloop:
WORD $0xB25E0083 // srst %r8, %r3 (search the range [R3, R8))
BVS srstloop // interrupted - continue
BGT notfoundr0
WORD $0xB25E0082 // srst %r8, %r2 (search the range [R2, R8))
BVS srstloop // interrupted - continue
BGT notfoundr0
foundr0:
XOR R0, R0 // reset R0
SUB R6, R8 // remove base
MOVD R8, 0(R2)
RET
XOR R0, R0 // reset R0
SUB R6, R8 // remove base
#ifndef GOEXPERIMENT_regabiargs
MOVD R8, 0(R5)
#else
MOVD R8, R2
#endif
RET
notfoundr0:
XOR R0, R0 // reset R0
MOVD $-1, 0(R2)
RET
XOR R0, R0 // reset R0
#ifndef GOEXPERIMENT_regabiargs
MOVD $-1, 0(R5)
#else
MOVD $-1, R2
#endif
RET
vectorimpl:
//if the address is not 16byte aligned, use loop for the header
MOVD R3, R8
AND $15, R8
CMPBGT R8, $0, notaligned
//if the address is not 16byte aligned, use loop for the header
MOVD R2, R8
AND $15, R8
CMPBGT R8, $0, notaligned
aligned:
ADD R6, R4, R8
MOVD R8, R7
AND $-16, R7
// replicate c across V17
VLVGB $0, R5, V19
VREPB $0, V19, V17
ADD R6, R3, R8
MOVD R8, R7
AND $-16, R7
// replicate c across V17
VLVGB $0, R4, V19
VREPB $0, V19, V17
vectorloop:
CMPBGE R3, R7, residual
VL 0(R3), V16 // load string to be searched into V16
ADD $16, R3
VFEEBS V16, V17, V18 // search V17 in V16 and set conditional code accordingly
BVS vectorloop
CMPBGE R2, R7, residual
VL 0(R2), V16 // load string to be searched into V16
ADD $16, R2
VFEEBS V16, V17, V18 // search V17 in V16 and set conditional code accordingly
BVS vectorloop
// when vector search found c in the string
VLGVB $7, V18, R7 // load 7th element of V18 containing index into R7
SUB $16, R3
SUB R6, R3
ADD R3, R7
MOVD R7, 0(R2)
RET
// when vector search found c in the string
VLGVB $7, V18, R7 // load 7th element of V18 containing index into R7
SUB $16, R2
SUB R6, R2
ADD R2, R7
#ifndef GOEXPERIMENT_regabiargs
MOVD R7, 0(R5)
#else
MOVD R7, R2
#endif
RET
notaligned:
MOVD R3, R8
AND $-16, R8
ADD $16, R8
MOVD R2, R8
AND $-16, R8
ADD $16, R8
notalignedloop:
CMPBEQ R3, R8, aligned
MOVBZ 0(R3), R7
LA 1(R3), R3
CMPBNE R7, R5, notalignedloop
BR found
CMPBEQ R2, R8, aligned
MOVBZ 0(R2), R7
LA 1(R2), R2
CMPBNE R7, R4, notalignedloop
BR found

View file

@ -5,7 +5,16 @@
#include "textflag.h"
// func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
TEXT ·Syscall6<ABIInternal>(SB),NOSPLIT,$0-80
#ifdef GOEXPERIMENT_regabiargs
MOVD R2, R1
MOVD R3, R2
MOVD R4, R3
MOVD R5, R4
MOVD R6, R5
MOVD R7, R6
MOVD R8, R7
#else
MOVD num+0(FP), R1 // syscall entry
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
@ -13,16 +22,27 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-80
MOVD a4+32(FP), R5
MOVD a5+40(FP), R6
MOVD a6+48(FP), R7
#endif
SYSCALL
MOVD $0xfffffffffffff001, R8
CMPUBLT R2, R8, ok
#ifdef GOEXPERIMENT_regabiargs
MOVD $0, R3
NEG R2, R4
MOVD $-1, R2
#else
MOVD $-1, r1+56(FP)
MOVD $0, r2+64(FP)
NEG R2, R2
MOVD R2, errno+72(FP)
#endif
RET
ok:
#ifdef GOEXPERIMENT_regabiargs
MOVD $0, R4
#else
MOVD R2, r1+56(FP)
MOVD R3, r2+64(FP)
MOVD $0, errno+72(FP)
#endif
RET

View file

@ -5,34 +5,82 @@
#include "textflag.h"
#include "funcdata.h"
// The frames of each of the two functions below contain two locals, at offsets
// that are known to the runtime.
//
// The first local is a bool called retValid with a whole pointer-word reserved
// for it on the stack. The purpose of this word is so that the runtime knows
// whether the stack-allocated return space contains valid values for stack
// scanning.
//
// The second local is an abi.RegArgs value whose offset is also known to the
// runtime, so that a stack map for it can be constructed, since it contains
// pointers visible to the GC.
#define LOCAL_RETVALID 40
#define LOCAL_REGARGS 48
// The frame size of the functions below is
// 32 (args of callReflect/callMethod) + 8 (bool + padding) + 264 (abi.RegArgs) = 304.
// makeFuncStub is the code half of the function returned by MakeFunc.
// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
// No arg size here, runtime pulls arg map out of the func value.
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$304
NO_LOCAL_POINTERS
ADD $LOCAL_REGARGS, R15, R10 // spillArgs using R10
BL runtime·spillArgs(SB)
MOVD R12, 32(R15) // save context reg R12 > args of moveMakeFuncArgPtrs < LOCAL_REGARGS
#ifdef GOEXPERIMENT_regabiargs
MOVD R12, R2
MOVD R10, R3
#else
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
MOVB $0, 40(R15)
ADD $40, R15, R3
MOVD R3, 24(R15)
MOVD $0, 32(R15)
MOVD R10, 16(R15)
#endif
BL ·moveMakeFuncArgPtrs<ABIInternal>(SB)
MOVD 32(R15), R12 // restore context reg R12
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R1
MOVD R1, 16(R15)
MOVB $0, LOCAL_RETVALID(R15)
ADD $LOCAL_RETVALID, R15, R1
MOVD R1, 24(R15)
ADD $LOCAL_REGARGS, R15, R1
MOVD R1, 32(R15)
BL ·callReflect(SB)
ADD $LOCAL_REGARGS, R15, R10 // unspillArgs using R10
BL runtime·unspillArgs(SB)
RET
// methodValueCall is the code half of the function returned by makeMethodValue.
// See the comment on the declaration of methodValueCall in makefunc.go
// for more details.
// No arg size here; runtime pulls arg map out of the func value.
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$40
TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$304
NO_LOCAL_POINTERS
ADD $LOCAL_REGARGS, R15, R10 // spillArgs using R10
BL runtime·spillArgs(SB)
MOVD R12, 32(R15) // save context reg R12 > args of moveMakeFuncArgPtrs < LOCAL_REGARGS
#ifdef GOEXPERIMENT_regabiargs
MOVD R12, R2
MOVD R10, R3
#else
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R3
MOVD R3, 16(R15)
MOVB $0, 40(R15)
ADD $40, R15, R3
MOVD R3, 24(R15)
MOVD $0, 32(R15)
MOVD R10, 16(R15)
#endif
BL ·moveMakeFuncArgPtrs<ABIInternal>(SB)
MOVD 32(R15), R12 // restore context reg R12
MOVD R12, 8(R15)
MOVD $argframe+0(FP), R1
MOVD R1, 16(R15)
MOVB $0, LOCAL_RETVALID(R15)
ADD $LOCAL_RETVALID, R15, R1
MOVD R1, 24(R15)
ADD $LOCAL_REGARGS, R15, R1
MOVD R1, 32(R15)
BL ·callMethod(SB)
ADD $LOCAL_REGARGS, R15, R10 // unspillArgs using R10
BL runtime·unspillArgs(SB)
RET

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !ppc64 && !ppc64le && !riscv64
//go:build !ppc64 && !ppc64le && !riscv64 && !s390x
package reflect

View file

@ -0,0 +1,30 @@
// Copyright 2025 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.
//go:build s390x
#include "textflag.h"
// On s390x, the float32 becomes a float64
// when loaded in a register, different from
// other platforms. These functions are
// needed to ensure correct conversions on s390x.
// Convert float32->uint64
TEXT ·archFloat32ToReg(SB),NOSPLIT,$0-16
FMOVS val+0(FP), F1
FMOVD F1, ret+8(FP)
RET
// Convert uint64->float32
TEXT ·archFloat32FromReg(SB),NOSPLIT,$0-12
FMOVD reg+0(FP), F1
// Normally a float64->float32 conversion
// would need rounding, but that is not needed
// here since the uint64 was originally converted
// from float32, and should be avoided to
// preserve SNaN values.
FMOVS F1, ret+8(FP)
RET

View file

@ -0,0 +1,10 @@
// Copyright 2025 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.
//go:build s390x
package reflect
func archFloat32FromReg(reg uint64) float32
func archFloat32ToReg(val float32) uint64

View file

@ -160,7 +160,7 @@ nocgo:
MOVD $0, 1(R0)
RET
DATA runtime·mainPC+0(SB)/8,$runtime·main(SB)
DATA runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB)
GLOBL runtime·mainPC(SB),RODATA,$8
TEXT runtime·breakpoint(SB),NOSPLIT|NOFRAME,$0-0
@ -205,25 +205,29 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
// Switch to m->g0's stack, call fn(g).
// Fn must never return. It should gogo(&g->sched)
// to keep running g.
TEXT runtime·mcall(SB), NOSPLIT, $-8-8
TEXT runtime·mcall<ABIInternal>(SB), NOSPLIT, $-8-8
#ifdef GOEXPERIMENT_regabiargs
MOVD R2, R12 // context
#else
MOVD fn+0(FP), R12 // context
#endif
// Save caller state in g->sched
MOVD R15, (g_sched+gobuf_sp)(g)
MOVD LR, (g_sched+gobuf_pc)(g)
MOVD $0, (g_sched+gobuf_lr)(g)
// Switch to m->g0 & its stack, call fn.
MOVD g, R3
MOVD g_m(g), R8
MOVD m_g0(R8), g
MOVD g, R2
MOVD g_m(g), R4
MOVD m_g0(R4), g
BL runtime·save_g(SB)
CMP g, R3
CMP g, R2
BNE 2(PC)
BR runtime·badmcall(SB)
MOVD fn+0(FP), R12 // context
MOVD 0(R12), R4 // code pointer
MOVD (g_sched+gobuf_sp)(g), R15 // sp = m->g0->sched.sp
SUB $16, R15
MOVD R3, 8(R15)
MOVD R2, 8(R15)
MOVD $0, 0(R15)
BL (R4)
BR runtime·badmcall2(SB)
@ -292,18 +296,18 @@ noswitch:
// func switchToCrashStack0(fn func())
TEXT runtime·switchToCrashStack0<ABIInternal>(SB), NOSPLIT, $0-8
MOVD fn+0(FP), R12 // context
MOVD g_m(g), R4 // curm
MOVD R2, R12 // context
MOVD g_m(g), R2 // curm
// set g to gcrash
MOVD $runtime·gcrash(SB), g // g = &gcrash
BL runtime·save_g(SB)
MOVD R4, g_m(g) // g.m = curm
MOVD g, m_g0(R4) // curm.g0 = g
MOVD R2, g_m(g) // g.m = curm
MOVD g, m_g0(R2) // curm.g0 = g
// switch to crashstack
MOVD (g_stack+stack_hi)(g), R4
ADD $(-4*8), R4, R15
MOVD (g_stack+stack_hi)(g), R2
ADD $(-4*8), R2, R15
// call target function
MOVD 0(R12), R3 // code pointer
@ -446,10 +450,14 @@ tailArgs: /* copy remaining bytes */ \
EXRL $callfnMVC<>(SB), R5; \
callFunction: \
MOVD f+8(FP), R12; \
MOVD (R12), R8; \
MOVD regArgs+40(FP), R10; \
BL ·unspillArgs(SB); \
MOVD (R12), R10; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (R8); \
BL (R10); \
/* copy return values back */ \
MOVD regArgs+40(FP), R10; \
BL ·spillArgs(SB); \
MOVD stackArgsType+0(FP), R7; \
MOVD stackArgs+16(FP), R6; \
MOVWZ stackArgsSize+24(FP), R5; \
@ -466,11 +474,12 @@ callFunction: \
// to reflectcallmove. It does not follow the Go ABI; it expects its
// arguments in registers.
TEXT callRet<>(SB), NOSPLIT, $40-0
NO_LOCAL_POINTERS;
MOVD R7, 8(R15)
MOVD R6, 16(R15)
MOVD R4, 24(R15)
MOVD R5, 32(R15)
MOVD $0, 40(R15)
MOVD R10, 40(R15)
BL runtime·reflectcallmove(SB)
RET
@ -754,15 +763,80 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-8
MOVD R3, ret+0(FP)
RET
#ifdef GOEXPERIMENT_regabiargs
// spillArgs stores return values from registers to a *internal/abi.RegArgs in R10.
TEXT runtime·spillArgs(SB),NOSPLIT,$0-0
MOVD R2, 0(R10)
MOVD R3, 8(R10)
MOVD R4, 16(R10)
MOVD R5, 24(R10)
MOVD R6, 32(R10)
MOVD R7, 40(R10)
MOVD R8, 48(R10)
MOVD R9, 56(R10)
FMOVD F0, 64(R10)
FMOVD F1, 72(R10)
FMOVD F2, 80(R10)
FMOVD F3, 88(R10)
FMOVD F4, 96(R10)
FMOVD F5, 104(R10)
FMOVD F6, 112(R10)
FMOVD F7, 120(R10)
FMOVD F8, 128(R10)
FMOVD F9, 136(R10)
FMOVD F10, 144(R10)
FMOVD F11, 152(R10)
FMOVD F12, 160(R10)
FMOVD F13, 168(R10)
FMOVD F14, 176(R10)
FMOVD F15, 184(R10)
RET
// unspillArgs loads args into registers from a *internal/abi.RegArgs in R10.
TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0
MOVD 0(R10), R2
MOVD 8(R10), R3
MOVD 16(R10), R4
MOVD 24(R10), R5
MOVD 32(R10), R6
MOVD 40(R10), R7
MOVD 48(R10), R8
MOVD 56(R10), R9
FMOVD 64(R10), F0
FMOVD 72(R10), F1
FMOVD 80(R10), F2
FMOVD 88(R10), F3
FMOVD 96(R10), F4
FMOVD 104(R10), F5
FMOVD 112(R10), F6
FMOVD 120(R10), F7
FMOVD 128(R10), F8
FMOVD 136(R10), F9
FMOVD 144(R10), F10
FMOVD 152(R10), F11
FMOVD 160(R10), F12
FMOVD 168(R10), F13
FMOVD 176(R10), F14
FMOVD 184(R10), F15
RET
#else
TEXT runtime·spillArgs(SB),NOSPLIT,$0-0
RET
TEXT runtime·unspillArgs(SB),NOSPLIT,$0-0
RET
#endif
// AES hashing not implemented for s390x
TEXT runtime·memhash(SB),NOSPLIT|NOFRAME,$0-32
JMP runtime·memhashFallback(SB)
TEXT runtime·strhash(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·strhashFallback(SB)
TEXT runtime·memhash32(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·memhash32Fallback(SB)
TEXT runtime·memhash64(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·memhash64Fallback(SB)
TEXT runtime·memhash<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-32
JMP runtime·memhashFallback<ABIInternal>(SB)
TEXT runtime·strhash<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·strhashFallback<ABIInternal>(SB)
TEXT runtime·memhash32<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·memhash32Fallback<ABIInternal>(SB)
TEXT runtime·memhash64<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
JMP runtime·memhash64Fallback<ABIInternal>(SB)
// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
// Must obey the gcc calling convention.
@ -902,8 +976,7 @@ TEXT runtime·panicBounds<ABIInternal>(SB),NOSPLIT,$144-0
// skip R14 aka LR @ 136
// skip R15 aka SP @ 144
MOVD R14, 8(R15) // PC immediately after call to panicBounds
ADD $24, R15, R0 // pointer to save area
MOVD R0, 16(R15)
MOVD R14, R2 // PC immediately after call to panicBounds
ADD $24, R15, R3 // pointer to save area
CALL runtime·panicBounds64<ABIInternal>(SB)
RET

View file

@ -796,6 +796,9 @@ func cgoCheckResult(val any) {
ep := efaceOf(&val)
t := ep._type
if t == nil {
return
}
cgoCheckArg(t, ep.data, !t.IsDirectIface(), false, cgoResultFail)
}

View file

@ -7,10 +7,14 @@
// See memclrNoHeapPointers Go doc for important implementation constraints.
// func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT|NOFRAME,$0-16
TEXT runtime·memclrNoHeapPointers<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-16
#ifndef GOEXPERIMENT_regabiargs
MOVD ptr+0(FP), R4
MOVD n+8(FP), R5
#else
MOVD R2, R4
MOVD R3, R5
#endif
CMPBGE R5, $32, clearge32
start:

View file

@ -7,10 +7,16 @@
// See memmove Go doc for important implementation constraints.
// func memmove(to, from unsafe.Pointer, n uintptr)
TEXT runtime·memmove(SB),NOSPLIT|NOFRAME,$0-24
TEXT runtime·memmove<ABIInternal>(SB),NOSPLIT|NOFRAME,$0-24
#ifndef GOEXPERIMENT_regabiargs
MOVD to+0(FP), R6
MOVD from+8(FP), R4
MOVD n+16(FP), R5
#else
MOVD R4, R5
MOVD R3, R4
MOVD R2, R6
#endif
CMPBEQ R6, R4, done

View file

@ -25,10 +25,14 @@
// func runtime·raceread(addr uintptr)
// Called from instrumented code.
TEXT runtime·raceread(SB), NOSPLIT, $0-8
TEXT runtime·raceread<ABIInternal>(SB), NOSPLIT, $0-8
// void __tsan_read(ThreadState *thr, void *addr, void *pc);
MOVD $__tsan_read(SB), R1
#ifndef GOEXPERIMENT_regabiargs
MOVD addr+0(FP), R3
#else
MOVD R2, R3
#endif
MOVD R14, R4
JMP racecalladdr<>(SB)
@ -46,10 +50,14 @@ TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
// func runtime·racewrite(addr uintptr)
// Called from instrumented code.
TEXT runtime·racewrite(SB), NOSPLIT, $0-8
TEXT runtime·racewrite<ABIInternal>(SB), NOSPLIT, $0-8
// void __tsan_write(ThreadState *thr, void *addr, void *pc);
MOVD $__tsan_write(SB), R1
#ifndef GOEXPERIMENT_regabiargs
MOVD addr+0(FP), R3
#else
MOVD R2, R3
#endif
MOVD R14, R4
JMP racecalladdr<>(SB)
@ -67,10 +75,15 @@ TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
// func runtime·racereadrange(addr, size uintptr)
// Called from instrumented code.
TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
TEXT runtime·racereadrange<ABIInternal>(SB), NOSPLIT, $0-16
// void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
MOVD $__tsan_read_range(SB), R1
#ifndef GOEXPERIMENT_regabiargs
LMG addr+0(FP), R3, R4
#else
MOVD R3, R4
MOVD R2, R3
#endif
MOVD R14, R5
JMP racecalladdr<>(SB)
@ -91,10 +104,15 @@ TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
// func runtime·racewriterange(addr, size uintptr)
// Called from instrumented code.
TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
TEXT runtime·racewriterange<ABIInternal>(SB), NOSPLIT, $0-16
// void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
MOVD $__tsan_write_range(SB), R1
#ifndef GOEXPERIMENT_regabiargs
LMG addr+0(FP), R3, R4
#else
MOVD R3, R4
MOVD R2, R3
#endif
MOVD R14, R5
JMP racecalladdr<>(SB)

View file

@ -39,7 +39,7 @@ func gotraceback() (level int32, all, crash bool) {
gp := getg()
t := atomic.Load(&traceback_cache)
crash = t&tracebackCrash != 0
all = gp.m.throwing >= throwTypeUser || t&tracebackAll != 0
all = gp.m.throwing > throwTypeUser || t&tracebackAll != 0
if gp.m.traceback != 0 {
level = int32(gp.m.traceback)
} else if gp.m.throwing >= throwTypeRuntime {

View file

@ -234,7 +234,7 @@ func (frame *stkframe) getStackMap(debug bool) (locals, args bitvector, objs []s
}
// stack objects.
if (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "loong64" || GOARCH == "ppc64" || GOARCH == "ppc64le" || GOARCH == "riscv64") &&
if (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "loong64" || GOARCH == "ppc64" || GOARCH == "ppc64le" || GOARCH == "riscv64" || GOARCH == "s390x") &&
unsafe.Sizeof(abi.RegArgs{}) > 0 && isReflect {
// For reflect.makeFuncStub and reflect.methodValueCall,
// we need to fake the stack object record.

View file

@ -8,6 +8,13 @@ package runtime
func load_g()
func save_g()
// Used by reflectcall and the reflect package.
//
// Spills/loads arguments in registers to/from an internal/abi.RegArgs
// respectively. Does not follow the Go ABI.
func spillArgs()
func unspillArgs()
// getfp returns the frame pointer register of its caller or 0 if not implemented.
// TODO: Make this a compiler intrinsic
func getfp() uintptr { return 0 }

View file

@ -19,7 +19,7 @@
//
// If !iscgo, this is a no-op.
//
// NOTE: setg_gcc<> assume this clobbers only R10 and R11.
// NOTE: setg_gcc<> and mcall assume this clobbers only R10 and R11.
TEXT runtime·save_g(SB),NOSPLIT|NOFRAME,$0-0
MOVB runtime·iscgo(SB), R10
CMPBEQ R10, $0, nocgo