Sfoglia il codice sorgente

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

git-svn-id: trunk@47729 -

florian 4 anni fa
parent
commit
3707cb4b1e
2 ha cambiato i file con 56 aggiunte e 6 eliminazioni
  1. 11 4
      compiler/nflw.pas
  2. 45 2
      tests/test/tminmax.pp

+ 11 - 4
compiler/nflw.pas

@@ -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)}

+ 45 - 2
tests/test/tminmax.pp

@@ -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;