optdfa.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
  1. {
  2. DFA
  3. Copyright (c) 2007 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. { $define DEBUG_DFA}
  18. { $define EXTDEBUG_DFA}
  19. { this unit implements routines to perform dfa }
  20. unit optdfa;
  21. {$i fpcdefs.inc}
  22. interface
  23. uses
  24. node,optutils;
  25. type
  26. TDFABuilder = class
  27. protected
  28. procedure CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
  29. public
  30. resultnode : tnode;
  31. nodemap : TIndexedNodeSet;
  32. { reset all dfa info, this is required before creating dfa info
  33. if the tree has been changed without updating dfa }
  34. procedure resetdfainfo(node : tnode);
  35. procedure createdfainfo(node : tnode);
  36. destructor destroy;override;
  37. end;
  38. implementation
  39. uses
  40. globtype,globals,
  41. verbose,
  42. cpuinfo,
  43. symconst,symdef,
  44. defutil,
  45. procinfo,
  46. nutils,
  47. nbas,nflw,ncon,ninl,ncal,nset,
  48. optbase;
  49. (*
  50. function initnodes(var n:tnode; arg: pointer) : foreachnoderesult;
  51. begin
  52. { node worth to add? }
  53. if (node_complexity(n)>1) and (tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable) then
  54. begin
  55. plists(arg)^.nodelist.Add(n);
  56. plists(arg)^.locationlist.Add(@n);
  57. result:=fen_false;
  58. end
  59. else
  60. result:=fen_norecurse_false;
  61. end;
  62. *)
  63. {
  64. x:=f; read: [f]
  65. while x do read: []
  66. a:=b; read: [a,b,d] def: [a] life: read*def=[a]
  67. c:=d; read: [a,d] def: [a,c] life: read*def=[a]
  68. e:=a; read: [a] def: [a,c,e] life: read*def=[a]
  69. function f(b,d,x : type) : type;
  70. begin
  71. while x do alive: b,d,x
  72. begin
  73. a:=b; alive: b,d,x
  74. c:=d; alive: a,d,x
  75. e:=a+c; alive: a,c,x
  76. dec(x); alive: c,e,x
  77. end;
  78. result:=c+e; alive: c,e
  79. end; alive: result
  80. }
  81. type
  82. tdfainfo = record
  83. use : PDFASet;
  84. def : PDFASet;
  85. map : TIndexedNodeSet
  86. end;
  87. pdfainfo = ^tdfainfo;
  88. function AddDefUse(var n: tnode; arg: pointer): foreachnoderesult;
  89. begin
  90. case n.nodetype of
  91. loadn:
  92. begin
  93. pdfainfo(arg)^.map.Add(n);
  94. if nf_modify in n.flags then
  95. begin
  96. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  97. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  98. end
  99. else if nf_write in n.flags then
  100. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  101. else
  102. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  103. {
  104. write('Use Set: ');
  105. PrintDFASet(output,pdfainfo(arg)^.use^);
  106. write(' Def Set: ');
  107. PrintDFASet(output,pdfainfo(arg)^.def^);
  108. writeln;
  109. }
  110. end;
  111. end;
  112. result:=fen_false;
  113. end;
  114. function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
  115. begin
  116. exclude(n.flags,nf_processing);
  117. result:=fen_false;
  118. end;
  119. function ResetDFA(var n: tnode; arg: pointer): foreachnoderesult;
  120. begin
  121. if assigned(n.optinfo) then
  122. begin
  123. with n.optinfo^ do
  124. begin
  125. life:=nil;
  126. def:=nil;
  127. use:=nil;
  128. defsum:=nil;
  129. end;
  130. end;
  131. result:=fen_false;
  132. end;
  133. procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
  134. var
  135. changed : boolean;
  136. procedure CreateInfo(node : tnode);
  137. { update life entry of a node with l, set changed if this changes
  138. life info for the node
  139. }
  140. procedure updatelifeinfo(n : tnode;l : TDFASet);
  141. var
  142. b : boolean;
  143. begin
  144. b:=DFASetNotEqual(l,n.optinfo^.life);
  145. {
  146. if b then
  147. begin
  148. printnode(output,n);
  149. printdfaset(output,l);
  150. writeln;
  151. printdfaset(output,n.optinfo^.life);
  152. writeln;
  153. end;
  154. }
  155. {$ifdef DEBUG_DFA}
  156. if not(changed) and b then
  157. writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
  158. {$endif DEBUG_DFA}
  159. changed:=changed or b;
  160. node.optinfo^.life:=l;
  161. end;
  162. procedure calclife(n : tnode);
  163. var
  164. l : TDFASet;
  165. begin
  166. if assigned(n.successor) then
  167. begin
  168. {
  169. write('Successor Life: ');
  170. printdfaset(output,n.successor.optinfo^.life);
  171. writeln;
  172. write('Def.');
  173. printdfaset(output,n.optinfo^.def);
  174. writeln;
  175. }
  176. { ensure we can access optinfo }
  177. DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);
  178. {
  179. printdfaset(output,l);
  180. writeln;
  181. }
  182. DFASetIncludeSet(l,n.optinfo^.use);
  183. DFASetIncludeSet(l,n.optinfo^.life);
  184. end
  185. else
  186. begin
  187. { last node, not exit or raise node and function? }
  188. if assigned(resultnode) and
  189. not(node.nodetype in [raisen,exitn]) then
  190. begin
  191. { if yes, result lifes }
  192. DFASetDiff(l,resultnode.optinfo^.life,n.optinfo^.def);
  193. DFASetIncludeSet(l,n.optinfo^.use);
  194. DFASetIncludeSet(l,n.optinfo^.life);
  195. end
  196. else
  197. begin
  198. l:=n.optinfo^.use;
  199. DFASetIncludeSet(l,n.optinfo^.life);
  200. end;
  201. end;
  202. updatelifeinfo(n,l);
  203. end;
  204. var
  205. dfainfo : tdfainfo;
  206. l : TDFASet;
  207. save: TDFASet;
  208. i : longint;
  209. begin
  210. if node=nil then
  211. exit;
  212. { ensure we've already optinfo set }
  213. node.allocoptinfo;
  214. if nf_processing in node.flags then
  215. exit;
  216. include(node.flags,nf_processing);
  217. if assigned(node.successor) then
  218. CreateInfo(node.successor);
  219. {$ifdef EXTDEBUG_DFA}
  220. writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');
  221. {$endif EXTDEBUG_DFA}
  222. { life:=succesorlive-definition+use }
  223. case node.nodetype of
  224. whilerepeatn:
  225. begin
  226. { analyze the loop condition }
  227. if not(assigned(node.optinfo^.def)) and
  228. not(assigned(node.optinfo^.use)) then
  229. begin
  230. dfainfo.use:[email protected]^.use;
  231. dfainfo.def:[email protected]^.def;
  232. dfainfo.map:=map;
  233. foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);
  234. end;
  235. { NB: this node should typically have empty def set }
  236. if assigned(node.successor) then
  237. DFASetDiff(l,node.successor.optinfo^.life,node.optinfo^.def)
  238. else if assigned(resultnode) then
  239. DFASetDiff(l,resultnode.optinfo^.life,node.optinfo^.def)
  240. else
  241. l:=nil;
  242. { for repeat..until, node use set in included at the end of loop }
  243. if not (lnf_testatbegin in twhilerepeatnode(node).loopflags) then
  244. DFASetIncludeSet(l,node.optinfo^.use);
  245. DFASetIncludeSet(l,node.optinfo^.life);
  246. save:=node.optinfo^.life;
  247. { to process body correctly, we need life info in place (because
  248. whilerepeatnode is successor of its body). }
  249. node.optinfo^.life:=l;
  250. { now process the body }
  251. CreateInfo(twhilerepeatnode(node).right);
  252. { restore, to prevent infinite recursion via changed flag }
  253. node.optinfo^.life:=save;
  254. { for while loops, node use set is included at the beginning of loop }
  255. l:=twhilerepeatnode(node).right.optinfo^.life;
  256. if lnf_testatbegin in twhilerepeatnode(node).loopflags then
  257. DFASetIncludeSet(l,node.optinfo^.use);
  258. UpdateLifeInfo(node,l);
  259. { ... and a second iteration for fast convergence }
  260. CreateInfo(twhilerepeatnode(node).right);
  261. end;
  262. forn:
  263. begin
  264. {
  265. left: loopvar
  266. right: from
  267. t1: to
  268. t2: body
  269. }
  270. { take care of the sucessor if it's possible that we don't have one execution of the body }
  271. if not((tfornode(node).right.nodetype=ordconstn) and (tfornode(node).t1.nodetype=ordconstn)) then
  272. calclife(node);
  273. node.allocoptinfo;
  274. if not(assigned(node.optinfo^.def)) and
  275. not(assigned(node.optinfo^.use)) then
  276. begin
  277. dfainfo.use:[email protected]^.use;
  278. dfainfo.def:[email protected]^.def;
  279. dfainfo.map:=map;
  280. foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);
  281. foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);
  282. foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);
  283. end;
  284. { take care of the sucessor if it's possible that we don't have one execution of the body }
  285. if not((tfornode(node).right.nodetype=ordconstn) and (tfornode(node).t1.nodetype=ordconstn)) then
  286. calclife(node);
  287. { create life for the body }
  288. CreateInfo(tfornode(node).t2);
  289. { update for node }
  290. { life:=life+use+body }
  291. l:=copy(node.optinfo^.life);
  292. DFASetIncludeSet(l,node.optinfo^.use);
  293. DFASetIncludeSet(l,tfornode(node).t2.optinfo^.life);
  294. { the for loop always updates its control variable }
  295. DFASetDiff(l,l,node.optinfo^.def);
  296. UpdateLifeInfo(node,l);
  297. { ... and a second iteration for fast convergence }
  298. CreateInfo(tfornode(node).t2);
  299. end;
  300. temprefn,
  301. loadn,
  302. typeconvn,
  303. assignn:
  304. begin
  305. if not(assigned(node.optinfo^.def)) and
  306. not(assigned(node.optinfo^.use)) then
  307. begin
  308. dfainfo.use:[email protected]^.use;
  309. dfainfo.def:[email protected]^.def;
  310. dfainfo.map:=map;
  311. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  312. end;
  313. calclife(node);
  314. end;
  315. statementn:
  316. begin
  317. { nested statement }
  318. CreateInfo(tstatementnode(node).statement);
  319. { inherit info }
  320. node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;
  321. end;
  322. blockn:
  323. begin
  324. CreateInfo(tblocknode(node).statements);
  325. if assigned(tblocknode(node).statements) then
  326. node.optinfo^.life:=tblocknode(node).statements.optinfo^.life;
  327. end;
  328. ifn:
  329. begin
  330. { get information from cond. expression }
  331. if not(assigned(node.optinfo^.def)) and
  332. not(assigned(node.optinfo^.use)) then
  333. begin
  334. dfainfo.use:[email protected]^.use;
  335. dfainfo.def:[email protected]^.def;
  336. dfainfo.map:=map;
  337. foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);
  338. end;
  339. { create life info for then and else node }
  340. CreateInfo(tifnode(node).right);
  341. CreateInfo(tifnode(node).t1);
  342. { ensure that we don't remove life info }
  343. l:=node.optinfo^.life;
  344. { get life info from then branch }
  345. if assigned(tifnode(node).right) then
  346. DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);
  347. { get life info from else branch }
  348. if assigned(tifnode(node).t1) then
  349. DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)
  350. else
  351. if assigned(node.successor) then
  352. DFASetIncludeSet(l,node.successor.optinfo^.life)
  353. { last node and function? }
  354. else
  355. if assigned(resultnode) then
  356. DFASetIncludeSet(l,resultnode.optinfo^.life);
  357. { add use info from the cond. expression }
  358. DFASetIncludeSet(l,tifnode(node).optinfo^.use);
  359. { finally, update the life info of the node }
  360. UpdateLifeInfo(node,l);
  361. end;
  362. casen:
  363. begin
  364. { get information from "case" expression }
  365. if not(assigned(node.optinfo^.def)) and
  366. not(assigned(node.optinfo^.use)) then
  367. begin
  368. dfainfo.use:[email protected]^.use;
  369. dfainfo.def:[email protected]^.def;
  370. dfainfo.map:=map;
  371. foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);
  372. end;
  373. { create life info for block and else nodes }
  374. for i:=0 to tcasenode(node).blocks.count-1 do
  375. CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);
  376. CreateInfo(tcasenode(node).elseblock);
  377. { ensure that we don't remove life info }
  378. l:=node.optinfo^.life;
  379. { get life info from case branches }
  380. for i:=0 to tcasenode(node).blocks.count-1 do
  381. DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);
  382. { get life info from else branch or the succesor }
  383. if assigned(tcasenode(node).elseblock) then
  384. DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)
  385. else
  386. if assigned(node.successor) then
  387. DFASetIncludeSet(l,node.successor.optinfo^.life)
  388. { last node and function? }
  389. else
  390. if assigned(resultnode) then
  391. DFASetIncludeSet(l,resultnode.optinfo^.life);
  392. { add use info from the "case" expression }
  393. DFASetIncludeSet(l,tcasenode(node).optinfo^.use);
  394. { finally, update the life info of the node }
  395. UpdateLifeInfo(node,l);
  396. end;
  397. exitn:
  398. begin
  399. if not(is_void(current_procinfo.procdef.returndef)) and
  400. not(current_procinfo.procdef.proctypeoption=potype_constructor) then
  401. begin
  402. if not(assigned(node.optinfo^.def)) and
  403. not(assigned(node.optinfo^.use)) then
  404. begin
  405. if assigned(texitnode(node).left) then
  406. begin
  407. node.optinfo^.def:=resultnode.optinfo^.def;
  408. dfainfo.use:[email protected]^.use;
  409. dfainfo.def:[email protected]^.def;
  410. dfainfo.map:=map;
  411. foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);
  412. calclife(node);
  413. end
  414. else
  415. begin
  416. { get info from faked resultnode }
  417. node.optinfo^.use:=resultnode.optinfo^.use;
  418. node.optinfo^.life:=node.optinfo^.use;
  419. changed:=true;
  420. end;
  421. end;
  422. end;
  423. end;
  424. raisen:
  425. begin
  426. if not(assigned(node.optinfo^.life)) then
  427. begin
  428. dfainfo.use:[email protected]^.use;
  429. dfainfo.def:[email protected]^.def;
  430. dfainfo.map:=map;
  431. foreachnodestatic(pm_postprocess,traisenode(node).left,@AddDefUse,@dfainfo);
  432. foreachnodestatic(pm_postprocess,traisenode(node).right,@AddDefUse,@dfainfo);
  433. foreachnodestatic(pm_postprocess,traisenode(node).third,@AddDefUse,@dfainfo);
  434. { update node }
  435. l:=node.optinfo^.life;
  436. DFASetIncludeSet(l,node.optinfo^.use);
  437. UpdateLifeInfo(node,l);
  438. printdfainfo(output,node);
  439. end;
  440. end;
  441. calln:
  442. begin
  443. if not(assigned(node.optinfo^.def)) and
  444. not(assigned(node.optinfo^.use)) then
  445. begin
  446. dfainfo.use:[email protected]^.use;
  447. dfainfo.def:[email protected]^.def;
  448. dfainfo.map:=map;
  449. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  450. end;
  451. calclife(node);
  452. end;
  453. tempcreaten,
  454. tempdeleten,
  455. inlinen,
  456. nothingn,
  457. continuen,
  458. goton,
  459. breakn,
  460. labeln:
  461. begin
  462. calclife(node);
  463. end;
  464. else
  465. begin
  466. writeln(nodetype2str[node.nodetype]);
  467. internalerror(2007050502);
  468. end;
  469. end;
  470. // exclude(node.flags,nf_processing);
  471. end;
  472. var
  473. runs : integer;
  474. dfarec : tdfainfo;
  475. begin
  476. runs:=0;
  477. if not(is_void(current_procinfo.procdef.returndef)) and
  478. not(current_procinfo.procdef.proctypeoption=potype_constructor) then
  479. begin
  480. { create a fake node using the result }
  481. resultnode:=load_result_node;
  482. resultnode.allocoptinfo;
  483. dfarec.use:[email protected]^.use;
  484. dfarec.def:[email protected]^.def;
  485. dfarec.map:=map;
  486. AddDefUse(resultnode,@dfarec);
  487. resultnode.optinfo^.life:=resultnode.optinfo^.use;
  488. end
  489. else
  490. resultnode:=nil;
  491. repeat
  492. inc(runs);
  493. changed:=false;
  494. CreateInfo(node);
  495. foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
  496. {$ifdef DEBUG_DFA}
  497. PrintIndexedNodeSet(output,map);
  498. PrintDFAInfo(output,node);
  499. {$endif DEBUG_DFA}
  500. until not(changed);
  501. {$ifdef DEBUG_DFA}
  502. writeln('DFA solver iterations: ',runs);
  503. {$endif DEBUG_DFA}
  504. end;
  505. { reset all dfa info, this is required before creating dfa info
  506. if the tree has been changed without updating dfa }
  507. procedure TDFABuilder.resetdfainfo(node : tnode);
  508. begin
  509. foreachnodestatic(pm_postprocess,node,@ResetDFA,nil);
  510. end;
  511. procedure TDFABuilder.createdfainfo(node : tnode);
  512. begin
  513. if not(assigned(nodemap)) then
  514. nodemap:=TIndexedNodeSet.Create;
  515. { add controll flow information }
  516. SetNodeSucessors(node);
  517. { now, collect life information }
  518. CreateLifeInfo(node,nodemap);
  519. end;
  520. destructor TDFABuilder.Destroy;
  521. begin
  522. Resultnode.free;
  523. nodemap.free;
  524. inherited destroy;
  525. end;
  526. end.