optutils.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. {
  2. Helper routines for the optimizer
  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. unit optutils;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cclasses,
  22. node,
  23. globtype;
  24. type
  25. { this implementation should be really improved,
  26. its purpose is to find equal nodes }
  27. TIndexedNodeSet = class(TFPList)
  28. function Add(node : tnode) : boolean;
  29. function Includes(node : tnode) : tnode;
  30. function Remove(node : tnode) : boolean;
  31. end;
  32. procedure SetNodeSucessors(p,last : tnode);
  33. procedure PrintDFAInfo(var f : text;p : tnode);
  34. procedure PrintIndexedNodeSet(var f : text;s : TIndexedNodeSet);
  35. { determines the optinfo.defsum field for the given node
  36. this field contains a sum of all expressions defined by
  37. all child expressions reachable through p
  38. }
  39. procedure CalcDefSum(p : tnode);
  40. { calculates/estimates the field execution weight of optinfo }
  41. procedure CalcExecutionWeights(p : tnode;Initial : longint = 100);
  42. { determines the optinfo.defsum field for the given node
  43. this field contains a sum of all expressions defined by
  44. all child expressions reachable through p
  45. }
  46. procedure CalcUseSum(p : tnode);
  47. { returns true, if n is a valid node and has life info }
  48. function has_life_info(n : tnode) : boolean;
  49. implementation
  50. uses
  51. cutils,
  52. verbose,
  53. optbase,
  54. ncal,nbas,nflw,nutils,nset,ncon;
  55. function TIndexedNodeSet.Add(node : tnode) : boolean;
  56. var
  57. i : Integer;
  58. p : tnode;
  59. begin
  60. node.allocoptinfo;
  61. p:=Includes(node);
  62. if assigned(p) then
  63. begin
  64. result:=false;
  65. node.optinfo^.index:=p.optinfo^.index;
  66. end
  67. else
  68. begin
  69. i:=inherited Add(node);
  70. node.optinfo^.index:=i;
  71. result:=true;
  72. end
  73. end;
  74. function TIndexedNodeSet.Includes(node : tnode) : tnode;
  75. var
  76. i : longint;
  77. begin
  78. for i:=0 to Count-1 do
  79. if tnode(List^[i]).isequal(node) then
  80. begin
  81. result:=tnode(List^[i]);
  82. exit;
  83. end;
  84. result:=nil;
  85. end;
  86. function TIndexedNodeSet.Remove(node : tnode) : boolean;
  87. var
  88. p : tnode;
  89. begin
  90. result:=false;
  91. p:=Includes(node);
  92. if assigned(p) then
  93. begin
  94. if inherited Remove(p)<>-1 then
  95. result:=true;
  96. end;
  97. end;
  98. procedure PrintIndexedNodeSet(var f : text;s : TIndexedNodeSet);
  99. var
  100. i : integer;
  101. begin
  102. for i:=0 to s.count-1 do
  103. begin
  104. writeln(f,'=============================== Node ',i,' ===============================');
  105. printnode(f,tnode(s[i]));
  106. writeln(f);
  107. end;
  108. end;
  109. function PrintNodeDFA(var n: tnode; arg: pointer): foreachnoderesult;
  110. begin
  111. if assigned(n.optinfo) and ((n.optinfo^.life<>nil) or (n.optinfo^.use<>nil) or (n.optinfo^.def<>nil)) then
  112. begin
  113. write(text(arg^),nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,') Life: ');
  114. PrintDFASet(text(arg^),n.optinfo^.life);
  115. write(text(arg^),' Def: ');
  116. PrintDFASet(text(arg^),n.optinfo^.def);
  117. write(text(arg^),' Use: ');
  118. PrintDFASet(text(arg^),n.optinfo^.use);
  119. if assigned(n.successor) then
  120. write(text(arg^),' Successor: ',nodetype2str[n.successor.nodetype],'(',n.successor.fileinfo.line,',',n.successor.fileinfo.column,')')
  121. else
  122. write(text(arg^),' Successor: nil');
  123. write(text(arg^),' DefSum: ');
  124. PrintDFASet(text(arg^),n.optinfo^.defsum);
  125. writeln(text(arg^));
  126. end;
  127. result:=fen_false;
  128. end;
  129. procedure PrintDFAInfo(var f : text;p : tnode);
  130. begin
  131. foreachnodestatic(pm_postprocess,p,@PrintNodeDFA,@f);
  132. end;
  133. type
  134. PBreakContinueStackNode = ^TBreakContinueStackNode;
  135. TBreakContinueStackNode = record
  136. { successor node for a break statement in the current loop }
  137. brk,
  138. { successor node for a continue statement in the current loop }
  139. cont : tnode;
  140. next : PBreakContinueStackNode;
  141. end;
  142. { implements a stack to track successor nodes for break and continue
  143. statements }
  144. TBreakContinueStack = object
  145. top: PBreakContinueStackNode;
  146. constructor Init;
  147. destructor Done;
  148. procedure Push(brk,cont : tnode);
  149. procedure Pop;
  150. end;
  151. const
  152. NullBreakContinueStackNode : TBreakContinueStackNode = (brk: nil; cont: nil; next: nil);
  153. constructor TBreakContinueStack.Init;
  154. begin
  155. top:=@NullBreakContinueStackNode;
  156. end;
  157. destructor TBreakContinueStack.Done;
  158. begin
  159. while top<>@NullBreakContinueStackNode do
  160. Pop;
  161. end;
  162. procedure TBreakContinueStack.Push(brk,cont : tnode);
  163. var
  164. n : PBreakContinueStackNode;
  165. begin
  166. new(n);
  167. n^.brk:=brk;
  168. n^.cont:=cont;
  169. n^.next:=top;
  170. top:=n;
  171. end;
  172. procedure TBreakContinueStack.Pop;
  173. var
  174. n : PBreakContinueStackNode;
  175. begin
  176. n:=top;
  177. top:=n^.next;
  178. Dispose(n);
  179. end;
  180. procedure SetNodeSucessors(p,last : tnode);
  181. var
  182. BreakContinueStack : TBreakContinueStack;
  183. Exitsuccessor: TNode;
  184. { sets the successor nodes of a node tree block
  185. returns the first node of the tree if it's a controll flow node }
  186. function DoSet(p : tnode;succ : tnode) : tnode;
  187. var
  188. hp1,hp2, oldexitsuccessor: tnode;
  189. i : longint;
  190. begin
  191. result:=nil;
  192. if p=nil then
  193. exit;
  194. case p.nodetype of
  195. statementn:
  196. begin
  197. hp1:=p;
  198. result:=p;
  199. while assigned(hp1) do
  200. begin
  201. { does another statement follow? }
  202. if assigned(tstatementnode(hp1).next) then
  203. begin
  204. hp2:=DoSet(tstatementnode(hp1).statement,tstatementnode(hp1).next);
  205. if assigned(hp2) then
  206. tstatementnode(hp1).successor:=hp2
  207. else
  208. tstatementnode(hp1).successor:=tstatementnode(hp1).next;
  209. end
  210. else
  211. begin
  212. hp2:=DoSet(tstatementnode(hp1).statement,succ);
  213. if assigned(hp2) then
  214. tstatementnode(hp1).successor:=hp2
  215. else
  216. tstatementnode(hp1).successor:=succ;
  217. end;
  218. hp1:=tstatementnode(hp1).next;
  219. end;
  220. end;
  221. blockn:
  222. begin
  223. result:=p;
  224. oldexitsuccessor:=Exitsuccessor;
  225. if nf_block_with_exit in p.flags then
  226. Exitsuccessor:=succ;
  227. DoSet(tblocknode(p).statements,succ);
  228. if assigned(tblocknode(p).statements) then
  229. p.successor:=tblocknode(p).statements
  230. else
  231. p.successor:=succ;
  232. Exitsuccessor:=oldexitsuccessor;
  233. end;
  234. forn:
  235. begin
  236. BreakContinueStack.Push(succ,p);
  237. result:=p;
  238. { the successor of the last node of the for body is the dummy loop iteration node
  239. it allows the dfa to inject needed life information into the loop }
  240. tfornode(p).loopiteration:=cnothingnode.create;
  241. DoSet(tfornode(p).t2,tfornode(p).loopiteration);
  242. p.successor:=succ;
  243. BreakContinueStack.Pop;
  244. end;
  245. breakn:
  246. begin
  247. result:=p;
  248. p.successor:=BreakContinueStack.top^.brk;
  249. end;
  250. continuen:
  251. begin
  252. result:=p;
  253. p.successor:=BreakContinueStack.top^.cont;
  254. end;
  255. whilerepeatn:
  256. begin
  257. BreakContinueStack.Push(succ,p);
  258. result:=p;
  259. { the successor of the last node of the while/repeat body is the while node itself }
  260. DoSet(twhilerepeatnode(p).right,p);
  261. p.successor:=succ;
  262. { special case: we do not do a dyn. dfa, but we should handle endless loops }
  263. if is_constboolnode(twhilerepeatnode(p).left) then
  264. begin
  265. if ((lnf_testatbegin in twhilerepeatnode(p).loopflags) and
  266. getbooleanvalue(twhilerepeatnode(p).left)) or (not(lnf_testatbegin in twhilerepeatnode(p).loopflags) and
  267. not(getbooleanvalue(twhilerepeatnode(p).left))) then
  268. p.successor:=nil;
  269. end;
  270. BreakContinueStack.Pop;
  271. end;
  272. ifn:
  273. begin
  274. result:=p;
  275. DoSet(tifnode(p).right,succ);
  276. DoSet(tifnode(p).t1,succ);
  277. p.successor:=succ;
  278. end;
  279. labeln:
  280. begin
  281. result:=p;
  282. if assigned(tlabelnode(p).left) then
  283. begin
  284. DoSet(tlabelnode(p).left,succ);
  285. p.successor:=tlabelnode(p).left;
  286. end
  287. else
  288. p.successor:=succ;
  289. end;
  290. assignn:
  291. begin
  292. result:=p;
  293. p.successor:=succ;
  294. end;
  295. goton:
  296. begin
  297. result:=p;
  298. if not(assigned(tgotonode(p).labelnode)) then
  299. internalerror(2007050701);
  300. p.successor:=tgotonode(p).labelnode;
  301. end;
  302. exitn:
  303. begin
  304. result:=p;
  305. p.successor:=Exitsuccessor;
  306. end;
  307. casen:
  308. begin
  309. result:=p;
  310. DoSet(tcasenode(p).elseblock,succ);
  311. for i:=0 to tcasenode(p).blocks.count-1 do
  312. DoSet(pcaseblock(tcasenode(p).blocks[i])^.statement,succ);
  313. p.successor:=succ;
  314. end;
  315. calln:
  316. begin
  317. { not sure if this is enough (FK) }
  318. result:=p;
  319. if cnf_call_never_returns in tcallnode(p).callnodeflags then
  320. p.successor:=nil
  321. else
  322. p.successor:=succ;
  323. end;
  324. inlinen:
  325. begin
  326. { not sure if this is enough (FK) }
  327. result:=p;
  328. p.successor:=succ;
  329. end;
  330. loadn,
  331. tempcreaten,
  332. tempdeleten,
  333. nothingn:
  334. begin
  335. result:=p;
  336. p.successor:=succ;
  337. end;
  338. raisen:
  339. begin
  340. result:=p;
  341. { raise never returns }
  342. p.successor:=nil;
  343. end;
  344. tryexceptn,
  345. tryfinallyn,
  346. onn:
  347. internalerror(2007050501);
  348. else
  349. ;
  350. end;
  351. end;
  352. begin
  353. BreakContinueStack.Init;
  354. Exitsuccessor:=nil;
  355. DoSet(p,last);
  356. BreakContinueStack.Done;
  357. end;
  358. function adddef(var n: tnode; arg: pointer): foreachnoderesult;
  359. var
  360. defsum : PDFASet absolute arg;
  361. begin
  362. if assigned(n.optinfo) then
  363. begin
  364. DFASetIncludeSet(defsum^,n.optinfo^.def);
  365. { for nodes itself do not necessarily expose the definition of the counter as
  366. the counter might be undefined after the for loop, so include here the counter
  367. explicitly }
  368. if (n.nodetype=forn) and assigned(tfornode(n).left.optinfo) then
  369. DFASetInclude(defsum^,tfornode(n).left.optinfo^.index);
  370. end;
  371. Result:=fen_false;
  372. end;
  373. procedure CalcDefSum(p : tnode);
  374. var
  375. defsum : PDFASet;
  376. begin
  377. p.allocoptinfo;
  378. defsum:[email protected]^.defsum;
  379. if not assigned(defsum^) then
  380. foreachnodestatic(pm_postprocess,p,@adddef,defsum);
  381. end;
  382. function SetExecutionWeight(var n: tnode; arg: pointer): foreachnoderesult;
  383. var
  384. Weight, CaseWeight : longint;
  385. i : Integer;
  386. begin
  387. Result:=fen_false;
  388. n.allocoptinfo;
  389. Weight:=max(plongint(arg)^,1);
  390. case n.nodetype of
  391. casen:
  392. begin
  393. CalcExecutionWeights(tcasenode(n).left,Weight);
  394. CaseWeight:=max(Weight div tcasenode(n).labelcnt,1);
  395. for i:=0 to tcasenode(n).blocks.count-1 do
  396. CalcExecutionWeights(pcaseblock(tcasenode(n).blocks[i])^.statement,CaseWeight);
  397. CalcExecutionWeights(tcasenode(n).elseblock,CaseWeight);
  398. Result:=fen_norecurse_false;
  399. end;
  400. whilerepeatn:
  401. begin
  402. CalcExecutionWeights(twhilerepeatnode(n).right,Weight*8);
  403. CalcExecutionWeights(twhilerepeatnode(n).left,Weight*8);
  404. Result:=fen_norecurse_false;
  405. end;
  406. ifn:
  407. begin
  408. CalcExecutionWeights(tifnode(n).left,Weight);
  409. CalcExecutionWeights(tifnode(n).right,Weight div 2);
  410. CalcExecutionWeights(tifnode(n).t1,Weight div 2);
  411. Result:=fen_norecurse_false;
  412. end;
  413. else
  414. ;
  415. end;
  416. n.optinfo^.executionweight:=Weight;
  417. end;
  418. procedure CalcExecutionWeights(p : tnode;Initial : longint = 100);
  419. begin
  420. if assigned(p) then
  421. foreachnodestatic(pm_postprocess,p,@SetExecutionWeight,Pointer(@Initial));
  422. end;
  423. function adduse(var n: tnode; arg: pointer): foreachnoderesult;
  424. var
  425. usesum : PDFASet absolute arg;
  426. begin
  427. if assigned(n.optinfo) then
  428. DFASetIncludeSet(usesum^,n.optinfo^.use);
  429. Result:=fen_false;
  430. end;
  431. procedure CalcUseSum(p : tnode);
  432. var
  433. usesum : PDFASet;
  434. begin
  435. p.allocoptinfo;
  436. usesum:[email protected]^.usesum;
  437. if not assigned(usesum^) then
  438. foreachnodestatic(pm_postprocess,p,@adduse,usesum);
  439. end;
  440. function has_life_info(n : tnode) : boolean;
  441. begin
  442. result:=assigned(n) and assigned(n.optinfo) and
  443. assigned(n.optinfo^.life);
  444. end;
  445. end.