From 6fea48f233019c375e20d55b0e8194acf1103127 Mon Sep 17 00:00:00 2001 From: folbrich Date: Wed, 21 Oct 2026 16:44:30 +0200 Subject: [PATCH] Carry the loop's float remainder as bits, so that it needs no stack slot The float remainder that 81ddf67 added kept its result in a float across the branch for a zero remainder, and the register allocator gave it a stack slot. That grew fast's frame by 8 bytes, which moved the dispatch head's store of pc to 0x80(SP), past the reach of a one-byte displacement: the store grew by 3 bytes, and the indirect jump that follows now crossed a 32-byte boundary, which the assembler pads with a NOP. Every instruction the loop ran paid for it; fib ran 2.7% more instructions, nbody 1.8%. Built as bits in an integer register, the result needs no slot: the frame and the head are as before 81ddf67, and instruction counts are back to within 0.7% of it. The gate's baseline returns to its earlier trade: GETFIELD 7, GETTABLE 2. --- bench/asmgate/baseline.txt | 4 ++-- checked_gen.go | 7 ++++--- fast.go | 7 ++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/bench/asmgate/baseline.txt b/bench/asmgate/baseline.txt index 6003ce6..0d4a421 100644 --- a/bench/asmgate/baseline.txt +++ b/bench/asmgate/baseline.txt @@ -1,8 +1,8 @@ # Stack accesses per hot opcode in (*executor).fast, outside write-barrier slow paths. # Opcodes not listed must have none. Written by go run ./bench/asmgate -update. amd64-v1 head 1 -amd64-v1 opGetField 6 -amd64-v1 opGetTable,opGetIndex 3 +amd64-v1 opGetField 7 +amd64-v1 opGetTable,opGetIndex 2 amd64-v1 opJmp 3 amd64-v1 opSelf 1 amd64-v3 head 2 diff --git a/checked_gen.go b/checked_gen.go index 21b1580..3810d8e 100644 --- a/checked_gen.go +++ b/checked_gen.go @@ -612,13 +612,14 @@ dispatch: if m != 0 && (m^b) < 0 { // round towards minus infinity m += b } - r := float64(m) + // the result's bits, so that no float lives across the branch, which spills it + r := math.Float64bits(float64(m)) if m == 0 { // as fmod: a zero remainder keeps the dividend's sign, which is bit 63 of an // integer and of a float alike - r = math.Float64frombits(x.n & (1 << 63)) + r = x.n & (1 << 63) } - setFloat(®s[uint8(i>>8)], r) + setFloat(®s[uint8(i>>8)], math.Float64frombits(r)) } else { e = exSlowOp break dispatch diff --git a/fast.go b/fast.go index b236c55..fa5730a 100644 --- a/fast.go +++ b/fast.go @@ -723,13 +723,14 @@ dispatch: if m != 0 && (m^b) < 0 { // round towards minus infinity m += b } - r := float64(m) + // the result's bits, so that no float lives across the branch, which spills it + r := math.Float64bits(float64(m)) if m == 0 { // as fmod: a zero remainder keeps the dividend's sign, which is bit 63 of an // integer and of a float alike - r = math.Float64frombits(x.n & (1 << 63)) + r = x.n & (1 << 63) } - setFloat(®s[uint8(i>>8)], r) + setFloat(®s[uint8(i>>8)], math.Float64frombits(r)) } else { e = exSlowOp break dispatch