Pārlūkot izejas kodu

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

git-svn-id: trunk@44041 -

florian 5 gadi atpakaļ
vecāks
revīzija
22197641b8
1 mainītis faili ar 45 papildinājumiem un 5 dzēšanām
  1. 45 5
      compiler/nflw.pas

+ 45 - 5
compiler/nflw.pas

@@ -1744,6 +1744,15 @@ implementation
       end;
       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;
     function tfornode.makewhileloop : tnode;
       var
       var
         ifblock,loopblock : tblocknode;
         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 }
         { if the lower bound is not constant, it must be store in a temp before calculating the upper bound }
         usefromtemp : boolean;
         usefromtemp : boolean;
         storefilepos: tfileposinfo;
         storefilepos: tfileposinfo;
+        countermin, countermax: Tconstexprint;
 
 
       procedure iterate_counter(var s : tstatementnode;fw : boolean);
       procedure iterate_counter(var s : tstatementnode;fw : boolean);
         begin
         begin
@@ -1785,18 +1795,48 @@ implementation
         fromtemp:=nil;
         fromtemp:=nil;
         storefilepos:=current_filepos;
         storefilepos:=current_filepos;
         current_filepos:=fileinfo;
         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
         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,
           { 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
             then we can't do the trick with incrementing the loop var only at the
             end
             end
           }
           }
           not(assigned(entrylabel));
           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 }
         { convert the for loop into a while loop }
         result:=internalstatements(statements);
         result:=internalstatements(statements);