diff --git a/compiler/nflw.pas b/compiler/nflw.pas index ab5d2dc880..3c18363c4d 100644 --- a/compiler/nflw.pas +++ b/compiler/nflw.pas @@ -46,7 +46,10 @@ interface { Should the value of the loop variable on exit be correct. } lnf_dont_mind_loopvar_on_exit, { Loop simplify flag } - lnf_simplify_processing); + lnf_simplify_processing, + { set if in a for loop the counter is not used, so an easier exit check + can be carried out } + lnf_counter_not_used); tloopflags = set of tloopflag; const @@ -1957,7 +1960,12 @@ implementation end else begin - addstatement(ifstatements,cwhilerepeatnode.create(caddnode.create_internal(cond,left.getcopy,t1.getcopy),loopblock,false,true)); + { is a simple comparision for equality sufficient? } + if do_loopvar_at_end and (lnf_backward in loopflags) and (lnf_counter_not_used in loopflags) then + addstatement(ifstatements,cwhilerepeatnode.create(caddnode.create_internal(equaln,left.getcopy, + caddnode.create_internal(subn,t1.getcopy,cordconstnode.create(1,t1.resultdef,false))),loopblock,false,true)) + else + addstatement(ifstatements,cwhilerepeatnode.create(caddnode.create_internal(cond,left.getcopy,t1.getcopy),loopblock,false,true)); addstatement(statements,ifblock); end; current_filepos:=storefilepos; diff --git a/compiler/optloop.pas b/compiler/optloop.pas index d9a6402a2e..6b04949848 100644 --- a/compiler/optloop.pas +++ b/compiler/optloop.pas @@ -24,6 +24,7 @@ unit optloop; {$i fpcdefs.inc} { $define DEBUG_OPTSTRENGTH} +{ $define DEBUG_OPTFORLOOP} interface @@ -32,6 +33,7 @@ unit optloop; function unroll_loop(node : tnode) : tnode; function OptimizeInductionVariables(node : tnode) : boolean; + function OptimizeForLoop(var node : tnode) : boolean; implementation @@ -523,7 +525,7 @@ unit optloop; end; - function iterforloops(var n: tnode; arg: pointer): foreachnoderesult; + function OptimizeInductionVariables_iterforloops(var n: tnode; arg: pointer): foreachnoderesult; var hp : tnode; begin @@ -553,7 +555,74 @@ unit optloop; function OptimizeInductionVariables(node : tnode) : boolean; begin changedforloop:=false; - foreachnodestatic(pm_postprocess,node,@iterforloops,nil); + foreachnodestatic(pm_postprocess,node,@OptimizeInductionVariables_iterforloops,nil); + Result:=changedforloop; + end; + + + function OptimizeForLoop_iterforloops(var n: tnode; arg: pointer): foreachnoderesult; + var + hp : tnode; + begin + Result:=fen_false; + if (n.nodetype=forn) and + not(lnf_backward in tfornode(n).loopflags) and + (lnf_dont_mind_loopvar_on_exit in tfornode(n).loopflags) and + is_constintnode(tfornode(n).right) and + { this is not strictly necessary, but we do it for now } + is_constnode(tfornode(n).t1) and + (([cs_check_overflow,cs_check_range]*n.localswitches)=[]) and + (([cs_check_overflow,cs_check_range]*tfornode(n).left.localswitches)=[]) and + ((tfornode(n).left.nodetype=loadn) and (tloadnode(tfornode(n).left).symtableentry is tabstractvarsym) and + not(tabstractvarsym(tloadnode(tfornode(n).left).symtableentry).addr_taken) and + not(tabstractvarsym(tloadnode(tfornode(n).left).symtableentry).different_scope)) then + begin + { do we have DFA available? } + if pi_dfaavailable in current_procinfo.flags then + begin + CalcUseSum(tfornode(n).t2); + CalcDefSum(tfornode(n).t2); + end + else + Internalerror(2017122801); + if not(assigned(tfornode(n).left.optinfo)) then + exit; + if not(DFASetIn(tfornode(n).t2.optinfo^.usesum,tfornode(n).left.optinfo^.index)) and + not(DFASetIn(tfornode(n).t2.optinfo^.defsum,tfornode(n).left.optinfo^.index)) then + begin + { convert the loop from i:=a to b into i:=b-a+1 to 1 as this simplifies the + abort condition } +{$ifdef DEBUG_OPTFORLOOP} + writeln('**********************************************************************************'); + writeln('Found loop for reverting: '); + printnode(n); + writeln('**********************************************************************************'); +{$endif DEBUG_OPTFORLOOP} + include(tfornode(n).loopflags,lnf_backward); + tfornode(n).right:=caddnode.create_internal(addn,caddnode.create_internal(subn,tfornode(n).t1,tfornode(n).right), + cordconstnode.create(1,tfornode(n).left.resultdef,false)); + tfornode(n).t1:=cordconstnode.create(1,tfornode(n).left.resultdef,false); + include(tfornode(n).loopflags,lnf_counter_not_used); + exclude(n.flags,nf_pass1_done); + do_firstpass(n); +{$ifdef DEBUG_OPTFORLOOP} + writeln('Loop reverted: '); + printnode(n); + writeln('**********************************************************************************'); +{$endif DEBUG_OPTFORLOOP} + changedforloop:=true; + end; + end; + end; + + + function OptimizeForLoop(var node : tnode) : boolean; + begin + Result:=false; + if not(pi_dfaavailable in current_procinfo.flags) then + exit; + changedforloop:=false; + foreachnodestatic(pm_postprocess,node,@OptimizeForLoop_iterforloops,nil); Result:=changedforloop; end; diff --git a/compiler/psub.pas b/compiler/psub.pas index 2866430aa5..3437264a41 100644 --- a/compiler/psub.pas +++ b/compiler/psub.pas @@ -1179,6 +1179,15 @@ implementation RedoDFA:=OptimizeInductionVariables(code); end; + if RedoDFA then + begin + dfabuilder.resetdfainfo(code); + dfabuilder.createdfainfo(code); + include(flags,pi_dfaavailable); + end; + + RedoDFA:=OptimizeForLoop(code); + RedoDFA:=ConvertForLoops(code) or RedoDFA; if RedoDFA then