internal/asm/c64: AMD64 DotcInc and DotuInc scalar tails read 16 bytes for one complex64
Upstream master 2b52c28fc756441b75b3af99cddc1649f4439ded; AMD64 ASM, no SIMD experiment.
Save as asm_dot_repro_test.go in the repository root. Run:
GOEXPERIMENT= go test -run '^TestUpstreamDotTail/DotuInc
```go
//go:build linux || darwin
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c64"
"runtime"
"syscall"
"testing"
"unsafe"
)
func TestUpstreamDotTail(t *testing.T) {
for _, conjugate := range []bool{false, true} {
name := "DotuInc"
if conjugate {
name = "DotcInc"
}
t.Run(name, func(t *testing.T) {
page := syscall.Getpagesize()
mem, err := syscall.Mmap(-1, 0, 2*page, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatal(err)
}
defer syscall.Munmap(mem)
if err := syscall.Mprotect(mem[page:], syscall.PROT_NONE); err != nil {
t.Fatal(err)
}
y := unsafe.Slice((*complex64)(unsafe.Pointer(&mem[page-8])), 1)
y[0] = 3 + 4i
x := []complex64{1 + 2i}
got, want := complex64(0), complex64(-5+10i)
if conjugate {
got = c64.DotcInc(x, y, 1, 1, 1, 0, 0)
want = 11 - 2i
} else {
got = c64.DotuInc(x, y, 1, 1, 1, 0, 0)
}
runtime.KeepAlive(mem)
if got != want {
t.Fatalf("got %v want %v", got, want)
}
})
}
}ASM may terminate the process; use ulimit -c 0. Go 1.27.1/Rosetta: original tail faults; repaired ASM and noasm controls pass. Native AMD64 pending.
-count=1 -timeout=5s .
GOEXPERIMENT= go test -run '^TestUpstreamDotTail/DotcInc
//go:build linux || darwin
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c64"
"runtime"
"syscall"
"testing"
"unsafe"
)
func TestUpstreamDotTail(t *testing.T) {
for _, conjugate := range []bool{false, true} {
name := "DotuInc"
if conjugate {
name = "DotcInc"
}
t.Run(name, func(t *testing.T) {
page := syscall.Getpagesize()
mem, err := syscall.Mmap(-1, 0, 2*page, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatal(err)
}
defer syscall.Munmap(mem)
if err := syscall.Mprotect(mem[page:], syscall.PROT_NONE); err != nil {
t.Fatal(err)
}
y := unsafe.Slice((*complex64)(unsafe.Pointer(&mem[page-8])), 1)
y[0] = 3 + 4i
x := []complex64{1 + 2i}
got, want := complex64(0), complex64(-5+10i)
if conjugate {
got = c64.DotcInc(x, y, 1, 1, 1, 0, 0)
want = 11 - 2i
} else {
got = c64.DotuInc(x, y, 1, 1, 1, 0, 0)
}
runtime.KeepAlive(mem)
if got != want {
t.Fatalf("got %v want %v", got, want)
}
})
}
}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
//go:build linux || darwin
package gonum_test
import (
"gonum.org/v1/gonum/internal/asm/c64"
"runtime"
"syscall"
"testing"
"unsafe"
)
func TestUpstreamDotTail(t *testing.T) {
for _, conjugate := range []bool{false, true} {
name := "DotuInc"
if conjugate {
name = "DotcInc"
}
t.Run(name, func(t *testing.T) {
page := syscall.Getpagesize()
mem, err := syscall.Mmap(-1, 0, 2*page, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatal(err)
}
defer syscall.Munmap(mem)
if err := syscall.Mprotect(mem[page:], syscall.PROT_NONE); err != nil {
t.Fatal(err)
}
y := unsafe.Slice((*complex64)(unsafe.Pointer(&mem[page-8])), 1)
y[0] = 3 + 4i
x := []complex64{1 + 2i}
got, want := complex64(0), complex64(-5+10i)
if conjugate {
got = c64.DotcInc(x, y, 1, 1, 1, 0, 0)
want = 11 - 2i
} else {
got = c64.DotuInc(x, y, 1, 1, 1, 0, 0)
}
runtime.KeepAlive(mem)
if got != want {
t.Fatalf("got %v want %v", got, want)
}
})
}
}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