Sixth target: s390x
Sixth target: s390x
s390x (IBM Z) is the sixth and final 64-bit Go SIMD target — and the first
big-endian one. It reuses the shared ABI0 model (abi) unchanged and adds
only a move table; the big-endian byte order is handled by cmd/asm and the Go
runtime, so the layout model needs no change.
The move table
| Type | arm64 | s390x |
|---|---|---|
int64 / uint64 / pointer | MOVD | MOVD |
int8/int16/int32 (signed) | MOVB/MOVH/MOVW | MOVB/MOVH/MOVW |
uint8/uint16/uint32 | MOVBU/MOVHU/MOVWU | MOVBZ/MOVHZ/MOVWZ |
float32 | FMOVS | FMOVS |
float64 | FMOVD | FMOVD |
s390x’s 8-byte integer move is MOVD, floats use FMOVS/FMOVD, and unsigned
sub-word loads use the Z zero-extend suffix (MOVBZ/MOVHZ/MOVWZ). The
move surface is identical to ppc64le; what differs is the byte order.
Big-endian
s390x is big-endian. ABI0 offsets are still byte-for-byte identical to the
little-endian targets — FP-relative slot placement is endianness-agnostic —
but the runtime test deliberately exercises the big-endian path, catching any
accidental little-endian assumption in the emitted assembly.
Example
sig := s390x.Layout(
[]string{"a", "b"}, []s390x.Type{s390x.Int64, s390x.Int64},
[]string{"ret"}, []s390x.Type{s390x.Int64},
)
b := s390x.NewFunc("add", sig, 0)
b.LoadArg("a", "R1").
LoadArg("b", "R2").
Raw("ADD R2, R1, R3").
StoreRet("R3", "ret").
Ret()emits:
TEXT ·add(SB), NOSPLIT, $0-24
MOVD a+0(FP), R1
MOVD b+8(FP), R2
ADD R2, R1, R3
MOVD R3, ret+16(FP)
RETSIMD
The packed-add example uses the z/Architecture vector facility (VL / VAF /
VST) through Raw over pointer arguments — see SIMD. It runs on the
big-endian target, so lane order is checked there too.
Validation
There is no common s390x developer host, so correctness is established in layers —
asmdecl (cross-arch), cmd/asm cross-build, and runtime under qemu-user
(qemu-user-static), in a dedicated asm-s390x CI job on ubuntu-latest (the
only big-endian runtime job; QEMU_CPU=max enables the vector facility). Only
the SIMD example is runtime-proven today (no dedicated aggregate/array example
yet, see the Roadmap):
go generate ./examples/simd/s390x/...
GOOS=linux GOARCH=s390x go vet ./examples/simd/s390x/...
GOOS=linux GOARCH=s390x go build ./examples/simd/s390x/...
QEMU_CPU=max GOARCH=s390x go test -exec=qemu-s390x-static ./examples/simd/s390x/...