2
0

optcse.pas 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. {
  2. Common subexpression elimination on base blocks
  3. Copyright (c) 2005-2012 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. {
  25. the function creates non optimal code so far:
  26. - call para nodes are cse barriers because they can be reordered and thus the
  27. temp. creation could be done too late
  28. - the cse knows nothing about register pressure. In case of high register pressure, cse might
  29. have a negative impact
  30. - the list of cseinvariant node types and inline numbers is not complete yet
  31. Further, it could be done probably in a faster way though the complexity can't probably not reduced
  32. }
  33. function do_optcse(var rootnode : tnode) : tnode;
  34. implementation
  35. uses
  36. globtype,globals,
  37. cutils,cclasses,
  38. nutils,compinnr,
  39. nbas,nld,ninl,ncal,nadd,nmem,
  40. pass_1,
  41. symconst,symdef,symsym,symtable,symtype,
  42. defutil,
  43. optbase;
  44. const
  45. cseinvariant : set of tnodetype = [addn,muln,subn,divn,slashn,modn,andn,orn,xorn,notn,vecn,
  46. derefn,equaln,unequaln,ltn,gtn,lten,gten,typeconvn,subscriptn,
  47. inn,symdifn,shrn,shln,ordconstn,realconstn,unaryminusn,pointerconstn,stringconstn,setconstn,niln,
  48. setelementn,{arrayconstructorn,arrayconstructorrangen,}
  49. isn,asn,starstarn,nothingn,temprefn,loadparentfpn {,callparan},assignn,addrn];
  50. function searchsubdomain(var n:tnode; arg: pointer) : foreachnoderesult;
  51. begin
  52. if (n.nodetype in cseinvariant) or
  53. ((n.nodetype=inlinen) and
  54. (tinlinenode(n).inlinenumber in [in_length_x,in_assigned_x,in_sqr_real,in_sqrt_real,in_sin_real,in_cos_real,in_abs_long,
  55. in_abs_real,in_exp_real,in_ln_real,in_pi_real,in_popcnt_x,in_arctan_real,in_round_real,in_trunc_real,
  56. { cse on fma will still not work because it would require proper handling of call nodes
  57. with more than one parameter }
  58. in_fma_single,in_fma_double,in_fma_extended,in_fma_float128,
  59. in_min_single,in_min_double,in_max_single,in_max_double,
  60. in_max_longint,in_max_dword,in_min_longint,in_min_dword
  61. ])
  62. ) or
  63. ((n.nodetype=callparan) and not(assigned(tcallparanode(n).right))) or
  64. ((n.nodetype=loadn) and
  65. not((tloadnode(n).symtableentry.typ in [staticvarsym,localvarsym,paravarsym]) and
  66. (vo_volatile in tabstractvarsym(tloadnode(n).symtableentry).varoptions))
  67. ) then
  68. result:=fen_true
  69. else
  70. begin
  71. pboolean(arg)^:=false;
  72. result:=fen_norecurse_true;
  73. end;
  74. end;
  75. type
  76. tlists = record
  77. nodelist : tfplist;
  78. locationlist : tfplist;
  79. equalto : tfplist;
  80. refs : tfplist;
  81. avail : TDFASet;
  82. end;
  83. plists = ^tlists;
  84. { collectnodes needs the address of itself to call foreachnodestatic,
  85. so we need a wrapper because @<func> inside <func doesn't work }
  86. function collectnodes(var n:tnode; arg: pointer) : foreachnoderesult;forward;
  87. function collectnodes2(var n:tnode; arg: pointer) : foreachnoderesult;
  88. begin
  89. result:=collectnodes(n,arg);
  90. end;
  91. function collectnodes(var n:tnode; arg: pointer) : foreachnoderesult;
  92. { when compiling a tree like
  93. and
  94. / \
  95. and C
  96. / \
  97. A B
  98. all expressions of B are available during evaluation of C. However considerung the whole expression,
  99. values of B and C might not be available due to short boolean evaluation.
  100. So recurseintobooleanchain detectes such chained and/or expressions and makes sub-expressions of B
  101. available during the evaluation of C
  102. firstleftend is later used to remove all sub expressions of B and C by storing the expression count
  103. in the cse table after handling A
  104. }
  105. var
  106. firstleftend : longint;
  107. procedure recurseintobooleanchain(t : tnodetype;n : tnode);
  108. begin
  109. if (tbinarynode(n).left.nodetype=t) and is_boolean(tbinarynode(n).left.resultdef) then
  110. recurseintobooleanchain(t,tbinarynode(n).left)
  111. else
  112. foreachnodestatic(pm_postprocess,tbinarynode(n).left,@collectnodes2,arg);
  113. firstleftend:=min(plists(arg)^.nodelist.count,firstleftend);
  114. foreachnodestatic(pm_postprocess,tbinarynode(n).right,@collectnodes2,arg);
  115. end;
  116. var
  117. i : longint;
  118. tempdef : tdef;
  119. begin
  120. result:=fen_false;
  121. { don't add the tree below an untyped const parameter: there is
  122. no information available that this kind of tree actually needs
  123. to be addresable, this could be improved }
  124. { the nodes below a type conversion node created for an absolute
  125. reference cannot be handled separately, because the absolute reference
  126. may have special requirements (no regability, must be in memory, ...)
  127. }
  128. if (((n.nodetype=callparan) and
  129. (tcallparanode(n).left.resultdef.typ=formaldef) and
  130. (tcallparanode(n).parasym.varspez=vs_const)) or
  131. ((n.nodetype=typeconvn) and
  132. (nf_absolute in n.flags))
  133. ) then
  134. begin
  135. result:=fen_norecurse_false;
  136. exit;
  137. end;
  138. if
  139. { node possible to add? }
  140. assigned(n.resultdef) and
  141. ((
  142. { regable expressions }
  143. (actualtargetnode(@n)^.flags*[nf_write,nf_modify,nf_address_taken]=[]) and
  144. (
  145. tstoreddef(n.resultdef).is_intregable or
  146. tstoreddef(n.resultdef).is_fpuregable or
  147. tstoreddef(n.resultdef).is_const_intregable
  148. ) and
  149. { is_int/fpuregable allows arrays and records to be in registers, cse cannot handle this }
  150. (
  151. not(n.resultdef.typ in [arraydef,recorddef]) or
  152. (
  153. (
  154. (n.resultdef.typ = recorddef) and
  155. tabstractrecordsymtable(tabstractrecorddef(n.resultdef).symtable).has_single_field(tempdef)
  156. ) or
  157. is_dynamic_array(n.resultdef) or
  158. (
  159. not(is_special_array(tstoreddef(n.resultdef))) and
  160. not(tstoreddef(n.resultdef).is_intregable) and
  161. not(tstoreddef(n.resultdef).is_fpuregable)
  162. )
  163. )
  164. ) and
  165. { same for voiddef }
  166. not(is_void(n.resultdef)) and
  167. { adding tempref and callpara nodes itself is worthless but
  168. their complexity is probably <= 1 anyways
  169. neither add setelementn nodes because the compiler sometimes depends on the fact
  170. that a certain node stays a setelementn, this does not hurt either because
  171. setelementn nodes itself generate no real code (except moving data into register) }
  172. not(n.nodetype in [temprefn,callparan,setelementn]) and
  173. { node worth to add?
  174. We consider almost every node because even loading a variables from
  175. a register instead of memory is more beneficial. This behaviour should
  176. not increase register pressure because if a variable is already
  177. in a register, the reg. allocator can merge the nodes. If a variable
  178. is loaded from memory, loading this variable and spilling another register
  179. should not add a speed penalty.
  180. }
  181. {
  182. load nodes are not considered if they load para or local symbols from the
  183. current stack frame, those are in registers anyways if possible
  184. }
  185. (not(actualtargetnode(@n)^.nodetype=loadn) or
  186. not(tloadnode(actualtargetnode(@n)^).symtableentry.typ in [paravarsym,localvarsym,staticvarsym]) or
  187. { apply cse on non-regable variables }
  188. ((tloadnode(actualtargetnode(@n)^).symtableentry.typ in [paravarsym,localvarsym,staticvarsym]) and
  189. not(tabstractvarsym(tloadnode(actualtargetnode(@n)^).symtableentry).is_regvar(true)) and
  190. not(vo_volatile in tabstractvarsym(tloadnode(actualtargetnode(@n)^).symtableentry).varoptions)) or
  191. (node_complexity(n)>1)
  192. ) and
  193. {
  194. Const nodes however are only considered if their complexity is >1
  195. This might be the case for the risc architectures if they need
  196. more than one instruction to load this particular value
  197. }
  198. (not(is_constnode(n)) or (node_complexity(n)>1)))
  199. {$if not(defined(i386)) and not(defined(i8086))}
  200. or
  201. { store reference of expression? }
  202. { loading the address of a global symbol takes typically more than
  203. one instruction on every platform except i8086/i386
  204. so consider in this case loading the address of the data
  205. }
  206. (((n.resultdef.typ in [arraydef,recorddef]) or is_object(n.resultdef)) and not(is_dynamic_array(n.resultdef)) and
  207. (n.nodetype=loadn) and
  208. (tloadnode(n).symtableentry.typ=staticvarsym)
  209. )
  210. {$endif not(defined(i386)) and not(defined(i8086))}
  211. ) then
  212. begin
  213. plists(arg)^.nodelist.Add(n);
  214. plists(arg)^.locationlist.Add(@n);
  215. plists(arg)^.refs.Add(nil);
  216. plists(arg)^.equalto.Add(pointer(-1));
  217. DFASetInclude(plists(arg)^.avail,plists(arg)^.nodelist.count-1);
  218. for i:=0 to plists(arg)^.nodelist.count-2 do
  219. begin
  220. if tnode(plists(arg)^.nodelist[i]).isequal(n) and DFASetIn(plists(arg)^.avail,i) then
  221. begin
  222. { use always the first occurence }
  223. if plists(arg)^.equalto[i]<>pointer(-1) then
  224. plists(arg)^.equalto[plists(arg)^.nodelist.count-1]:=plists(arg)^.equalto[i]
  225. else
  226. plists(arg)^.equalto[plists(arg)^.nodelist.count-1]:=pointer(ptrint(i));
  227. plists(arg)^.refs[i]:=pointer(plists(arg)^.refs[i])+1;
  228. { tree has been found, no need to search further,
  229. sub-trees have been added by the first occurence of
  230. the tree already }
  231. result:=fen_norecurse_false;
  232. break;
  233. end;
  234. end;
  235. end;
  236. { boolean and/or require a special handling: after evaluating the and/or node,
  237. the expressions of the right side might not be available due to short boolean
  238. evaluation, so after handling the right side, mark those expressions
  239. as unavailable }
  240. if (n.nodetype in [orn,andn]) and is_boolean(taddnode(n).left.resultdef) then
  241. begin
  242. firstleftend:=high(longint);
  243. recurseintobooleanchain(n.nodetype,n);
  244. for i:=firstleftend to plists(arg)^.nodelist.count-1 do
  245. DFASetExclude(plists(arg)^.avail,i);
  246. result:=fen_norecurse_false;
  247. end;
  248. {$ifdef cpuhighleveltarget}
  249. { The high level targets use the functionality from ncgnstld for
  250. nested accesses, and that one stores the complete location of the
  251. nested variable in tloadnode.left rather than only the location of
  252. the parent context containing it. This causes problems with the
  253. CSE in case the nested variable is used as an lvalue, so disable
  254. CSE in that case
  255. }
  256. if (n.nodetype=loadn) and assigned(tloadnode(n).left) then
  257. result:=fen_norecurse_false;
  258. {$endif}
  259. end;
  260. function searchcsedomain(var n: tnode; arg: pointer) : foreachnoderesult;
  261. var
  262. csedomain : boolean;
  263. lists : tlists;
  264. templist : tfplist;
  265. i : longint;
  266. def : tstoreddef;
  267. nodes : tblocknode;
  268. creates,
  269. statements : tstatementnode;
  270. deletetemp : ttempdeletenode;
  271. hp : ttempcreatenode;
  272. addrstored : boolean;
  273. hp2 : tnode;
  274. begin
  275. result:=fen_false;
  276. nodes:=nil;
  277. if (n.nodetype in cseinvariant) and
  278. { a setelement node is cseinvariant, but it might not be replaced by a block so
  279. it cannot be the root of the cse search }
  280. (n.nodetype<>setelementn) then
  281. begin
  282. csedomain:=true;
  283. foreachnodestatic(pm_postprocess,n,@searchsubdomain,@csedomain);
  284. if not(csedomain) then
  285. begin
  286. { try to transform the tree to get better cse domains, consider:
  287. + (1)
  288. / \
  289. (2) + C
  290. / \
  291. A B
  292. if A is not cse'able but B and C are, then the compiler cannot do cse so the tree is transformed into
  293. +
  294. / \
  295. A +
  296. / \
  297. B C
  298. Because A could be another tree of this kind, the whole process is done in a while loop
  299. }
  300. if (n.nodetype in [andn,orn,addn,muln]) and
  301. (n.nodetype=tbinarynode(n).left.nodetype) and
  302. { do is optimizations only for integers, reals (no currency!), vectors, sets or booleans }
  303. (is_integer(n.resultdef) or is_real(n.resultdef) or is_vector(n.resultdef) or is_set(n.resultdef) or
  304. is_boolean(n.resultdef)) and
  305. { either if fastmath is on }
  306. ((cs_opt_fastmath in current_settings.optimizerswitches) or
  307. { or for the logical operators, they cannot overflow }
  308. (n.nodetype in [andn,orn]) or
  309. { or for integers if range checking is off }
  310. ((is_integer(n.resultdef) and
  311. (n.localswitches*[cs_check_range,cs_check_overflow]=[]) and
  312. (tbinarynode(n).left.localswitches*[cs_check_range,cs_check_overflow]=[]))) or
  313. { for sets, we can do this always }
  314. (is_set(n.resultdef))
  315. ) then
  316. while (n.nodetype=tbinarynode(n).left.nodetype) and
  317. { if node (1) is fully boolean evaluated and node (2) not, we cannot do the swap as this might result in B being evaluated always,
  318. the other way round is no problem, C is still evaluated only if needed }
  319. (not(is_boolean(n.resultdef)) or not(n.nodetype in [andn,orn]) or doshortbooleval(n) or not(doshortbooleval(tbinarynode(n).left))) and
  320. { the resulttypes of the operands we'll swap must be equal,
  321. required in case of a 32x32->64 multiplication, then we
  322. cannot swap out one of the 32 bit operands for a 64 bit one
  323. }
  324. (tbinarynode(tbinarynode(n).left).left.resultdef=tbinarynode(n).left.resultdef) and
  325. (tbinarynode(n).left.resultdef=tbinarynode(n).right.resultdef) do
  326. begin
  327. csedomain:=true;
  328. foreachnodestatic(pm_postprocess,tbinarynode(n).right,@searchsubdomain,@csedomain);
  329. if csedomain then
  330. begin
  331. csedomain:=true;
  332. foreachnodestatic(pm_postprocess,tbinarynode(tbinarynode(n).left).right,@searchsubdomain,@csedomain);
  333. if csedomain then
  334. begin
  335. { move the full boolean evaluation of (2) to (1), if it was there (so it again applies to A and
  336. what follows) }
  337. if not(doshortbooleval(tbinarynode(n).left)) and
  338. doshortbooleval(n) then
  339. begin
  340. n.localswitches:=n.localswitches+(tbinarynode(n).left.localswitches*[cs_full_boolean_eval]);
  341. exclude(tbinarynode(n).left.localswitches,cs_full_boolean_eval);
  342. tbinarynode(n).left.flags:=tbinarynode(n).left.flags+(n.flags*[nf_short_bool]);
  343. exclude(n.Flags,nf_short_bool);
  344. end;
  345. hp2:=tbinarynode(tbinarynode(n).left).left;
  346. tbinarynode(tbinarynode(n).left).left:=tbinarynode(tbinarynode(n).left).right;
  347. tbinarynode(tbinarynode(n).left).right:=tbinarynode(n).right;
  348. tbinarynode(n).right:=tbinarynode(n).left;
  349. tbinarynode(n).left:=hp2;
  350. { the transformed tree could result in new possibilities to fold constants
  351. so force a firstpass on the root node }
  352. exclude(tbinarynode(n).right.flags,nf_pass1_done);
  353. do_firstpass(tbinarynode(n).right);
  354. end
  355. else
  356. break;
  357. end
  358. else
  359. break;
  360. end;
  361. end
  362. else
  363. begin
  364. statements:=nil;
  365. result:=fen_norecurse_true;
  366. {$ifdef csedebug}
  367. writeln('============ cse domain ==================');
  368. printnode(output,n);
  369. writeln('Complexity: ',node_complexity(n));
  370. {$endif csedebug}
  371. lists.nodelist:=tfplist.create;
  372. lists.locationlist:=tfplist.create;
  373. lists.equalto:=tfplist.create;
  374. lists.refs:=tfplist.create;
  375. foreachnodestatic(pm_postprocess,n,@collectnodes,@lists);
  376. templist:=tfplist.create;
  377. templist.count:=lists.nodelist.count;
  378. { check all nodes if one is used more than once }
  379. for i:=0 to lists.nodelist.count-1 do
  380. begin
  381. { current node used more than once? }
  382. if assigned(lists.refs[i]) then
  383. begin
  384. if not(assigned(statements)) then
  385. begin
  386. nodes:=internalstatements(statements);
  387. addstatement(statements,internalstatements(creates));
  388. end;
  389. def:=tstoreddef(tnode(lists.nodelist[i]).resultdef);
  390. { we cannot handle register stored records or array in CSE yet
  391. but we can store their reference }
  392. addrstored:=((def.typ in [arraydef,recorddef]) or is_object(def)) and not(is_dynamic_array(def));
  393. if addrstored then
  394. templist[i]:=ctempcreatenode.create_value(cpointerdef.getreusable(def),voidpointertype.size,tt_persistent,
  395. true,caddrnode.create_internal(tnode(lists.nodelist[i])))
  396. else
  397. templist[i]:=ctempcreatenode.create_value(def,def.size,tt_persistent,
  398. def.is_intregable or def.is_fpuregable or def.is_const_intregable,tnode(lists.nodelist[i]));
  399. { the value described by the temp. is immutable and the temp. can be always in register
  400. ttempcreatenode.create normally takes care of the register location but it does not
  401. know about immutability so it cannot take care of managed types }
  402. ttempcreatenode(templist[i]).includetempflag(ti_const);
  403. ttempcreatenode(templist[i]).includetempflag(ti_may_be_in_reg);
  404. { make debugging easier and set temp. location to the original location }
  405. tnode(templist[i]).fileinfo:=tnode(lists.nodelist[i]).fileinfo;
  406. addstatement(creates,tnode(templist[i]));
  407. { the delete node has no semantic use yet, it is just used to clean up memory }
  408. deletetemp:=ctempdeletenode.create(ttempcreatenode(templist[i]));
  409. deletetemp.includetempflag(ti_cleanup_only);
  410. addstatement(tstatementnode(arg^),deletetemp);
  411. { make debugging easier and set temp. location to the original location }
  412. creates.fileinfo:=tnode(lists.nodelist[i]).fileinfo;
  413. hp:=ttempcreatenode(templist[i]);
  414. do_firstpass(tnode(hp));
  415. templist[i]:=hp;
  416. if addrstored then
  417. pnode(lists.locationlist[i])^:=cderefnode.Create(ctemprefnode.create(ttempcreatenode(templist[i])))
  418. else
  419. pnode(lists.locationlist[i])^:=ctemprefnode.create(ttempcreatenode(templist[i]));
  420. { make debugging easier and set temp. location to the original location }
  421. pnode(lists.locationlist[i])^.fileinfo:=tnode(lists.nodelist[i]).fileinfo;
  422. do_firstpass(pnode(lists.locationlist[i])^);
  423. {$ifdef csedebug}
  424. printnode(output,statements);
  425. {$endif csedebug}
  426. end
  427. { current node reference to another node? }
  428. else if lists.equalto[i]<>pointer(-1) then
  429. begin
  430. def:=tstoreddef(tnode(lists.nodelist[i]).resultdef);
  431. { we cannot handle register stored records or array in CSE yet
  432. but we can store their reference }
  433. addrstored:=((def.typ in [arraydef,recorddef]) or is_object(def)) and not(is_dynamic_array(def));
  434. {$if defined(csedebug) or defined(csestats)}
  435. writeln;
  436. writeln('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
  437. writeln('Complexity: ',node_complexity(tnode(lists.nodelist[i])),' Node ',i,' equals Node ',ptrint(lists.equalto[i]));
  438. printnode(output,tnode(lists.nodelist[i]));
  439. printnode(output,tnode(lists.nodelist[ptrint(lists.equalto[i])]));
  440. writeln('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
  441. writeln;
  442. {$endif defined(csedebug) or defined(csestats)}
  443. templist[i]:=templist[ptrint(lists.equalto[i])];
  444. if addrstored then
  445. pnode(lists.locationlist[i])^:=cderefnode.Create(ctemprefnode.create(ttempcreatenode(templist[ptrint(lists.equalto[i])])))
  446. else
  447. pnode(lists.locationlist[i])^:=ctemprefnode.create(ttempcreatenode(templist[ptrint(lists.equalto[i])]));
  448. { make debugging easier and set temp. location to the original location }
  449. pnode(lists.locationlist[i])^.fileinfo:=tnode(lists.nodelist[i]).fileinfo;
  450. do_firstpass(pnode(lists.locationlist[i])^);
  451. end;
  452. end;
  453. { clean up unused trees }
  454. for i:=0 to lists.nodelist.count-1 do
  455. if lists.equalto[i]<>pointer(-1) then
  456. tnode(lists.nodelist[i]).free;
  457. {$ifdef csedebug}
  458. writeln('nodes: ',lists.nodelist.count);
  459. writeln('==========================================');
  460. {$endif csedebug}
  461. lists.nodelist.free;
  462. lists.locationlist.free;
  463. lists.equalto.free;
  464. lists.refs.free;
  465. templist.free;
  466. if assigned(statements) then
  467. begin
  468. { call para nodes need a special handling because
  469. they can be only children nodes of call nodes
  470. so the initialization code is inserted below the
  471. call para node
  472. }
  473. if n.nodetype=callparan then
  474. begin
  475. addstatement(statements,tcallparanode(n).left);
  476. tcallparanode(n).left:=nodes;
  477. do_firstpass(tcallparanode(n).left);
  478. end
  479. else
  480. begin
  481. addstatement(statements,n);
  482. n:=nodes;
  483. do_firstpass(n);
  484. end;
  485. {$ifdef csedebug}
  486. printnode(output,nodes);
  487. {$endif csedebug}
  488. end;
  489. end
  490. end;
  491. end;
  492. function do_optcse(var rootnode : tnode) : tnode;
  493. var
  494. deletes,
  495. statements : tstatementnode;
  496. deleteblock,
  497. rootblock : tblocknode;
  498. begin
  499. {$ifdef csedebug}
  500. writeln('====================================================================================');
  501. writeln('CSE optimization pass started');
  502. writeln('====================================================================================');
  503. printnode(rootnode);
  504. writeln('====================================================================================');
  505. writeln;
  506. {$endif csedebug}
  507. deleteblock:=internalstatements(deletes);
  508. foreachnodestatic(pm_postprocess,rootnode,@searchcsedomain,@deletes);
  509. rootblock:=internalstatements(statements);
  510. addstatement(statements,rootnode);
  511. addstatement(statements,deleteblock);
  512. rootnode:=rootblock;
  513. do_firstpass(rootnode);
  514. {$ifdef csedebug}
  515. writeln('====================================================================================');
  516. writeln('CSE optimization result');
  517. writeln('====================================================================================');
  518. printnode(rootnode);
  519. writeln('====================================================================================');
  520. writeln;
  521. {$endif csedebug}
  522. result:=nil;
  523. end;
  524. end.