From 22197641b883bf4ad288141feb49caa0a53962a0 Mon Sep 17 00:00:00 2001 From: florian Date: Sun, 26 Jan 2020 20:13:17 +0000 Subject: [PATCH] * last commit fixing calculation of do_loopvar_at_end was not complete, hopefully finally fixed git-svn-id: trunk@44041 - --- compiler/nflw.pas | 50 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/compiler/nflw.pas b/compiler/nflw.pas index 4a96dcab44..981ff799d6 100644 --- a/compiler/nflw.pas +++ b/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);