2
0

optutils.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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. { returns true, if n is a valid node and has life info }
  43. function has_life_info(n : tnode) : boolean;
  44. implementation
  45. uses
  46. cutils,
  47. verbose,
  48. optbase,
  49. ncal,nbas,nflw,nutils,nset,ncon;
  50. function TIndexedNodeSet.Add(node : tnode) : boolean;
  51. var
  52. i : Integer;
  53. p : tnode;
  54. begin
  55. node.allocoptinfo;
  56. p:=Includes(node);
  57. if assigned(p) then
  58. begin
  59. result:=false;
  60. node.optinfo^.index:=p.optinfo^.index;
  61. end
  62. else
  63. begin
  64. i:=inherited Add(node);
  65. node.optinfo^.index:=i;
  66. result:=true;
  67. end
  68. end;
  69. function TIndexedNodeSet.Includes(node : tnode) : tnode;
  70. var
  71. i : longint;
  72. begin
  73. for i:=0 to Count-1 do
  74. if tnode(List^[i]).isequal(node) then
  75. begin
  76. result:=tnode(List^[i]);
  77. exit;
  78. end;
  79. result:=nil;
  80. end;
  81. function TIndexedNodeSet.Remove(node : tnode) : boolean;
  82. var
  83. p : tnode;
  84. begin
  85. result:=false;
  86. p:=Includes(node);
  87. if assigned(p) then
  88. begin
  89. if inherited Remove(p)<>-1 then
  90. result:=true;
  91. end;
  92. end;
  93. procedure PrintIndexedNodeSet(var f : text;s : TIndexedNodeSet);
  94. var
  95. i : integer;
  96. begin
  97. for i:=0 to s.count-1 do
  98. begin
  99. writeln(f,'=============================== Node ',i,' ===============================');
  100. printnode(f,tnode(s[i]));
  101. writeln(f);
  102. end;
  103. end;
  104. function PrintNodeDFA(var n: tnode; arg: pointer): foreachnoderesult;
  105. begin
  106. if assigned(n.optinfo) and ((n.optinfo^.life<>nil) or (n.optinfo^.use<>nil) or (n.optinfo^.def<>nil)) then
  107. begin
  108. write(text(arg^),nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,') Life: ');
  109. PrintDFASet(text(arg^),n.optinfo^.life);
  110. write(text(arg^),' Def: ');
  111. PrintDFASet(text(arg^),n.optinfo^.def);
  112. write(text(arg^),' Use: ');
  113. PrintDFASet(text(arg^),n.optinfo^.use);
  114. if assigned(n.successor) then
  115. write(text(arg^),' Successor: ',nodetype2str[n.successor.nodetype],'(',n.successor.fileinfo.line,',',n.successor.fileinfo.column,')')
  116. else
  117. write(text(arg^),' Successor: nil');
  118. write(text(arg^),' DefSum: ');
  119. PrintDFASet(text(arg^),n.optinfo^.defsum);
  120. writeln(text(arg^));
  121. end;
  122. result:=fen_false;
  123. end;
  124. procedure PrintDFAInfo(var f : text;p : tnode);
  125. begin
  126. foreachnodestatic(pm_postprocess,p,@PrintNodeDFA,@f);
  127. end;
  128. procedure SetNodeSucessors(p,last : tnode);
  129. var
  130. Continuestack : TFPList;
  131. Breakstack : TFPList;
  132. { sets the successor nodes of a node tree block
  133. returns the first node of the tree if it's a controll flow node }
  134. function DoSet(p : tnode;succ : tnode) : tnode;
  135. var
  136. hp1,hp2 : tnode;
  137. i : longint;
  138. begin
  139. result:=nil;
  140. if p=nil then
  141. exit;
  142. case p.nodetype of
  143. statementn:
  144. begin
  145. hp1:=p;
  146. result:=p;
  147. while assigned(hp1) do
  148. begin
  149. { does another statement follow? }
  150. if assigned(tstatementnode(hp1).next) then
  151. begin
  152. hp2:=DoSet(tstatementnode(hp1).statement,tstatementnode(hp1).next);
  153. if assigned(hp2) then
  154. tstatementnode(hp1).successor:=hp2
  155. else
  156. tstatementnode(hp1).successor:=tstatementnode(hp1).next;
  157. end
  158. else
  159. begin
  160. hp2:=DoSet(tstatementnode(hp1).statement,succ);
  161. if assigned(hp2) then
  162. tstatementnode(hp1).successor:=hp2
  163. else
  164. tstatementnode(hp1).successor:=succ;
  165. end;
  166. hp1:=tstatementnode(hp1).next;
  167. end;
  168. end;
  169. blockn:
  170. begin
  171. result:=p;
  172. DoSet(tblocknode(p).statements,succ);
  173. if assigned(tblocknode(p).statements) then
  174. p.successor:=tblocknode(p).statements
  175. else
  176. p.successor:=succ;
  177. end;
  178. forn:
  179. begin
  180. Breakstack.Add(succ);
  181. Continuestack.Add(p);
  182. result:=p;
  183. { the successor of the last node of the for body is the dummy loop iteration node
  184. it allows the dfa to inject needed life information into the loop }
  185. tfornode(p).loopiteration:=cnothingnode.create;
  186. DoSet(tfornode(p).t2,tfornode(p).loopiteration);
  187. p.successor:=succ;
  188. Breakstack.Delete(Breakstack.Count-1);
  189. Continuestack.Delete(Continuestack.Count-1);
  190. end;
  191. breakn:
  192. begin
  193. result:=p;
  194. p.successor:=tnode(Breakstack.Last);
  195. end;
  196. continuen:
  197. begin
  198. result:=p;
  199. p.successor:=tnode(Continuestack.Last);
  200. end;
  201. whilerepeatn:
  202. begin
  203. Breakstack.Add(succ);
  204. Continuestack.Add(p);
  205. result:=p;
  206. { the successor of the last node of the while/repeat body is the while node itself }
  207. DoSet(twhilerepeatnode(p).right,p);
  208. p.successor:=succ;
  209. { special case: we do not do a dyn. dfa, but we should handle endless loops }
  210. if is_constboolnode(twhilerepeatnode(p).left) then
  211. begin
  212. if ((lnf_testatbegin in twhilerepeatnode(p).loopflags) and
  213. getbooleanvalue(twhilerepeatnode(p).left)) or (not(lnf_testatbegin in twhilerepeatnode(p).loopflags) and
  214. not(getbooleanvalue(twhilerepeatnode(p).left))) then
  215. p.successor:=nil;
  216. end;
  217. Breakstack.Delete(Breakstack.Count-1);
  218. Continuestack.Delete(Continuestack.Count-1);
  219. end;
  220. ifn:
  221. begin
  222. result:=p;
  223. DoSet(tifnode(p).right,succ);
  224. DoSet(tifnode(p).t1,succ);
  225. p.successor:=succ;
  226. end;
  227. labeln:
  228. begin
  229. result:=p;
  230. if assigned(tlabelnode(p).left) then
  231. begin
  232. DoSet(tlabelnode(p).left,succ);
  233. p.successor:=tlabelnode(p).left;
  234. end
  235. else
  236. p.successor:=succ;
  237. end;
  238. assignn:
  239. begin
  240. result:=p;
  241. p.successor:=succ;
  242. end;
  243. goton:
  244. begin
  245. result:=p;
  246. if not(assigned(tgotonode(p).labelnode)) then
  247. internalerror(2007050701);
  248. p.successor:=tgotonode(p).labelnode;
  249. end;
  250. exitn:
  251. begin
  252. result:=p;
  253. p.successor:=nil;
  254. end;
  255. casen:
  256. begin
  257. result:=p;
  258. DoSet(tcasenode(p).elseblock,succ);
  259. for i:=0 to tcasenode(p).blocks.count-1 do
  260. DoSet(pcaseblock(tcasenode(p).blocks[i])^.statement,succ);
  261. p.successor:=succ;
  262. end;
  263. calln:
  264. begin
  265. { not sure if this is enough (FK) }
  266. result:=p;
  267. if cnf_call_never_returns in tcallnode(p).callnodeflags then
  268. p.successor:=nil
  269. else
  270. p.successor:=succ;
  271. end;
  272. inlinen:
  273. begin
  274. { not sure if this is enough (FK) }
  275. result:=p;
  276. p.successor:=succ;
  277. end;
  278. loadn,
  279. tempcreaten,
  280. tempdeleten,
  281. nothingn:
  282. begin
  283. result:=p;
  284. p.successor:=succ;
  285. end;
  286. raisen:
  287. begin
  288. result:=p;
  289. { raise never returns }
  290. p.successor:=nil;
  291. end;
  292. tryexceptn,
  293. tryfinallyn,
  294. onn:
  295. internalerror(2007050501);
  296. end;
  297. end;
  298. begin
  299. Breakstack:=TFPList.Create;
  300. Continuestack:=TFPList.Create;
  301. DoSet(p,last);
  302. Continuestack.Free;
  303. Breakstack.Free;
  304. end;
  305. var
  306. sum : TDFASet;
  307. function adddef(var n: tnode; arg: pointer): foreachnoderesult;
  308. begin
  309. if assigned(n.optinfo) then
  310. DFASetIncludeSet(sum,n.optinfo^.def);
  311. Result:=fen_false;
  312. end;
  313. procedure CalcDefSum(p : tnode);
  314. begin
  315. p.allocoptinfo;
  316. if not assigned(p.optinfo^.defsum) then
  317. begin
  318. sum:=nil;
  319. foreachnodestatic(pm_postprocess,p,@adddef,nil);
  320. p.optinfo^.defsum:=sum;
  321. end;
  322. end;
  323. function SetExecutionWeight(var n: tnode; arg: pointer): foreachnoderesult;
  324. var
  325. Weight : longint;
  326. i : Integer;
  327. begin
  328. Result:=fen_false;
  329. n.allocoptinfo;
  330. Weight:=max(plongint(arg)^,1);
  331. case n.nodetype of
  332. casen:
  333. begin
  334. CalcExecutionWeights(tcasenode(n).left,Weight);
  335. for i:=0 to tcasenode(n).blocks.count-1 do
  336. CalcExecutionWeights(pcaseblock(tcasenode(n).blocks[i])^.statement,max(1,Weight div case_count_labels(tcasenode(n).labels)));
  337. CalcExecutionWeights(tcasenode(n).elseblock,max(1,Weight div case_count_labels(tcasenode(n).labels)));
  338. Result:=fen_norecurse_false;
  339. end;
  340. whilerepeatn:
  341. begin
  342. CalcExecutionWeights(twhilerepeatnode(n).right,max(Weight,1)*8);
  343. CalcExecutionWeights(twhilerepeatnode(n).left,max(Weight,1)*8);
  344. Result:=fen_norecurse_false;
  345. end;
  346. ifn:
  347. begin
  348. CalcExecutionWeights(tifnode(n).left,Weight);
  349. CalcExecutionWeights(tifnode(n).right,max(Weight div 2,1));
  350. CalcExecutionWeights(tifnode(n).t1,max(Weight div 2,1));
  351. Result:=fen_norecurse_false;
  352. end;
  353. else
  354. n.optinfo^.executionweight:=weight;
  355. end;
  356. end;
  357. procedure CalcExecutionWeights(p : tnode;Initial : longint = 100);
  358. begin
  359. if assigned(p) then
  360. foreachnodestatic(pm_postprocess,p,@SetExecutionWeight,Pointer(@Initial));
  361. end;
  362. function has_life_info(n : tnode) : boolean;
  363. begin
  364. result:=assigned(n) and assigned(n.optinfo) and
  365. assigned(n.optinfo^.life);
  366. end;
  367. end.