* improved for loop unrolling

git-svn-id: trunk@22320 -
This commit is contained in:
florian 2012-09-04 21:34:00 +00:00
parent 2f1989c1a6
commit 9773b92cbe

View File

@ -60,6 +60,34 @@ unit optloop;
number_unrolls:=1; number_unrolls:=1;
end; end;
type
treplaceinfo = record
loadnode : tloadnode;
value : Tconstexprint;
end;
preplaceinfo = ^treplaceinfo;
function checkbreakcontinue(var n:tnode; arg: pointer): foreachnoderesult;
begin
if n.nodetype in [breakn,continuen] then
result:=fen_norecurse_true
else
result:=fen_false;
end;
function replaceloadnodes(var n: tnode; arg: pointer): foreachnoderesult;
begin
if (n.nodetype=loadn) and (tloadnode(n).symtableentry=preplaceinfo(arg)^.loadnode.symtableentry) then
begin
if n.flags*[nf_modify,nf_write]<>[] then
internalerror(2012090402);
n.free;
n:=cordconstnode.create(preplaceinfo(arg)^.value,preplaceinfo(arg)^.loadnode.resultdef,false);
end;
result:=fen_false;
end;
function unroll_loop(node : tnode) : tnode; function unroll_loop(node : tnode) : tnode;
var var
@ -67,6 +95,8 @@ unit optloop;
counts : qword; counts : qword;
unrollstatement,newforstatement : tstatementnode; unrollstatement,newforstatement : tstatementnode;
unrollblock : tblocknode; unrollblock : tblocknode;
getridoffor : boolean;
replaceinfo : treplaceinfo;
begin begin
result:=nil; result:=nil;
if (cs_opt_size in current_settings.optimizerswitches) then if (cs_opt_size in current_settings.optimizerswitches) then
@ -84,13 +114,28 @@ unit optloop;
else else
counts:=tordconstnode(tfornode(node).t1).value-tordconstnode(tfornode(node).right).value+1; counts:=tordconstnode(tfornode(node).t1).value-tordconstnode(tfornode(node).right).value+1;
{ don't unroll more than we need } { don't unroll more than we need,
if unrolls>counts then
multiply unroll by two here because we can get rid
of the counter variable completely and replace it by a constant
if unrolls=counts }
if unrolls*2>counts then
unrolls:=counts; unrolls:=counts;
{ create block statement } { create block statement }
unrollblock:=internalstatements(unrollstatement); unrollblock:=internalstatements(unrollstatement);
{ can we get rid completly of the for ? }
getridoffor:=(unrolls=counts) and not(foreachnodestatic(tfornode(node).t2,@checkbreakcontinue,nil));
if getridoffor then
begin
if tfornode(node).left.nodetype<>loadn then
internalerror(2012090301);
replaceinfo.loadnode:=tloadnode(tfornode(node).left);
replaceinfo.value:=tordconstnode(tfornode(node).right).value;
end;
{ let's unroll (and rock of course) } { let's unroll (and rock of course) }
for i:=1 to unrolls do for i:=1 to unrolls do
begin begin
@ -105,26 +150,34 @@ unit optloop;
addstatement(unrollstatement,tfornode(node).entrylabel); addstatement(unrollstatement,tfornode(node).entrylabel);
end; end;
{ for itself increases at the last iteration } if getridoffor then
if i<unrolls then begin
begin foreachnodestatic(tnode(unrollstatement),@replaceloadnodes,@replaceinfo);
{ insert incr/decrementation of counter var } if lnf_backward in tfornode(node).loopflags then
if lnf_backward in tfornode(node).loopflags then replaceinfo.value:=replaceinfo.value-1
addstatement(unrollstatement, else
geninlinenode(in_dec_x,false,ccallparanode.create(tfornode(node).left.getcopy,nil))) replaceinfo.value:=replaceinfo.value+1;
end
else else
addstatement(unrollstatement, begin
geninlinenode(in_inc_x,false,ccallparanode.create(tfornode(node).left.getcopy,nil))); { for itself increases at the last iteration }
end; if i<unrolls then
begin
{ insert incr/decrementation of counter var }
if lnf_backward in tfornode(node).loopflags then
addstatement(unrollstatement,
geninlinenode(in_dec_x,false,ccallparanode.create(tfornode(node).left.getcopy,nil)))
else
addstatement(unrollstatement,
geninlinenode(in_inc_x,false,ccallparanode.create(tfornode(node).left.getcopy,nil)));
end;
end;
end; end;
{ can we get rid of the for statement? } { can we get rid of the for statement? }
if unrolls=counts then if getridoffor then
begin begin
{ create block statement } { create block statement }
result:=internalstatements(newforstatement); result:=internalstatements(newforstatement);
{ initial assignment }
addstatement(newforstatement,cassignmentnode.create(
tfornode(node).left.getcopy,tfornode(node).right.getcopy));
addstatement(newforstatement,unrollblock); addstatement(newforstatement,unrollblock);
end; end;
end end