optdfa.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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. procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
  120. var
  121. changed : boolean;
  122. procedure CreateInfo(node : tnode);
  123. { update life entry of a node with l, set changed if this changes
  124. life info for the node
  125. }
  126. procedure updatelifeinfo(n : tnode;l : TDFASet);
  127. var
  128. b : boolean;
  129. begin
  130. b:=DFASetNotEqual(l,n.optinfo^.life);
  131. {
  132. if b then
  133. begin
  134. printnode(output,n);
  135. printdfaset(output,l);
  136. writeln;
  137. printdfaset(output,n.optinfo^.life);
  138. writeln;
  139. end;
  140. }
  141. {$ifdef DEBUG_DFA}
  142. if not(changed) and b then
  143. writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
  144. {$endif DEBUG_DFA}
  145. changed:=changed or b;
  146. node.optinfo^.life:=l;
  147. end;
  148. procedure calclife(n : tnode);
  149. var
  150. l : TDFASet;
  151. begin
  152. if assigned(n.successor) then
  153. begin
  154. {
  155. write('Successor Life: ');
  156. printdfaset(output,n.successor.optinfo^.life);
  157. writeln;
  158. write('Def.');
  159. printdfaset(output,n.optinfo^.def);
  160. writeln;
  161. }
  162. { ensure we can access optinfo }
  163. DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);
  164. {
  165. printdfaset(output,l);
  166. writeln;
  167. }
  168. DFASetIncludeSet(l,n.optinfo^.use);
  169. DFASetIncludeSet(l,n.optinfo^.life);
  170. end
  171. else
  172. begin
  173. l:=n.optinfo^.use;
  174. DFASetIncludeSet(l,n.optinfo^.life);
  175. end;
  176. updatelifeinfo(n,l);
  177. end;
  178. var
  179. dfainfo : tdfainfo;
  180. l : TDFASet;
  181. i : longint;
  182. begin
  183. if node=nil then
  184. exit;
  185. { ensure we've already optinfo set }
  186. node.allocoptinfo;
  187. if nf_processing in node.flags then
  188. exit;
  189. include(node.flags,nf_processing);
  190. if assigned(node.successor) then
  191. CreateInfo(node.successor);
  192. {$ifdef EXTDEBUG_DFA}
  193. writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');
  194. {$endif EXTDEBUG_DFA}
  195. { life:=succesorlive-definition+use }
  196. case node.nodetype of
  197. whilerepeatn:
  198. begin
  199. calclife(node);
  200. { take care of repeat until! }
  201. if lnf_testatbegin in twhilerepeatnode(node).loopflags then
  202. begin
  203. node.allocoptinfo;
  204. if not(assigned(node.optinfo^.def)) and
  205. not(assigned(node.optinfo^.use)) then
  206. begin
  207. dfainfo.use:[email protected]^.use;
  208. dfainfo.def:[email protected]^.def;
  209. dfainfo.map:=map;
  210. foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);
  211. end;
  212. calclife(node);
  213. { now iterate through the loop }
  214. CreateInfo(twhilerepeatnode(node).right);
  215. { update while node }
  216. { life:=life+use+right.life }
  217. l:=node.optinfo^.life;
  218. DFASetIncludeSet(l,node.optinfo^.use);
  219. DFASetIncludeSet(l,twhilerepeatnode(node).right.optinfo^.life);
  220. UpdateLifeInfo(node,l);
  221. { ... and a second iteration for fast convergence }
  222. CreateInfo(twhilerepeatnode(node).right);
  223. end;
  224. end;
  225. forn:
  226. begin
  227. {
  228. left: loopvar
  229. right: from
  230. t1: to
  231. t2: body
  232. }
  233. calclife(node);
  234. node.allocoptinfo;
  235. if not(assigned(node.optinfo^.def)) and
  236. not(assigned(node.optinfo^.use)) then
  237. begin
  238. dfainfo.use:[email protected]^.use;
  239. dfainfo.def:[email protected]^.def;
  240. dfainfo.map:=map;
  241. foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);
  242. foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);
  243. foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);
  244. end;
  245. calclife(node);
  246. { create life the body }
  247. CreateInfo(tfornode(node).t2);
  248. { update for node }
  249. { life:=life+use+body }
  250. l:=node.optinfo^.life;
  251. DFASetIncludeSet(l,node.optinfo^.use);
  252. DFASetIncludeSet(l,tfornode(node).t2.optinfo^.life);
  253. UpdateLifeInfo(node,l);
  254. { ... and a second iteration for fast convergence }
  255. CreateInfo(tfornode(node).t2);
  256. end;
  257. temprefn,
  258. loadn,
  259. typeconvn,
  260. assignn:
  261. begin
  262. if not(assigned(node.optinfo^.def)) and
  263. not(assigned(node.optinfo^.use)) then
  264. begin
  265. dfainfo.use:[email protected]^.use;
  266. dfainfo.def:[email protected]^.def;
  267. dfainfo.map:=map;
  268. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  269. end;
  270. calclife(node);
  271. end;
  272. statementn:
  273. begin
  274. { nested statement }
  275. CreateInfo(tstatementnode(node).statement);
  276. { inherit info }
  277. node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;
  278. end;
  279. blockn:
  280. begin
  281. CreateInfo(tblocknode(node).statements);
  282. if assigned(tblocknode(node).statements) then
  283. node.optinfo^.life:=tblocknode(node).statements.optinfo^.life;
  284. end;
  285. ifn:
  286. begin
  287. { get information from cond. expression }
  288. if not(assigned(node.optinfo^.def)) and
  289. not(assigned(node.optinfo^.use)) then
  290. begin
  291. dfainfo.use:[email protected]^.use;
  292. dfainfo.def:[email protected]^.def;
  293. dfainfo.map:=map;
  294. foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);
  295. end;
  296. { create life info for then and else node }
  297. CreateInfo(tifnode(node).right);
  298. CreateInfo(tifnode(node).t1);
  299. { ensure that we don't remove life info }
  300. l:=node.optinfo^.life;
  301. { get life info from then branch }
  302. if assigned(tifnode(node).right) then
  303. DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);
  304. { get life info from else branch }
  305. if assigned(tifnode(node).t1) then
  306. DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)
  307. else
  308. if assigned(node.successor) then
  309. DFASetIncludeSet(l,node.successor.optinfo^.life);
  310. { add use info from the cond. expression }
  311. DFASetIncludeSet(l,tifnode(node).optinfo^.use);
  312. { finally, update the life info of the node }
  313. UpdateLifeInfo(node,l);
  314. end;
  315. casen:
  316. begin
  317. { get information from "case" expression }
  318. if not(assigned(node.optinfo^.def)) and
  319. not(assigned(node.optinfo^.use)) then
  320. begin
  321. dfainfo.use:[email protected]^.use;
  322. dfainfo.def:[email protected]^.def;
  323. dfainfo.map:=map;
  324. foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);
  325. end;
  326. { create life info for block and else nodes }
  327. for i:=0 to tcasenode(node).blocks.count-1 do
  328. CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);
  329. CreateInfo(tcasenode(node).elseblock);
  330. { ensure that we don't remove life info }
  331. l:=node.optinfo^.life;
  332. { get life info from case branches }
  333. for i:=0 to tcasenode(node).blocks.count-1 do
  334. DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);
  335. { get life info from else branch or the succesor }
  336. if assigned(tcasenode(node).elseblock) then
  337. DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)
  338. else
  339. if assigned(node.successor) then
  340. DFASetIncludeSet(l,node.successor.optinfo^.life);
  341. { add use info from the "case" expression }
  342. DFASetIncludeSet(l,tcasenode(node).optinfo^.use);
  343. { finally, update the life info of the node }
  344. UpdateLifeInfo(node,l);
  345. end;
  346. exitn:
  347. begin
  348. if not(is_void(current_procinfo.procdef.returndef)) and
  349. not(current_procinfo.procdef.proctypeoption=potype_constructor) then
  350. begin
  351. if not(assigned(node.optinfo^.def)) and
  352. not(assigned(node.optinfo^.use)) then
  353. begin
  354. if assigned(texitnode(node).left) then
  355. begin
  356. node.optinfo^.def:=resultnode.optinfo^.def;
  357. dfainfo.use:[email protected]^.use;
  358. dfainfo.def:[email protected]^.def;
  359. dfainfo.map:=map;
  360. foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);
  361. calclife(node);
  362. end
  363. else
  364. begin
  365. { get info from faked resultnode }
  366. node.optinfo^.use:=resultnode.optinfo^.use;
  367. node.optinfo^.life:=node.optinfo^.use;
  368. changed:=true;
  369. end;
  370. end;
  371. end;
  372. end;
  373. raisen:
  374. begin
  375. if not(assigned(node.optinfo^.life)) then
  376. begin
  377. dfainfo.use:[email protected]^.use;
  378. dfainfo.def:[email protected]^.def;
  379. dfainfo.map:=map;
  380. foreachnodestatic(pm_postprocess,traisenode(node).left,@AddDefUse,@dfainfo);
  381. foreachnodestatic(pm_postprocess,traisenode(node).right,@AddDefUse,@dfainfo);
  382. foreachnodestatic(pm_postprocess,traisenode(node).third,@AddDefUse,@dfainfo);
  383. { update node }
  384. l:=node.optinfo^.life;
  385. DFASetIncludeSet(l,node.optinfo^.use);
  386. UpdateLifeInfo(node,l);
  387. printdfainfo(output,node);
  388. end;
  389. end;
  390. calln:
  391. begin
  392. if not(assigned(node.optinfo^.def)) and
  393. not(assigned(node.optinfo^.use)) then
  394. begin
  395. dfainfo.use:[email protected]^.use;
  396. dfainfo.def:[email protected]^.def;
  397. dfainfo.map:=map;
  398. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  399. end;
  400. calclife(node);
  401. end;
  402. tempcreaten,
  403. tempdeleten,
  404. inlinen,
  405. nothingn,
  406. continuen,
  407. goton,
  408. breakn,
  409. labeln:
  410. begin
  411. calclife(node);
  412. end;
  413. else
  414. begin
  415. writeln(nodetype2str[node.nodetype]);
  416. internalerror(2007050502);
  417. end;
  418. end;
  419. // exclude(node.flags,nf_processing);
  420. end;
  421. var
  422. runs : integer;
  423. dfarec : tdfainfo;
  424. begin
  425. runs:=0;
  426. if not(is_void(current_procinfo.procdef.returndef)) and
  427. not(current_procinfo.procdef.proctypeoption=potype_constructor) then
  428. begin
  429. { create a fake node using the result }
  430. resultnode:=load_result_node;
  431. resultnode.allocoptinfo;
  432. dfarec.use:[email protected]^.use;
  433. dfarec.def:[email protected]^.def;
  434. dfarec.map:=map;
  435. AddDefUse(resultnode,@dfarec);
  436. end
  437. else
  438. resultnode:=nil;
  439. repeat
  440. inc(runs);
  441. changed:=false;
  442. CreateInfo(node);
  443. foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
  444. {$ifdef DEBUG_DFA}
  445. PrintIndexedNodeSet(output,map);
  446. PrintDFAInfo(output,node);
  447. {$endif DEBUG_DFA}
  448. until not(changed);
  449. {$ifdef DEBUG_DFA}
  450. writeln('DFA solver iterations: ',runs);
  451. {$endif DEBUG_DFA}
  452. end;
  453. { reset all dfa info, this is required before creating dfa info
  454. if the tree has been changed without updating dfa }
  455. procedure TDFABuilder.resetdfainfo(node : tnode);
  456. begin
  457. end;
  458. procedure TDFABuilder.createdfainfo(node : tnode);
  459. {
  460. var
  461. lastnode : tnode;
  462. fakeexitnode : texitnode;
  463. }
  464. begin
  465. if not(assigned(nodemap)) then
  466. nodemap:=TIndexedNodeSet.Create;
  467. { add controll flow information }
  468. SetNodeSucessors(node);
  469. {
  470. { create an exit node for functions to get
  471. the function result at the end handled properly }
  472. if not(is_void(current_procinfo.procdef.returndef)) and
  473. not(current_procinfo.procdef.proctypeoption=potype_constructor) then
  474. begin
  475. lastnode:=node;
  476. while assigned(lastnode.successor) do
  477. lastnode:=lastnode.successor;
  478. fakeexitnode:=cexitnode.create(nil);
  479. lastnode.successor:=fakeexitnode;
  480. end
  481. else
  482. fakeexitnode:=nil;
  483. }
  484. { now, collect life information }
  485. CreateLifeInfo(node,nodemap);
  486. {
  487. if assigned(fakeexitnode) then
  488. begin
  489. lastnode.successor.free;
  490. lastnode.successor:=nil;
  491. end;
  492. }
  493. end;
  494. destructor TDFABuilder.Destroy;
  495. begin
  496. Resultnode.free;
  497. nodemap.free;
  498. inherited destroy;
  499. end;
  500. end.