You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
cmd/compile: simd.Float32s.Neg rebuilds its sign-bit constant on every loop iteration #81846
Compiled and disassembled a loop that calls Float32s.Neg:
package main
import"simd"funcneg(dst, a []float32) {
fori:=0; i<len(dst); {
v, n:=simd.LoadFloat32sPart(a[i:])
v.Neg().StorePart(dst[i:])
i+=n
}
}
funcmain() {
a:=make([]float32, 100)
d:=make([]float32, 100)
neg(d, a)
}
GOEXPERIMENT=simd go build -o neg .
go tool objdump -s 'main\.neg@simd512$' neg
neg is a dispatcher that picks neg@simd128, neg@simd256 or neg@simd512
on every call; the loop body lives in the width-specific clone.
What did you see happen?
Neg lowers to an XOR with a sign-bit vector, but the instructions that
build that vector are emitted at the use site, inside the loop body, instead
of once before the loop. On go1.27.1 the relevant part of neg@simd512
is:
4a3898 ... ; loop head (the back edge jumps here)
4a38d6 VMOVDQU64 0(DX), Z1 ; full-width load
4a3922 MOVL $-0x80000000, DX ; constant rebuilt every iteration
4a3927 VMOVD DX, X2
4a392b VPBROADCASTD X2, Z2
4a3937 VPXORD Z2, Z1, Z1 ; the actual negation
4a3947 VMOVDQU64 Z1, 0(R9) ; full-width store
4a394d JMP 0x4a3898 ; back edge, before the constant rebuild
On gotip (go1.28-devel_2ca679b1f1) the same sequence appears, at shifted
addresses:
49cfd2 ... ; loop head
49d016 VMOVDQU64 0(DX), Z0
49d05c MOVL $-0x80000000, DX ; constant rebuilt every iteration
49d061 VMOVD DX, X1
49d065 VPBROADCASTD X1, Z1
49d071 VPXORD Z1, Z0, Z0
49d07e VMOVDQU64 Z0, 0(R9)
49d084 JMP 0x49cfd2 ; back edge, before the constant rebuild
In both, the MOVL $-0x80000000 / VMOVD / VPBROADCASTD sequence sits
between the loop head and the back-edge jump target, so it re-executes every
iteration. The result is correct; it is three extra instructions and a
dependency chain per iteration for a value that never changes.
What did you expect to see?
The sign-bit constant materialized once before the loop and kept live in a
register across iterations, the way a user-hoisted constant already is.
Activity
mauri870 commentedon Sep 29, 2026
cc @golang/compiler
gabyhelp commentedon Sep 29, 2026
Related Issues
Related Code Changes
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
prattmic commentedon Sep 29, 2026
cc @dr2chase @JunyangShao @cherrymui