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:
parent
92e09e517f
commit
5c1293f268
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue