fix(native): Round() rounds half-away-from-zero to match QBE/Delphi

Native lowered Round() with cvtsd2si/cvtss2si, which honour the FPU rounding
mode (round-half-to-even / banker's): Round(2.5)=2, Round(-2.5)=-2. QBE — and
Delphi/FPC — round half away from zero via C99 round(): Round(2.5)=3,
Round(-2.5)=-3. Native now calls round()/roundf() first, then truncates the
integral result, matching QBE exactly. The two Round e2e tests are converted to
AssertRunsOnAll.

All three fixpoints green; 3481 tests pass.
This commit is contained in:
Graeme Geldenhuys 2026-06-18 07:57:59 +01:00
parent 92e09e517f
commit 5c1293f268
2 changed files with 16 additions and 12 deletions

View file

@ -5325,12 +5325,22 @@ begin
end;
if SameText(FC.Name, 'Round') and (FC.Args.Count = 1) then
begin
{ Round half-away-from-zero, matching Delphi/FPC Round() and the QBE
backend. cvtsd2si/cvtss2si alone would honour the FPU rounding mode
(round-half-to-even / banker's), which disagrees with QBE so route
through C99 round()/roundf() first, then truncate the integral result. }
Self.EmitExprToXmm0(TASTExpr(FC.Args.Items[0]));
if (TASTExpr(FC.Args.Items[0]).ResolvedType <> nil) and
(TASTExpr(FC.Args.Items[0]).ResolvedType.Kind = tySingle) then
Self.Emit(#9'cvtss2si %xmm0, %rax')
begin
Self.Emit(#9'callq roundf');
Self.Emit(#9'cvttss2si %xmm0, %rax');
end
else
Self.Emit(#9'cvtsd2si %xmm0, %rax');
begin
Self.Emit(#9'callq round');
Self.Emit(#9'cvttsd2si %xmm0, %rax');
end;
Exit;
end;
if SameText(FC.Name, 'Trunc') and (FC.Args.Count = 1) then

View file

@ -287,10 +287,9 @@ begin
end;
procedure TE2EMathTests.TestRun_Round_HalfUp;
var Output: string; RCode: Integer;
begin
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
AssertTrue('compile+run', CompileAndRun(
AssertRunsOnAll(
'''
program P;
var R: Integer;
@ -298,16 +297,13 @@ begin
R := Round(2.5);
WriteLn(IntToStr(R))
end.
''', Output, RCode));
AssertEquals('exit code', 0, RCode);
AssertEquals('round(2.5)', '3', Trim(Output));
''', '3' + Chr(10), 0);
end;
procedure TE2EMathTests.TestRun_Round_HalfDown;
var Output: string; RCode: Integer;
begin
if not ToolchainAvailable() then begin Ignore('toolchain unavailable'); Exit; end;
AssertTrue('compile+run', CompileAndRun(
AssertRunsOnAll(
'''
program P;
var R: Integer;
@ -315,9 +311,7 @@ begin
R := Round(-2.5);
WriteLn(IntToStr(R))
end.
''', Output, RCode));
AssertEquals('exit code', 0, RCode);
AssertEquals('round(-2.5)', '-3', Trim(Output));
''', '-3' + Chr(10), 0);
end;
procedure TE2EMathTests.TestRun_Trunc_Positive;