Browse Source

* last commit fixing calculation of do_loopvar_at_end was not complete,
hopefully finally fixed

git-svn-id: trunk@44041 -

florian 5 years ago
parent
commit
22197641b8
1 changed files with 45 additions and 5 deletions
  1. 45 5
      compiler/nflw.pas

+ 45 - 5
compiler/nflw.pas

@@ -1744,6 +1744,15 @@ implementation
       end;
 
 
+    function checkcontinue(var n:tnode; arg: pointer): foreachnoderesult;
+      begin
+        if n.nodetype=continuen then
+          result:=fen_norecurse_true
+        else
+          result:=fen_false;
+      end;
+
+
     function tfornode.makewhileloop : tnode;
       var
         ifblock,loopblock : tblocknode;
@@ -1760,6 +1769,7 @@ implementation
         { if the lower bound is not constant, it must be store in a temp before calculating the upper bound }
         usefromtemp : boolean;
         storefilepos: tfileposinfo;
+        countermin, countermax: Tconstexprint;
 
       procedure iterate_counter(var s : tstatementnode;fw : boolean);
         begin
@@ -1785,18 +1795,48 @@ implementation
         fromtemp:=nil;
         storefilepos:=current_filepos;
         current_filepos:=fileinfo;
+
+        case left.resultdef.typ of
+          enumdef:
+            begin
+              countermin:=tenumdef(left.resultdef).min;
+              countermax:=tenumdef(left.resultdef).max;
+            end;
+          orddef:
+            begin
+              countermin:=torddef(left.resultdef).low;
+              countermax:=torddef(left.resultdef).high;
+            end;
+          else
+            Internalerror(2020012601);
+        end;
+
+        { check if we can pred/succ the loop var at the end }
         do_loopvar_at_end:=(lnf_dont_mind_loopvar_on_exit in loopflags) and
-          (right.nodetype=ordconstn) and (t1.nodetype=ordconstn) and
-          { we cannot test at the end after the inc/dec if the to value is equal to the max. value of the counter variable }
-          not(not(is_signed(left.resultdef)) and (tordconstnode(t1).value<>((1 shl (left.resultdef.size*8))-1))) and
-          not(is_signed(left.resultdef) and (tordconstnode(t1).value<>((1 shl (left.resultdef.size*8-1))-1))) and
+          is_constnode(right) and is_constnode(t1) and
+          { we cannot test at the end after the pred/succ if the to value is equal to the max./min. value of the counter variable
+            because we either get an overflow/underflow or the compiler removes the check as it never can be true }
+
+          { checking just the min./max. value depending on the pure size of the counter does not work as the check might
+            get optimized away
+          not(not(lnf_backward in loopflags) and not(is_signed(left.resultdef)) and (get_ordinal_value(t1)=((1 shl (left.resultdef.size*8))-1))) and
+          not(not(lnf_backward in loopflags) and is_signed(left.resultdef) and (get_ordinal_value(t1)=((1 shl (left.resultdef.size*8-1))-1))) and
+          not((lnf_backward in loopflags) and not(is_signed(left.resultdef)) and (get_ordinal_value(t1)=0)) and
+          not((lnf_backward in loopflags) and is_signed(left.resultdef) and (get_ordinal_value(t1)=(-Tconstexprint(1 shl (left.resultdef.size*8-1))))) and
+          }
+
+          not(not(lnf_backward in loopflags) and (get_ordinal_value(t1)=countermax)) and
+          not((lnf_backward in loopflags) and (get_ordinal_value(t1)=countermin)) and
+          { neither might the for loop contain a continue statement as continue in a while loop would skip the increment at the end
+            of the loop, this could be overcome by replacing the continue statement with an pred/succ; continue sequence }
+          not(foreachnodestatic(t2,@checkcontinue,nil)) and
           { if the loop is unrolled and there is a jump into the loop,
             then we can't do the trick with incrementing the loop var only at the
             end
           }
           not(assigned(entrylabel));
 
-        needsifblock:=(right.nodetype<>ordconstn) or (t1.nodetype<>ordconstn);
+        needsifblock:=not(is_constnode(right)) or not(is_constnode(t1));
 
         { convert the for loop into a while loop }
         result:=internalstatements(statements);