diff options
author | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-29 20:02:32 +0000 |
---|---|---|
committer | florian <florian@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2005-05-29 20:02:32 +0000 |
commit | a37575485da08136c3f52c402e2e723828b837ce (patch) | |
tree | 842f183088333cad2d2ed92705281291e33a428a | |
parent | 4622d670b16a411d1fe47bae713b1ad92c46a3eb (diff) | |
download | fpc-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.pas | 56 | ||||
-rw-r--r-- | nodeopt/compiler/optunrol.pas | 129 |
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. |