* handle min/max properly if it is applied to NaNs

* test extended

git-svn-id: trunk@47729 -
This commit is contained in:
florian 2020-12-08 20:41:58 +00:00
parent 8fd3beb35b
commit 3707cb4b1e
2 changed files with 56 additions and 6 deletions

View File

@ -1614,8 +1614,10 @@ implementation
(tassignmentnode(thenstmnt).right.isequal(taddnode(left).right) and (tassignmentnode(elsestmnt).right.isequal(taddnode(left).left)))) then
begin
paratype:=tassignmentnode(thenstmnt).left.resultdef;
if (left.nodetype in [gtn,gten]) and
(tassignmentnode(thenstmnt).right.isequal(taddnode(left).left) and (tassignmentnode(elsestmnt).right.isequal(taddnode(left).right))) then
if ((left.nodetype in [gtn,gten]) and
tassignmentnode(thenstmnt).right.isequal(taddnode(left).left)) or
((left.nodetype in [ltn,lten]) and
tassignmentnode(thenstmnt).right.isequal(taddnode(left).right)) then
begin
if is_double(paratype) then
in_nr:=in_max_double
@ -1637,9 +1639,14 @@ implementation
else if is_s32bitint(paratype) then
in_nr:=in_min_longint;
end;
{ for inline nodes, the first parameter is the last one in the linked list
Due to the defined behaviour for the min/max intrinsics that in case of a NaN
the second parameter is taken, we have to put the else part into the second parameter
thus pass it to the first callparanode call }
Result:=cassignmentnode.create_internal(tassignmentnode(thenstmnt).left.getcopy,
cinlinenode.create(in_nr,false,ccallparanode.create(taddnode(left).right.getcopy,
ccallparanode.create(taddnode(left).left.getcopy,nil)))
cinlinenode.create(in_nr,false,ccallparanode.create(tassignmentnode(elsestmnt).right.getcopy,
ccallparanode.create(tassignmentnode(thenstmnt).right.getcopy,nil)))
);
end;
{$endif defined(i386) or defined(x86_64) or defined(xtensa)}

View File

@ -1,4 +1,9 @@
{ %opt=-O- -Oonofastmath } { with fast math, the operands of min/max might be swapped and this breaks the tests using NaN }
{$mode objfpc}
uses
Math;
procedure TestSingle;
function Min1(a, b: Single): Single; inline;
@ -36,7 +41,7 @@ procedure TestSingle;
end;
var
v1,v3 : Single;
v1,v3,vNaN : Single;
begin
v1:=1;
@ -73,6 +78,25 @@ procedure TestSingle;
halt(33);
if Max2(v1,v3)<>v3 then
halt(34);
SetExceptionMask([exInvalidOp]);
vNaN:=NaN;
if not(IsNaN(Min1(v1,vNaN))) then
halt(41);
if Min1(NaN,v1)<>v1 then
halt(42);
if not(IsNaN(Max1(v1,vNaN))) then
halt(43);
if Max1(vNaN,v3)<>v3 then
halt(44);
if not(IsNaN(Min2(v1,vNaN))) then
halt(45);
if Min2(vNaN,v3)<>v3 then
halt(46);
if not(IsNaN(Max2(v1,vNaN))) then
halt(47);
if Max2(vNaN,v3)<>v3 then
halt(48);
SetExceptionMask([]);
end;
procedure TestDouble;
@ -112,7 +136,7 @@ procedure TestDouble;
end;
var
v1,v3 : Double;
v1,v3,vNaN : Double;
begin
v1:=1;
@ -149,6 +173,25 @@ procedure TestDouble;
halt(133);
if Max2(v1,v3)<>v3 then
halt(134);
SetExceptionMask([exInvalidOp]);
vNaN:=NaN;
if not(IsNaN(Min1(v1,vNaN))) then
halt(141);
if Min1(NaN,v1)<>v1 then
halt(142);
if not(IsNaN(Max1(v1,vNaN))) then
halt(143);
if Max1(vNaN,v3)<>v3 then
halt(144);
if not(IsNaN(Min2(v1,vNaN))) then
halt(145);
if Min2(vNaN,v3)<>v3 then
halt(146);
if not(IsNaN(Max2(v1,vNaN))) then
halt(147);
if Max2(vNaN,v3)<>v3 then
halt(148);
SetExceptionMask([]);
end;