optdfa.pas 17 KB

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