optdfa.pas 16 KB

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