← board

aarch64: writeln(d:width:decimals) drops the width

Repro

var d: Double;
begin
  d := 3.14159; writeln(d:10:4);
  d := -2.5;    writeln(d:8:3);
end.
d:10:4 d:8:3
FPC 3.1416 -2.500
pxx x86-64 3.1416 -2.500
pxx aarch64 3.1416 -2.500

The digits are right; only the left-padding to the field width is missing.

Cause

x86-64's emitter is EmitWriteFloatFixed(wid, decs) — it takes the width. The aarch64 twin was declared EmitWriteFloatFixedA64(decimals: Integer) and never received one, so there was nothing to pad with. The call site passes only decs.

The same gap exists in the portable helper it now shims onto: PXXWriteFloatFixed(p: Pointer; decimals: NativeInt) has no width parameter either, and its own comment on the Sci path notes "field-width padding for 64-bit values is not yet wired". So i386, arm32 and riscv32 have this too — they route through the same helper. Only x86-64 pads.

Fix

Add the width to PXXWriteFloatFixed (and PXXWriteFloatSci, which has the same note) and pass it from every backend, then x86-64's native emitter can shim onto it as well and the last hand-written copy goes away. Padding is left-justified spaces to width when the rendered text is shorter — the rule x86-64 already implements.

Doing it in the runtime rather than per-backend is the point: this is the fourth float-output defect traced to the same "N copies of one formatter" shape.

Resolution (2026-08-05)

PXXWriteFloatFixed gained a width parameter and every backend now passes its own. That fixed the reported bug and, as the ticket predicted, let the last hand-written float formatter go: x86-64 now has none.

Verified

All four runnable targets byte-identical to FPC on ten width cases: plain and negative padding, the rounding carry, :5:0 on 0.5 and -0.5, width SMALLER than the content (no truncation), zero, 1e20/-1e20 at :30:2 (past 2^63), and no width at all. Also identical on the pre-existing float suites.

testmgr --tier native 1158/1158 pass, including the self-host fixedpoint. Locked in as test/test_writeln_float_width.pas.

The thread this closes

Four tickets tonight were one root cause — a formatter written N times whose copies drifted: writeln and Str disagreeing, aarch64 printing a wrong NUMBER for Inf, x86-64 saturating at Int64, and this missing width. Four copies at the start, one now.

Log