internal/asm/c64,c128: AMD64 AXPY faults on valid alignment and overruns an exhausted alignment tail
Upstream master 2b52c28fc756441b75b3af99cddc1649f4439ded; AMD64 ASM, no SIMD experiment.
Save as asm_axpy_repro_test.go in the repository root. Run:
GOEXPERIMENT= go test -run '^TestUpstreamAXPY/c64_alignment
```go
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c128"
"gonum.org/v1/gonum/internal/asm/c64"
"testing"
"unsafe"
)
func c64Aligned(t *testing.T, n int, mod uintptr) []complex64 {
storage := new(struct {
A [32]complex64
Pad float32
B [32]complex64
})
for _, v := range [][]complex64{storage.A[:], storage.B[:]} {
for start := 0; start < 2; start++ {
if uintptr(unsafe.Pointer(&v[start]))%16 == mod {
return v[start : start+n]
}
}
}
t.Fatal("fixture alignment")
return nil
}
func TestUpstreamAXPY(t *testing.T) {
t.Run("c64_alignment", func(t *testing.T) {
y := c64Aligned(t, 17, 4)
x := make([]complex64, 17)
for i := range x {
x[i], y[i] = 1, 2
}
c64.AxpyUnitary(3, x, y)
for _, v := range y {
if v != 5 {
t.Fatalf("got %v, want 5", v)
}
}
})
t.Run("c64_empty_tail", func(t *testing.T) {
y := c64Aligned(t, 1, 8)
y[0] = 2
dst := make([]complex64, 1)
c64.AxpyUnitaryTo(dst, 3, []complex64{1}, y)
if dst[0] != 5 {
t.Fatalf("got %v, want 5", dst)
}
})
t.Run("c128_alignment", func(t *testing.T) {
storage := new(struct {
A [8]complex128
Pad uint64
B [8]complex128
})
y := storage.A[:]
if uintptr(unsafe.Pointer(&y[0]))%16 == 0 {
y = storage.B[:]
}
if uintptr(unsafe.Pointer(&y[0]))%16 != 8 {
t.Fatal("fixture alignment")
}
y = y[:1]
y[0] = 2
c128.AxpyUnitary(3, []complex128{1}, y)
if y[0] != 5 {
t.Fatalf("got %v, want 5", y)
}
})
}ASM may terminate the process; use ulimit -c 0. Go 1.27.1: noasm passes; Rosetta reproduces the exhausted tail but not alignment faults. Repaired ASM tests pass under Rosetta; native AMD64 pending.
-count=1 -timeout=5s .
GOEXPERIMENT= go test -run '^TestUpstreamAXPY/c64_empty_tail
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c128"
"gonum.org/v1/gonum/internal/asm/c64"
"testing"
"unsafe"
)
func c64Aligned(t *testing.T, n int, mod uintptr) []complex64 {
storage := new(struct {
A [32]complex64
Pad float32
B [32]complex64
})
for _, v := range [][]complex64{storage.A[:], storage.B[:]} {
for start := 0; start < 2; start++ {
if uintptr(unsafe.Pointer(&v[start]))%16 == mod {
return v[start : start+n]
}
}
}
t.Fatal("fixture alignment")
return nil
}
func TestUpstreamAXPY(t *testing.T) {
t.Run("c64_alignment", func(t *testing.T) {
y := c64Aligned(t, 8, 4)
x := make([]complex64, 8)
for i := range x {
x[i], y[i] = 1, 2
}
c64.AxpyUnitary(3, x, y)
for _, v := range y {
if v != 5 {
t.Fatalf("got %v, want 5", v)
}
}
})
t.Run("c64_empty_tail", func(t *testing.T) {
y := c64Aligned(t, 1, 8)
y[0] = 2
dst := make([]complex64, 1)
c64.AxpyUnitaryTo(dst, 3, []complex64{1}, y)
if dst[0] != 5 {
t.Fatalf("got %v, want 5", dst)
}
})
t.Run("c128_alignment", func(t *testing.T) {
storage := new(struct {
A [8]complex128
Pad uint64
B [8]complex128
})
y := storage.A[:]
if uintptr(unsafe.Pointer(&y[0]))%16 == 0 {
y = storage.B[:]
}
if uintptr(unsafe.Pointer(&y[0]))%16 != 8 {
t.Fatal("fixture alignment")
}
y = y[:1]
y[0] = 2
c128.AxpyUnitary(3, []complex128{1}, y)
if y[0] != 5 {
t.Fatalf("got %v, want 5", y)
}
})
}ASM may terminate the process; use ulimit -c 0. Verification: source audited; noasm control passed on darwin/arm64, Go 1.27.1. Fresh native AMD64 execution not yet verified.
-count=1 -timeout=5s .
GOEXPERIMENT= go test -run '^TestUpstreamAXPY/c128_alignment
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c128"
"gonum.org/v1/gonum/internal/asm/c64"
"testing"
"unsafe"
)
func c64Aligned(t *testing.T, n int, mod uintptr) []complex64 {
storage := new(struct {
A [32]complex64
Pad float32
B [32]complex64
})
for _, v := range [][]complex64{storage.A[:], storage.B[:]} {
for start := 0; start < 2; start++ {
if uintptr(unsafe.Pointer(&v[start]))%16 == mod {
return v[start : start+n]
}
}
}
t.Fatal("fixture alignment")
return nil
}
func TestUpstreamAXPY(t *testing.T) {
t.Run("c64_alignment", func(t *testing.T) {
y := c64Aligned(t, 8, 4)
x := make([]complex64, 8)
for i := range x {
x[i], y[i] = 1, 2
}
c64.AxpyUnitary(3, x, y)
for _, v := range y {
if v != 5 {
t.Fatalf("got %v, want 5", v)
}
}
})
t.Run("c64_empty_tail", func(t *testing.T) {
y := c64Aligned(t, 1, 8)
y[0] = 2
dst := make([]complex64, 1)
c64.AxpyUnitaryTo(dst, 3, []complex64{1}, y)
if dst[0] != 5 {
t.Fatalf("got %v, want 5", dst)
}
})
t.Run("c128_alignment", func(t *testing.T) {
storage := new(struct {
A [8]complex128
Pad uint64
B [8]complex128
})
y := storage.A[:]
if uintptr(unsafe.Pointer(&y[0]))%16 == 0 {
y = storage.B[:]
}
if uintptr(unsafe.Pointer(&y[0]))%16 != 8 {
t.Fatal("fixture alignment")
}
y = y[:1]
y[0] = 2
c128.AxpyUnitary(3, []complex128{1}, y)
if y[0] != 5 {
t.Fatalf("got %v, want 5", y)
}
})
}ASM may terminate the process; use ulimit -c 0. Verification: source audited; noasm control passed on darwin/arm64, Go 1.27.1. Fresh native AMD64 execution not yet verified.
-count=1 -timeout=5s .
Add `-tags noasm` for the passing control.
```go
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c128"
"gonum.org/v1/gonum/internal/asm/c64"
"testing"
"unsafe"
)
func c64Aligned(t *testing.T, n int, mod uintptr) []complex64 {
storage := new(struct {
A [32]complex64
Pad float32
B [32]complex64
})
for _, v := range [][]complex64{storage.A[:], storage.B[:]} {
for start := 0; start < 2; start++ {
if uintptr(unsafe.Pointer(&v[start]))%16 == mod {
return v[start : start+n]
}
}
}
t.Fatal("fixture alignment")
return nil
}
func TestUpstreamAXPY(t *testing.T) {
t.Run("c64_alignment", func(t *testing.T) {
y := c64Aligned(t, 8, 4)
x := make([]complex64, 8)
for i := range x {
x[i], y[i] = 1, 2
}
c64.AxpyUnitary(3, x, y)
for _, v := range y {
if v != 5 {
t.Fatalf("got %v, want 5", v)
}
}
})
t.Run("c64_empty_tail", func(t *testing.T) {
y := c64Aligned(t, 1, 8)
y[0] = 2
dst := make([]complex64, 1)
c64.AxpyUnitaryTo(dst, 3, []complex64{1}, y)
if dst[0] != 5 {
t.Fatalf("got %v, want 5", dst)
}
})
t.Run("c128_alignment", func(t *testing.T) {
storage := new(struct {
A [8]complex128
Pad uint64
B [8]complex128
})
y := storage.A[:]
if uintptr(unsafe.Pointer(&y[0]))%16 == 0 {
y = storage.B[:]
}
if uintptr(unsafe.Pointer(&y[0]))%16 != 8 {
t.Fatal("fixture alignment")
}
y = y[:1]
y[0] = 2
c128.AxpyUnitary(3, []complex128{1}, y)
if y[0] != 5 {
t.Fatalf("got %v, want 5", y)
}
})
}ASM may terminate the process; use ulimit -c 0. Verification: source audited; noasm control passed on darwin/arm64, Go 1.27.1. Fresh native AMD64 execution not yet verified.
Source: gonum/gonum