summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2005-05-29 20:02:32 +0000
committerflorian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2>2005-05-29 20:02:32 +0000
commita37575485da08136c3f52c402e2e723828b837ce (patch)
tree842f183088333cad2d2ed92705281291e33a428a
parent4622d670b16a411d1fe47bae713b1ad92c46a3eb (diff)
downloadfpc-a37575485da08136c3f52c402e2e723828b837ce.tar.gz
+ new files added
git-svn-id: http://svn.freepascal.org/svn/fpc/branches/florian@148 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r--nodeopt/compiler/optcse.pas56
-rw-r--r--nodeopt/compiler/optunrol.pas129
2 files changed, 185 insertions, 0 deletions
diff --git a/nodeopt/compiler/optcse.pas b/nodeopt/compiler/optcse.pas
new file mode 100644
index 0000000000..87825ac1ed
--- /dev/null
+++ b/nodeopt/compiler/optcse.pas
@@ -0,0 +1,56 @@
+unit optcse;
+
+ interface
+
+ procedure docse(rootnode : tnode);
+
+ implementation
+
+ procedure docse(rootnode : tnode);
+ begin
+ { create a linear list of nodes }
+
+ { create hash values }
+
+ { sort by hash values, taking care of nf_csebarrier and keeping the
+ original order of the nodes }
+
+ { compare nodes with equal hash values }
+
+ { search barrier }
+ for i:=0 to nodelist.length-1 do
+ begin
+ { and then search backward so we get always the largest equal trees }
+ j:=i+1;
+ { collect equal nodes }
+ while (j<=nodelist.length-1) and
+ nodelist[i].docompare(nodelist[j]) do
+ inc(j);
+ dec(j);
+ if j>i then
+ begin
+ { cse found }
+
+ { create temp. location }
+
+ { replace first node by
+ - temp. creation
+ - expression calculation
+ - assignment of expression to temp. }
+ tempnode:=ctempcreatenode.create(nodelist[i].resulttype,nodelist[i].resulttype.def.size,tt_persistent,
+ nodelist[i].resulttype.def.is_intregable or nodelist[i].resulttype.def.is_fpuregable);
+ addstatement(createstatement,tempnode);
+ addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
+ caddrnode.create_internal(para.left)));
+ para.left := ctypeconvnode.create_internal(cderefnode.create(ctemprefnode.create(tempnode)),para.left.resulttype);
+ addstatement(deletestatement,ctempdeletenode.create(tempnode));
+
+ { replace next nodes by loading the temp. reference }
+
+ { replace last node by loading the temp. reference and
+ delete the temp. }
+ end;
+ end;
+ end;
+
+end.
diff --git a/nodeopt/compiler/optunrol.pas b/nodeopt/compiler/optunrol.pas
new file mode 100644
index 0000000000..49f1fadde7
--- /dev/null
+++ b/nodeopt/compiler/optunrol.pas
@@ -0,0 +1,129 @@
+unit optunrol;
+
+{$i fpcdefs.inc}
+
+ interface
+
+ uses
+ node;
+
+ type
+ tunrollinfo = record
+ { if count isn divisable by unrolls then
+ the for loop must jump to this label to get the correct
+ number of executions }
+ entrylabel : tnode;
+ end;
+
+ function unroll_loop(node : tnode;out unrollinfo : tunrollinfo) : tnode;
+
+ implementation
+
+ uses
+ globtype,globals,
+ cpuinfo,
+ nutils,
+ nbas,nflw,ncon,ninl,ncal;
+
+ var
+ nodecount : aint;
+
+ function donodecount(var n: tnode; arg: pointer): foreachnoderesult;
+ begin
+ inc(nodecount);
+ result:=fen_false;
+ end;
+
+
+ { rough estimation how large the tree "node" is }
+ function countnodes(node : tnode) : aint;
+ begin
+ nodecount:=0;
+ foreachnodestatic(node,@donodecount,nil);
+ result:=nodecount;
+ end;
+
+
+ function number_unrolls(node : tnode) : integer;
+ begin
+ { multiply by 2 for CPUs with a long pipeline }
+ if aktoptprocessor in [ClassPentium4] then
+ number_unrolls:=60 div countnodes(node)
+ else
+ number_unrolls:=30 div countnodes(node);
+
+ if number_unrolls=0 then
+ number_unrolls:=1;
+ end;
+
+
+ function unroll_loop(node : tnode) : tnode;
+ var
+ unrolls,i : integer;
+ counts : qword;
+ unrollstatement : tstatementnode;
+ unrollblock : tblocknode;
+ entrylabel : tlabelnode;
+ begin
+ result:=nil;
+ if (cs_littlesize in aktglobalswitches) then
+ exit;
+ if not(node.nodetype in [forn]) then
+ exit;
+ fillchar(tfornode(node).unrollinfo,sizeof(tunrollinfo),0);
+ unrolls:=number_unrolls(tfornode(node).t2);
+ if unrolls>1 then
+ begin
+ { number of executions known? }
+ if (tfornode(node).right.nodetype=ordconstn) and (tfornode(node).t1.nodetype=ordconstn) then
+ begin
+ if lnf_backward in tfornode(node).loopflags then
+ counts:=tordconstnode(tfornode(node).right).value-tordconstnode(tfornode(node).t1).value+1
+ else
+ counts:=tordconstnode(tfornode(node).t1).value-tordconstnode(tfornode(node).right).value+1;
+
+ { don't unroll more than we need }
+ if unrolls>counts then
+ unrolls:=counts;
+
+ { create block statement }
+ unrollblock:=internalstatements(unrollstatement);
+
+ { let's unroll (and rock of course) }
+ for i:=1 to unrolls do
+ begin
+ { set and insert entry label? }
+ if (counts mod unrolls<>0) and
+ ((counts mod unrolls)=unrolls-i+1) then
+ begin
+ tfornode(node).unrollinfo.entrylabel:=clabelnode.createcase(
+ end;
+ { create and insert copy of the statement block }
+ addstatement(unrollstatement,tfornode(tfornode(node).t2).getcopy);
+
+ { for itself increases at the last iteration }
+ if i<unrolls then
+ begin
+ { insert incrementation of counter var }
+ addstatement(unrollstatement,
+ geninlinenode(in_inc_x,false,ccallparanode.create(tfornode(node).left.getcopy,nil)));
+ end;
+ end;
+ { can we get rid of the for statement? }
+ if unrolls=counts then
+ result:=unrollblock;
+ end
+ else
+ begin
+ { for now, we can't handle this }
+ exit;
+ end;
+ if not(assigned(result)) then
+ begin
+ tfornode(node).t2.free;
+ tfornode(node).t2:=unrollblock;
+ end;
+ end;
+ end;
+
+end.