optcse.pas 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. {
  2. Common subexpression elimination on base blocks
  3. Copyright (c) 2005 by Florian Klaempfl
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit optcse;
  18. {$i fpcdefs.inc}
  19. { $define csedebug}
  20. { $define csestats}
  21. interface
  22. uses
  23. node;
  24. function do_optcse(var rootnode : tnode) : tnode;
  25. implementation
  26. uses
  27. globtype,
  28. cclasses,
  29. verbose,
  30. nutils,
  31. nbas,nld,
  32. pass_1,
  33. symtype,symdef;
  34. const
  35. cseinvariant : set of tnodetype = [loadn,addn,muln,subn,divn,slashn,modn,andn,orn,xorn,notn,vecn,
  36. derefn,equaln,unequaln,ltn,gtn,lten,gten,typeconvn,subscriptn,
  37. inn,symdifn,shrn,shln,ordconstn,realconstn,unaryminusn,pointerconstn,stringconstn,setconstn,
  38. isn,asn,starstarn,nothingn];
  39. function searchsubdomain(var n:tnode; arg: pointer) : foreachnoderesult;
  40. begin
  41. if not(n.nodetype in cseinvariant) then
  42. begin
  43. pboolean(arg)^:=false;
  44. result:=fen_norecurse_true;
  45. end
  46. else
  47. result:=fen_true;
  48. end;
  49. type
  50. tlists = record
  51. nodelist : tfplist;
  52. locationlist : tfplist;
  53. end;
  54. plists = ^tlists;
  55. function collectnodes(var n:tnode; arg: pointer) : foreachnoderesult;
  56. begin
  57. result:=fen_false;
  58. { node worth to add? }
  59. if (node_complexity(n)>1) and (tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable) and
  60. { adding tempref nodes is worthless but their complexity is probably <= 1 anyways }
  61. not(n.nodetype in [temprefn]) then
  62. begin
  63. plists(arg)^.nodelist.Add(n);
  64. plists(arg)^.locationlist.Add(@n);
  65. end;
  66. {
  67. else
  68. result:=fen_norecurse_false;
  69. }
  70. end;
  71. function searchcsedomain(var n: tnode; arg: pointer) : foreachnoderesult;
  72. var
  73. csedomain : boolean;
  74. lists : tlists;
  75. templist : tfplist;
  76. i,j : longint;
  77. def : tstoreddef;
  78. nodes : tblocknode;
  79. creates,
  80. statements : tstatementnode;
  81. hp : ttempcreatenode;
  82. begin
  83. result:=fen_false;
  84. if n.nodetype in cseinvariant then
  85. begin
  86. csedomain:=true;
  87. foreachnodestatic(pm_postprocess,n,@searchsubdomain,@csedomain);
  88. { found a cse domain }
  89. if csedomain then
  90. begin
  91. statements:=nil;
  92. result:=fen_norecurse_true;
  93. {$ifdef csedebug}
  94. writeln('============ cse domain ==================');
  95. printnode(output,n);
  96. writeln('Complexity: ',node_complexity(n));
  97. {$endif csedebug}
  98. lists.nodelist:=tfplist.create;
  99. lists.locationlist:=tfplist.create;
  100. foreachnodestatic(pm_postprocess,n,@collectnodes,@lists);
  101. templist:=tfplist.create;
  102. templist.count:=lists.nodelist.count;
  103. { this is poorly coded, just comparing every node with all other nodes }
  104. for i:=0 to lists.nodelist.count-1 do
  105. for j:=i+1 to lists.nodelist.count-1 do
  106. begin
  107. if not(tnode(lists.nodelist[i]).nodetype in [tempcreaten,temprefn]) and
  108. tnode(lists.nodelist[i]).isequal(tnode(lists.nodelist[j])) then
  109. begin
  110. if not(assigned(statements)) then
  111. begin
  112. nodes:=internalstatements(statements);
  113. addstatement(statements,internalstatements(creates));
  114. end;
  115. {$if defined(csedebug) or defined(csestats)}
  116. writeln(' ==== ');
  117. printnode(output,tnode(lists.nodelist[i]));
  118. writeln(' equals ');
  119. printnode(output,tnode(lists.nodelist[j]));
  120. writeln(' ==== ');
  121. {$endif defined(csedebug) or defined(csestats)}
  122. def:=tstoreddef(tnode(lists.nodelist[i]).resultdef);
  123. if assigned(def) then
  124. begin
  125. if assigned(templist[i]) then
  126. begin
  127. templist[j]:=templist[i];
  128. pnode(lists.locationlist[j])^.free;
  129. pnode(lists.locationlist[j])^:=ctemprefnode.create(ttempcreatenode(templist[j]));
  130. do_firstpass(pnode(lists.locationlist[j])^);
  131. end
  132. else
  133. begin
  134. templist[i]:=ctempcreatenode.create(def,def.size,tt_persistent,
  135. def.is_intregable or def.is_fpuregable);
  136. addstatement(creates,tnode(templist[i]));
  137. { properties can't be passed by "var" }
  138. hp:=ttempcreatenode(templist[i]);
  139. do_firstpass(tnode(hp));
  140. addstatement(statements,cassignmentnode.create(ctemprefnode.create(ttempcreatenode(templist[i])),
  141. tnode(lists.nodelist[i])));
  142. pnode(lists.locationlist[i])^:=ctemprefnode.create(ttempcreatenode(templist[i]));
  143. do_firstpass(pnode(lists.locationlist[i])^);
  144. templist[j]:=templist[i];
  145. pnode(lists.locationlist[j])^.free;
  146. pnode(lists.locationlist[j])^:=ctemprefnode.create(ttempcreatenode(templist[j]));
  147. do_firstpass(pnode(lists.locationlist[j])^);
  148. {$ifdef csedebug}
  149. printnode(output,statements);
  150. {$endif csedebug}
  151. end;
  152. end
  153. else
  154. internalerror(2007091701);
  155. end;
  156. end;
  157. if assigned(statements) then
  158. begin
  159. addstatement(statements,n);
  160. n:=nodes;
  161. do_firstpass(n);
  162. {$ifdef csedebug}
  163. printnode(output,nodes);
  164. {$endif csedebug}
  165. end;
  166. {$ifdef csedebug}
  167. writeln('nodes: ',lists.nodelist.count);
  168. writeln('==========================================');
  169. {$endif csedebug}
  170. lists.nodelist.free;
  171. lists.locationlist.free;
  172. templist.free;
  173. end
  174. end;
  175. end;
  176. function do_optcse(var rootnode : tnode) : tnode;
  177. begin
  178. foreachnodestatic(pm_postprocess,rootnode,@searchcsedomain,nil);
  179. result:=nil;
  180. (*
  181. { create a linear list of nodes }
  182. { create hash values }
  183. { sort by hash values, taking care of nf_csebarrier and keeping the
  184. original order of the nodes }
  185. { compare nodes with equal hash values }
  186. { search barrier }
  187. for i:=0 to nodelist.length-1 do
  188. begin
  189. { and then search backward so we get always the largest equal trees }
  190. j:=i+1;
  191. { collect equal nodes }
  192. while (j<=nodelist.length-1) and
  193. nodelist[i].isequal(nodelist[j]) do
  194. inc(j);
  195. dec(j);
  196. if j>i then
  197. begin
  198. { cse found }
  199. { create temp. location }
  200. { replace first node by
  201. - temp. creation
  202. - expression calculation
  203. - assignment of expression to temp. }
  204. tempnode:=ctempcreatenode.create(nodelist[i].resultdef,nodelist[i].resultdef.size,tt_persistent,
  205. nodelist[i].resultdef.is_intregable or nodelist[i].resultdef.is_fpuregable);
  206. addstatement(createstatement,tempnode);
  207. addstatement(createstatement,cassignmentnode.create(ctemprefnode.create(tempnode),
  208. caddrnode.create_internal(para.left)));
  209. para.left := ctypeconvnode.create_internal(cderefnode.create(ctemprefnode.create(tempnode)),para.left.resultdef);
  210. addstatement(deletestatement,ctempdeletenode.create(tempnode));
  211. { replace next nodes by loading the temp. reference }
  212. { replace last node by loading the temp. reference and
  213. delete the temp. }
  214. end;
  215. end;
  216. *)
  217. end;
  218. end.