optdfa.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  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. temprefn,
  92. loadn:
  93. begin
  94. pdfainfo(arg)^.map.Add(n);
  95. if nf_modify in n.flags then
  96. begin
  97. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  98. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  99. end
  100. else if nf_write in n.flags then
  101. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  102. else
  103. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  104. {
  105. write('Use Set: ');
  106. PrintDFASet(output,pdfainfo(arg)^.use^);
  107. write(' Def Set: ');
  108. PrintDFASet(output,pdfainfo(arg)^.def^);
  109. writeln;
  110. }
  111. end;
  112. end;
  113. result:=fen_false;
  114. end;
  115. function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
  116. begin
  117. exclude(n.flags,nf_processing);
  118. result:=fen_false;
  119. end;
  120. function ResetDFA(var n: tnode; arg: pointer): foreachnoderesult;
  121. begin
  122. if assigned(n.optinfo) then
  123. begin
  124. with n.optinfo^ do
  125. begin
  126. life:=nil;
  127. def:=nil;
  128. use:=nil;
  129. defsum:=nil;
  130. end;
  131. end;
  132. result:=fen_false;
  133. end;
  134. procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
  135. var
  136. changed : boolean;
  137. procedure CreateInfo(node : tnode);
  138. { update life entry of a node with l, set changed if this changes
  139. life info for the node
  140. }
  141. procedure updatelifeinfo(n : tnode;l : TDFASet);
  142. var
  143. b : boolean;
  144. begin
  145. b:=DFASetNotEqual(l,n.optinfo^.life);
  146. {
  147. if b then
  148. begin
  149. printnode(output,n);
  150. printdfaset(output,l);
  151. writeln;
  152. printdfaset(output,n.optinfo^.life);
  153. writeln;
  154. end;
  155. }
  156. {$ifdef DEBUG_DFA}
  157. if not(changed) and b then
  158. begin
  159. writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
  160. write(' Life info set was: ');PrintDFASet(Output,n.optinfo^.life);writeln;
  161. write(' Life info set will be: ');PrintDFASet(Output,l);writeln;
  162. end;
  163. {$endif DEBUG_DFA}
  164. changed:=changed or b;
  165. n.optinfo^.life:=l;
  166. end;
  167. procedure calclife(n : tnode);
  168. var
  169. l : TDFASet;
  170. begin
  171. if assigned(n.successor) then
  172. begin
  173. {
  174. write('Successor Life: ');
  175. printdfaset(output,n.successor.optinfo^.life);
  176. writeln;
  177. write('Def.');
  178. printdfaset(output,n.optinfo^.def);
  179. writeln;
  180. }
  181. { ensure we can access optinfo }
  182. DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);
  183. {
  184. printdfaset(output,l);
  185. writeln;
  186. }
  187. DFASetIncludeSet(l,n.optinfo^.use);
  188. DFASetIncludeSet(l,n.optinfo^.life);
  189. end
  190. else
  191. begin
  192. { last node, not exit or raise node and function? }
  193. if assigned(resultnode) and
  194. not(n.nodetype=exitn) and
  195. not((n.nodetype=calln) and (cnf_call_never_returns in tcallnode(n).callnodeflags)) then
  196. begin
  197. { if yes, result lifes }
  198. DFASetDiff(l,resultnode.optinfo^.life,n.optinfo^.def);
  199. DFASetIncludeSet(l,n.optinfo^.use);
  200. DFASetIncludeSet(l,n.optinfo^.life);
  201. end
  202. else
  203. begin
  204. l:=n.optinfo^.use;
  205. DFASetIncludeSet(l,n.optinfo^.life);
  206. end;
  207. end;
  208. updatelifeinfo(n,l);
  209. end;
  210. var
  211. dfainfo : tdfainfo;
  212. l : TDFASet;
  213. save: TDFASet;
  214. i : longint;
  215. counteruse_after_loop : boolean;
  216. begin
  217. if node=nil then
  218. exit;
  219. { ensure we've already optinfo set }
  220. node.allocoptinfo;
  221. if nf_processing in node.flags then
  222. exit;
  223. include(node.flags,nf_processing);
  224. if not(assigned(node.successor)) and (node<>resultnode) then
  225. node.successor:=resultnode;
  226. if assigned(node.successor) then
  227. CreateInfo(node.successor);
  228. {$ifdef EXTDEBUG_DFA}
  229. writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');
  230. {$endif EXTDEBUG_DFA}
  231. { life:=succesorlive-definition+use }
  232. case node.nodetype of
  233. whilerepeatn:
  234. begin
  235. { analyze the loop condition }
  236. if not(assigned(node.optinfo^.def)) and
  237. not(assigned(node.optinfo^.use)) then
  238. begin
  239. dfainfo.use:[email protected]^.use;
  240. dfainfo.def:[email protected]^.def;
  241. dfainfo.map:=map;
  242. foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);
  243. end;
  244. { NB: this node should typically have empty def set }
  245. if assigned(node.successor) then
  246. DFASetDiff(l,node.successor.optinfo^.life,node.optinfo^.def)
  247. else if assigned(resultnode) then
  248. DFASetDiff(l,resultnode.optinfo^.life,node.optinfo^.def)
  249. else
  250. l:=nil;
  251. { for repeat..until, node use set in included at the end of loop }
  252. if not (lnf_testatbegin in twhilerepeatnode(node).loopflags) then
  253. DFASetIncludeSet(l,node.optinfo^.use);
  254. DFASetIncludeSet(l,node.optinfo^.life);
  255. save:=node.optinfo^.life;
  256. { to process body correctly, we need life info in place (because
  257. whilerepeatnode is successor of its body). }
  258. node.optinfo^.life:=l;
  259. { now process the body }
  260. CreateInfo(twhilerepeatnode(node).right);
  261. { restore, to prevent infinite recursion via changed flag }
  262. node.optinfo^.life:=save;
  263. { for while loops, node use set is included at the beginning of loop }
  264. l:=twhilerepeatnode(node).right.optinfo^.life;
  265. if lnf_testatbegin in twhilerepeatnode(node).loopflags then
  266. DFASetIncludeSet(l,node.optinfo^.use);
  267. UpdateLifeInfo(node,l);
  268. { ... and a second iteration for fast convergence }
  269. CreateInfo(twhilerepeatnode(node).right);
  270. end;
  271. forn:
  272. begin
  273. {
  274. left: loopvar
  275. right: from
  276. t1: to
  277. t2: body
  278. }
  279. node.allocoptinfo;
  280. tfornode(node).loopiteration.allocoptinfo;
  281. if not(assigned(node.optinfo^.def)) and
  282. not(assigned(node.optinfo^.use)) then
  283. begin
  284. dfainfo.use:[email protected]^.use;
  285. dfainfo.def:[email protected]^.def;
  286. dfainfo.map:=map;
  287. foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);
  288. foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);
  289. foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);
  290. end;
  291. { create life for the body }
  292. CreateInfo(tfornode(node).t2);
  293. { is the counter living after the loop?
  294. if left is a record element, it might not be tracked by dfa, so
  295. optinfo might not be assigned
  296. }
  297. counteruse_after_loop:=assigned(tfornode(node).left.optinfo) and
  298. DFASetIn(node.successor.optinfo^.life,tfornode(node).left.optinfo^.index);
  299. { if yes, then we should warn }
  300. { !!!!!! }
  301. { first update the dummy node }
  302. { get the life of the loop block }
  303. l:=copy(tfornode(node).t2.optinfo^.life);
  304. { take care of the sucessor }
  305. DFASetIncludeSet(l,node.successor.optinfo^.life);
  306. { the counter variable is living as well inside the for loop
  307. if left is a record element, it might not be tracked by dfa, so
  308. optinfo might not be assigned
  309. }
  310. if assigned(tfornode(node).left.optinfo) then
  311. DFASetInclude(l,tfornode(node).left.optinfo^.index);
  312. { force block node life info }
  313. UpdateLifeInfo(tfornode(node).loopiteration,l);
  314. { now update the for node itself }
  315. { get the life of the loop block }
  316. l:=copy(tfornode(node).t2.optinfo^.life);
  317. { take care of the sucessor as it's possible that we don't have one execution of the body }
  318. if not(tfornode(node).right.nodetype=ordconstn) or not(tfornode(node).t1.nodetype=ordconstn) then
  319. DFASetIncludeSet(l,node.successor.optinfo^.life);
  320. {
  321. the counter variable is not living at the entry of the for node
  322. if left is a record element, it might not be tracked by dfa, so
  323. optinfo might not be assigned
  324. }
  325. if assigned(tfornode(node).left.optinfo) then
  326. DFASetExclude(l,tfornode(node).left.optinfo^.index);
  327. { ... but it could be that left/right use it, so do this after
  328. removing the def of the counter variable }
  329. DFASetIncludeSet(l,node.optinfo^.use);
  330. UpdateLifeInfo(node,l);
  331. { ... and a second iteration for fast convergence }
  332. CreateInfo(tfornode(node).t2);
  333. end;
  334. temprefn,
  335. loadn,
  336. typeconvn,
  337. assignn:
  338. begin
  339. if not(assigned(node.optinfo^.def)) and
  340. not(assigned(node.optinfo^.use)) then
  341. begin
  342. dfainfo.use:[email protected]^.use;
  343. dfainfo.def:[email protected]^.def;
  344. dfainfo.map:=map;
  345. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  346. end;
  347. calclife(node);
  348. end;
  349. statementn:
  350. begin
  351. { nested statement }
  352. CreateInfo(tstatementnode(node).statement);
  353. { inherit info }
  354. node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;
  355. end;
  356. blockn:
  357. begin
  358. CreateInfo(tblocknode(node).statements);
  359. { ensure that we don't remove life info }
  360. l:=node.optinfo^.life;
  361. if assigned(node.successor) then
  362. DFASetIncludeSet(l,node.successor.optinfo^.life);
  363. UpdateLifeInfo(node,l);
  364. end;
  365. ifn:
  366. begin
  367. { get information from cond. expression }
  368. if not(assigned(node.optinfo^.def)) and
  369. not(assigned(node.optinfo^.use)) then
  370. begin
  371. dfainfo.use:[email protected]^.use;
  372. dfainfo.def:[email protected]^.def;
  373. dfainfo.map:=map;
  374. foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);
  375. end;
  376. { create life info for then and else node }
  377. CreateInfo(tifnode(node).right);
  378. CreateInfo(tifnode(node).t1);
  379. { ensure that we don't remove life info }
  380. l:=node.optinfo^.life;
  381. { get life info from then branch }
  382. if assigned(tifnode(node).right) then
  383. DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);
  384. { get life info from else branch }
  385. if assigned(tifnode(node).t1) then
  386. DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)
  387. else
  388. if assigned(node.successor) then
  389. DFASetIncludeSet(l,node.successor.optinfo^.life)
  390. { last node and function? }
  391. else
  392. if assigned(resultnode) then
  393. DFASetIncludeSet(l,resultnode.optinfo^.life);
  394. { add use info from the cond. expression }
  395. DFASetIncludeSet(l,tifnode(node).optinfo^.use);
  396. { finally, update the life info of the node }
  397. UpdateLifeInfo(node,l);
  398. end;
  399. casen:
  400. begin
  401. { get information from "case" expression }
  402. if not(assigned(node.optinfo^.def)) and
  403. not(assigned(node.optinfo^.use)) then
  404. begin
  405. dfainfo.use:[email protected]^.use;
  406. dfainfo.def:[email protected]^.def;
  407. dfainfo.map:=map;
  408. foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);
  409. end;
  410. { create life info for block and else nodes }
  411. for i:=0 to tcasenode(node).blocks.count-1 do
  412. CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);
  413. CreateInfo(tcasenode(node).elseblock);
  414. { ensure that we don't remove life info }
  415. l:=node.optinfo^.life;
  416. { get life info from case branches }
  417. for i:=0 to tcasenode(node).blocks.count-1 do
  418. DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);
  419. { get life info from else branch or the succesor }
  420. if assigned(tcasenode(node).elseblock) then
  421. DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)
  422. else
  423. if assigned(node.successor) then
  424. DFASetIncludeSet(l,node.successor.optinfo^.life)
  425. { last node and function? }
  426. else
  427. if assigned(resultnode) then
  428. DFASetIncludeSet(l,resultnode.optinfo^.life);
  429. { add use info from the "case" expression }
  430. DFASetIncludeSet(l,tcasenode(node).optinfo^.use);
  431. { finally, update the life info of the node }
  432. UpdateLifeInfo(node,l);
  433. end;
  434. exitn:
  435. begin
  436. if not(is_void(current_procinfo.procdef.returndef)) then
  437. begin
  438. if not(assigned(node.optinfo^.def)) and
  439. not(assigned(node.optinfo^.use)) then
  440. begin
  441. if assigned(texitnode(node).left) then
  442. begin
  443. node.optinfo^.def:=resultnode.optinfo^.def;
  444. dfainfo.use:[email protected]^.use;
  445. dfainfo.def:[email protected]^.def;
  446. dfainfo.map:=map;
  447. foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);
  448. calclife(node);
  449. end
  450. else
  451. begin
  452. { get info from faked resultnode }
  453. node.optinfo^.use:=resultnode.optinfo^.use;
  454. node.optinfo^.life:=node.optinfo^.use;
  455. changed:=true;
  456. end;
  457. end;
  458. end;
  459. end;
  460. inlinen,
  461. calln:
  462. begin
  463. if not(assigned(node.optinfo^.def)) and
  464. not(assigned(node.optinfo^.use)) then
  465. begin
  466. dfainfo.use:[email protected]^.use;
  467. dfainfo.def:[email protected]^.def;
  468. dfainfo.map:=map;
  469. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  470. end;
  471. calclife(node);
  472. end;
  473. tempcreaten,
  474. tempdeleten,
  475. nothingn,
  476. continuen,
  477. goton,
  478. breakn,
  479. labeln:
  480. begin
  481. calclife(node);
  482. end;
  483. else
  484. if node<>resultnode then
  485. begin
  486. writeln(nodetype2str[node.nodetype]);
  487. internalerror(2007050502);
  488. end;
  489. end;
  490. // exclude(node.flags,nf_processing);
  491. end;
  492. var
  493. runs : integer;
  494. dfarec : tdfainfo;
  495. begin
  496. runs:=0;
  497. if not(is_void(current_procinfo.procdef.returndef)) then
  498. begin
  499. { create a fake node using the result }
  500. if current_procinfo.procdef.proctypeoption=potype_constructor then
  501. resultnode:=load_self_node
  502. else
  503. resultnode:=load_result_node;
  504. resultnode.allocoptinfo;
  505. dfarec.use:[email protected]^.use;
  506. dfarec.def:[email protected]^.def;
  507. dfarec.map:=map;
  508. AddDefUse(resultnode,@dfarec);
  509. resultnode.optinfo^.life:=resultnode.optinfo^.use;
  510. end
  511. else
  512. resultnode:=cnothingnode.create;
  513. repeat
  514. inc(runs);
  515. changed:=false;
  516. CreateInfo(node);
  517. foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
  518. {$ifdef DEBUG_DFA}
  519. PrintIndexedNodeSet(output,map);
  520. PrintDFAInfo(output,node);
  521. {$endif DEBUG_DFA}
  522. until not(changed);
  523. {$ifdef DEBUG_DFA}
  524. writeln('DFA solver iterations: ',runs);
  525. {$endif DEBUG_DFA}
  526. end;
  527. { reset all dfa info, this is required before creating dfa info
  528. if the tree has been changed without updating dfa }
  529. procedure TDFABuilder.resetdfainfo(node : tnode);
  530. begin
  531. foreachnodestatic(pm_postprocess,node,@ResetDFA,nil);
  532. end;
  533. procedure TDFABuilder.createdfainfo(node : tnode);
  534. begin
  535. if not(assigned(nodemap)) then
  536. nodemap:=TIndexedNodeSet.Create;
  537. { add controll flow information }
  538. SetNodeSucessors(node,resultnode);
  539. { now, collect life information }
  540. CreateLifeInfo(node,nodemap);
  541. end;
  542. destructor TDFABuilder.Destroy;
  543. begin
  544. Resultnode.free;
  545. nodemap.free;
  546. inherited destroy;
  547. end;
  548. end.