Browse Source

* min/max optimization needs to check both operands of the if condition, even if no else-statement is passed, resolves #38249

git-svn-id: trunk@47843 -
florian 4 years ago
parent
commit
6db164c993
4 changed files with 40 additions and 7 deletions
  1. 1 0
      .gitattributes
  2. 26 3
      compiler/nflw.pas
  3. 4 4
      tests/test/tminmax.pp
  4. 9 0
      tests/webtbs/tw38249.pp

+ 1 - 0
.gitattributes

@@ -18614,6 +18614,7 @@ tests/webtbs/tw38201.pp svneol=native#text/pascal
 tests/webtbs/tw38202.pp svneol=native#text/pascal
 tests/webtbs/tw38225.pp svneol=native#text/pascal
 tests/webtbs/tw38238.pp svneol=native#text/pascal
+tests/webtbs/tw38249.pp svneol=native#text/pascal
 tests/webtbs/tw3827.pp svneol=native#text/plain
 tests/webtbs/tw3829.pp svneol=native#text/plain
 tests/webtbs/tw3833.pp svneol=native#text/plain

+ 26 - 3
compiler/nflw.pas

@@ -1563,6 +1563,7 @@ implementation
         paratype: tdef;
       begin
         result:=nil;
+        elsestmnt:=nil;
         in_nr:=Default(tinlinenumber);
         { optimize constant expressions }
         if (left.nodetype=ordconstn) then
@@ -1590,7 +1591,21 @@ implementation
           end;
 {$ifndef llvm}
 {$if defined(i386) or defined(x86_64) or defined(xtensa)}
-        { use min/max intrinsic? }
+        { use min/max intrinsic?
+          convert (with <op> being <, >, >=, <=
+          if a <op> b then
+            x:=a
+          else
+            x:=b;
+
+          and
+
+          if a <op> b then
+            x:=a;
+
+          into appropriate min/max intrinsics
+
+          }
         if (cs_opt_level2 in current_settings.optimizerswitches) and
            (left.nodetype in [gtn,gten,ltn,lten]) and IsSingleStatement(right,thenstmnt) and ((t1=nil) or IsSingleStatement(t1,elsestmnt)) and
           (thenstmnt.nodetype=assignn) and ((t1=nil) or (elsestmnt.nodetype=assignn)) and
@@ -1608,8 +1623,16 @@ implementation
 {$if defined(xtensa)}
           (CPUXTENSA_HAS_MINMAX in cpu_capabilities[current_settings.cputype]) and is_32bitint(tassignmentnode(thenstmnt).right.resultdef) and
 {$endif defined(xtensa)}
-          ((tassignmentnode(thenstmnt).right.isequal(taddnode(left).left) and ((t1=nil) or (tassignmentnode(elsestmnt).right.isequal(taddnode(left).right)))) or
-           (tassignmentnode(thenstmnt).right.isequal(taddnode(left).right) and ((t1=nil) or (tassignmentnode(elsestmnt).right.isequal(taddnode(left).left))))
+          { the right size of the assignment in the then clause must either }
+
+          { equal to the left ... }                                           { ... and the else clause must be either not exist                 }             { or the else clause exists and the right side of the assignment in the else clause }
+                                                                              { and the left side of the assignment in the then clause must be   }             { must be equal to the right side of the comparison operator                        }
+                                                                              {  equal to the right operand of the comparison operator           }
+          ((tassignmentnode(thenstmnt).right.isequal(taddnode(left).left) and (((t1=nil) and (tassignmentnode(thenstmnt).left.isequal(taddnode(left).right))) or (assigned(elsestmnt) and tassignmentnode(elsestmnt).right.isequal(taddnode(left).right)))) or
+          { ... or right operand of the comparison operator }                 { ... and the else clause must be either not exist                 }             { or the else clause exists and the right side of the assignment in the else clause }
+                                                                              { and the left side of the assignment in the then clause must be   }             { must be equal to the left side of the comparison operator                         }
+                                                                              {  equal to the left operand of the comparison operator            }
+           (tassignmentnode(thenstmnt).right.isequal(taddnode(left).right) and (((t1=nil) and (tassignmentnode(thenstmnt).left.isequal(taddnode(left).left))) or (assigned(elsestmnt) and tassignmentnode(elsestmnt).right.isequal(taddnode(left).left))))
           ) then
           begin
             paratype:=tassignmentnode(thenstmnt).left.resultdef;

+ 4 - 4
tests/test/tminmax.pp

@@ -45,7 +45,7 @@ procedure TestSingle;
   function Min3(a, b: Single): Single; inline;
     begin
       Result := b;
-      if a < b then
+      if a < Result then
         Result := a;
     end;
 
@@ -53,7 +53,7 @@ procedure TestSingle;
   function Max3(a, b: Single): Single; inline;
     begin
       Result := b;
-      if a > b then
+      if a > Result then
         Result := a;
     end;
 
@@ -61,7 +61,7 @@ procedure TestSingle;
   function Min4(a, b: Single): Single; inline;
     begin
       Result := b;
-      if a <= b then
+      if a <= Result then
         Result := a;
     end;
 
@@ -69,7 +69,7 @@ procedure TestSingle;
   function Max4(a, b: Single): Single; inline;
     begin
       Result := b;
-      if a >= b then
+      if a >= Result then
         Result := a;
     end;
 

+ 9 - 0
tests/webtbs/tw38249.pp

@@ -0,0 +1,9 @@
+var
+  A: Double = 0.0001;
+  B: Double = 0;
+begin
+  if B >= 0 then
+    A := B;
+  if A<>0 then
+    halt(1);
+end.