#2105·gonum

internal/asm/f32,f64: AMD64 GER mishandles valid negative increments

Author: jamestjspCreated Sep 8, 2026Updated Sep 8, 2026

Upstream master 2b52c28fc756441b75b3af99cddc1649f4439ded; AMD64 ASM, no SIMD experiment.

Save as asm_ger_repro_test.go in the repository root. Run:

bash
GOEXPERIMENT= go test -run '^TestUpstreamGER' -count=1 -timeout=5s .

Add -tags noasm for the passing control.

go
package gonum_test

import (
	"fmt"
	blasgo "gonum.org/v1/gonum/blas/gonum"
	"testing"
)

func TestUpstreamGER(t *testing.T) {
	for _, steps := range [][2]int{{1, -1}, {-1, 1}, {-1, -1}} {
		t.Run(fmt.Sprint(steps), func(t *testing.T) {
			// Extra initialized backing keeps the known erroneous offsets mapped.
			xd, yd := make([]float64, 128), make([]float64, 128)
			xs, ys := make([]float32, 128), make([]float32, 128)
			for i := range xd {
				xd[i] = float64(i + 1)
				yd[i] = float64(i + 2)
				xs[i] = float32(i + 1)
				ys[i] = float32(i + 2)
			}
			const m, n = 5, 3
			ad, as := make([]float64, m*n), make([]float32, m*n)
			blasgo.Implementation{}.Dger(m, n, 1, xd, steps[0], yd, steps[1], ad, n)
			blasgo.Implementation{}.Sger(m, n, 1, xs, steps[0], ys, steps[1], as, n)
			for i := 0; i < m; i++ {
				for j := 0; j < n; j++ {
					ix, iy := i, j
					if steps[0] < 0 {
						ix = m - 1 - i
					}
					if steps[1] < 0 {
						iy = n - 1 - j
					}
					want := xd[ix] * yd[iy]
					if ad[i*n+j] != want {
						t.Errorf("Dger [%d,%d]: got %g want %g", i, j, ad[i*n+j], want)
					}
					if as[i*n+j] != float32(want) {
						t.Errorf("Sger [%d,%d]: got %g want %g", i, j, as[i*n+j], want)
					}
				}
			}
		})
	}
}

Go 1.27.1/Rosetta: original gives incorrect matrices; repaired ASM and noasm controls pass. Native AMD64 pending.