optdfa.pas 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  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. procedure redodfainfo(node : tnode);
  37. destructor destroy;override;
  38. end;
  39. procedure CheckAndWarn(code : tnode;nodetosearch : tnode);
  40. implementation
  41. uses
  42. globtype,constexp,
  43. verbose,
  44. symconst,symdef,symsym,
  45. defutil,
  46. procinfo,
  47. nutils,htypechk,
  48. nbas,nflw,ncal,nset,nld,nadd,
  49. optbase;
  50. (*
  51. function initnodes(var n:tnode; arg: pointer) : foreachnoderesult;
  52. begin
  53. { node worth to add? }
  54. if (node_complexity(n)>1) and (tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable) then
  55. begin
  56. plists(arg)^.nodelist.Add(n);
  57. plists(arg)^.locationlist.Add(@n);
  58. result:=fen_false;
  59. end
  60. else
  61. result:=fen_norecurse_false;
  62. end;
  63. *)
  64. {
  65. x:=f; read: [f]
  66. while x do read: []
  67. a:=b; read: [a,b,d] def: [a] life: read*def=[a]
  68. c:=d; read: [a,d] def: [a,c] life: read*def=[a]
  69. e:=a; read: [a] def: [a,c,e] life: read*def=[a]
  70. function f(b,d,x : type) : type;
  71. begin
  72. while x do alive: b,d,x
  73. begin
  74. a:=b; alive: b,d,x
  75. c:=d; alive: a,d,x
  76. e:=a+c; alive: a,c,x
  77. dec(x); alive: c,e,x
  78. end;
  79. result:=c+e; alive: c,e
  80. end; alive: result
  81. }
  82. type
  83. tdfainfo = record
  84. use : PDFASet;
  85. def : PDFASet;
  86. map : TIndexedNodeSet
  87. end;
  88. pdfainfo = ^tdfainfo;
  89. function AddDefUse(var n: tnode; arg: pointer): foreachnoderesult;
  90. begin
  91. case n.nodetype of
  92. tempcreaten:
  93. begin
  94. if assigned(ttempcreatenode(n).tempinfo^.tempinitcode) then
  95. begin
  96. pdfainfo(arg)^.map.Add(n);
  97. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index);
  98. end;
  99. end;
  100. temprefn,
  101. loadn:
  102. begin
  103. pdfainfo(arg)^.map.Add(n);
  104. if nf_modify in n.flags then
  105. begin
  106. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  107. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  108. end
  109. else if nf_write in n.flags then
  110. DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
  111. else
  112. DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
  113. end;
  114. else
  115. ;
  116. end;
  117. result:=fen_false;
  118. end;
  119. function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
  120. begin
  121. exclude(n.flags,nf_processing);
  122. { dfa works only on normalized trees, so do not recurse into expressions, because
  123. ResetProcessing eats a signififcant amount of time of CheckAndWarn
  124. the following set contains (hopefully) most of the expression nodes }
  125. if n.nodetype in [calln,inlinen,assignn,callparan,andn,addn,orn,subn,muln,divn,slashn,notn,equaln,unequaln,gtn,ltn,lten,gten,loadn,
  126. typeconvn,vecn,subscriptn,addrn,derefn] then
  127. result:=fen_norecurse_false
  128. else
  129. result:=fen_false;
  130. end;
  131. function ResetDFA(var n: tnode; arg: pointer): foreachnoderesult;
  132. begin
  133. if assigned(n.optinfo) then
  134. begin
  135. with n.optinfo^ do
  136. begin
  137. life:=nil;
  138. def:=nil;
  139. use:=nil;
  140. defsum:=nil;
  141. end;
  142. end;
  143. result:=fen_false;
  144. end;
  145. procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
  146. var
  147. changed : boolean;
  148. procedure CreateInfo(node : tnode);
  149. { update life entry of a node with l, set changed if this changes
  150. life info for the node
  151. }
  152. procedure updatelifeinfo(n : tnode;l : TDFASet);
  153. var
  154. b : boolean;
  155. begin
  156. b:=DFASetNotEqual(l,n.optinfo^.life);
  157. {$ifdef DEBUG_DFA}
  158. if not(changed) and b then
  159. begin
  160. writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
  161. write(' Life info set was: ');PrintDFASet(Output,n.optinfo^.life);writeln;
  162. write(' Life info set will be: ');PrintDFASet(Output,l);writeln;
  163. end;
  164. {$endif DEBUG_DFA}
  165. changed:=changed or b;
  166. n.optinfo^.life:=l;
  167. end;
  168. procedure calclife(n : tnode);
  169. var
  170. l : TDFASet;
  171. begin
  172. if assigned(n.successor) then
  173. begin
  174. { ensure we can access optinfo }
  175. DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);
  176. DFASetIncludeSet(l,n.optinfo^.use);
  177. DFASetIncludeSet(l,n.optinfo^.life);
  178. end
  179. else
  180. begin
  181. l:=n.optinfo^.use;
  182. DFASetIncludeSet(l,n.optinfo^.life);
  183. end;
  184. updatelifeinfo(n,l);
  185. end;
  186. var
  187. dfainfo : tdfainfo;
  188. l : TDFASet;
  189. save: TDFASet;
  190. lv, hv: TConstExprInt;
  191. i : longint;
  192. counteruse_after_loop : boolean;
  193. begin
  194. if node=nil then
  195. exit;
  196. { ensure we've already optinfo set }
  197. node.allocoptinfo;
  198. if nf_processing in node.flags then
  199. exit;
  200. include(node.flags,nf_processing);
  201. if assigned(node.successor) then
  202. CreateInfo(node.successor);
  203. {$ifdef EXTDEBUG_DFA}
  204. writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');
  205. {$endif EXTDEBUG_DFA}
  206. { life:=succesorlive-definition+use }
  207. case node.nodetype of
  208. whilerepeatn:
  209. begin
  210. { analyze the loop condition }
  211. if not(assigned(node.optinfo^.def)) and
  212. not(assigned(node.optinfo^.use)) then
  213. begin
  214. dfainfo.use:[email protected]^.use;
  215. dfainfo.def:[email protected]^.def;
  216. dfainfo.map:=map;
  217. foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);
  218. end;
  219. { NB: this node should typically have empty def set }
  220. if assigned(node.successor) then
  221. DFASetDiff(l,node.successor.optinfo^.life,node.optinfo^.def)
  222. else if assigned(resultnode) then
  223. DFASetDiff(l,resultnode.optinfo^.life,node.optinfo^.def)
  224. else
  225. l:=nil;
  226. { for repeat..until, node use set in included at the end of loop }
  227. if not (lnf_testatbegin in twhilerepeatnode(node).loopflags) then
  228. DFASetIncludeSet(l,node.optinfo^.use);
  229. DFASetIncludeSet(l,node.optinfo^.life);
  230. save:=node.optinfo^.life;
  231. { to process body correctly, we need life info in place (because
  232. whilerepeatnode is successor of its body). }
  233. node.optinfo^.life:=l;
  234. { now process the body }
  235. CreateInfo(twhilerepeatnode(node).right);
  236. { restore, to prevent infinite recursion via changed flag }
  237. node.optinfo^.life:=save;
  238. { for while loops, node use set is included at the beginning of loop }
  239. l:=twhilerepeatnode(node).right.optinfo^.life;
  240. if lnf_testatbegin in twhilerepeatnode(node).loopflags then
  241. DFASetIncludeSet(l,node.optinfo^.use);
  242. UpdateLifeInfo(node,l);
  243. { ... and a second iteration for fast convergence }
  244. CreateInfo(twhilerepeatnode(node).right);
  245. end;
  246. forn:
  247. begin
  248. {
  249. left: loopvar
  250. right: from
  251. t1: to
  252. t2: body
  253. }
  254. node.allocoptinfo;
  255. tfornode(node).loopiteration.allocoptinfo;
  256. if not(assigned(node.optinfo^.def)) and
  257. not(assigned(node.optinfo^.use)) then
  258. begin
  259. dfainfo.use:[email protected]^.use;
  260. dfainfo.def:[email protected]^.def;
  261. dfainfo.map:=map;
  262. foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);
  263. foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);
  264. foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);
  265. end;
  266. { create life for the body }
  267. CreateInfo(tfornode(node).t2);
  268. { is the counter living after the loop?
  269. if left is a record element, it might not be tracked by dfa, so
  270. optinfo might not be assigned
  271. }
  272. counteruse_after_loop:=assigned(tfornode(node).left.optinfo) and assigned(node.successor) and
  273. DFASetIn(node.successor.optinfo^.life,tfornode(node).left.optinfo^.index);
  274. if counteruse_after_loop then
  275. begin
  276. { if yes, then we should warn }
  277. { !!!!!! }
  278. end
  279. else
  280. Include(tfornode(node).loopflags,lnf_dont_mind_loopvar_on_exit);
  281. { first update the dummy node }
  282. { get the life of the loop block }
  283. l:=copy(tfornode(node).t2.optinfo^.life);
  284. { take care of the sucessor }
  285. if assigned(node.successor) then
  286. DFASetIncludeSet(l,node.successor.optinfo^.life);
  287. { the counter variable is living as well inside the for loop
  288. if left is a record element, it might not be tracked by dfa, so
  289. optinfo might not be assigned
  290. }
  291. if assigned(tfornode(node).left.optinfo) then
  292. DFASetInclude(l,tfornode(node).left.optinfo^.index);
  293. { force block node life info }
  294. UpdateLifeInfo(tfornode(node).loopiteration,l);
  295. { now update the for node itself }
  296. { get the life of the loop block }
  297. l:=copy(tfornode(node).t2.optinfo^.life);
  298. { take care of the sucessor as it's possible that we don't have one execution of the body }
  299. if (not(tfornode(node).right.nodetype=ordconstn) or not(tfornode(node).t1.nodetype=ordconstn)) and
  300. assigned(node.successor) then
  301. DFASetIncludeSet(l,node.successor.optinfo^.life);
  302. {
  303. the counter variable is not living at the entry of the for node
  304. if left is a record element, it might not be tracked by dfa, so
  305. optinfo might not be assigned
  306. }
  307. if assigned(tfornode(node).left.optinfo) then
  308. DFASetExclude(l,tfornode(node).left.optinfo^.index);
  309. { ... but it could be that left/right use it, so do this after
  310. removing the def of the counter variable }
  311. DFASetIncludeSet(l,node.optinfo^.use);
  312. UpdateLifeInfo(node,l);
  313. { ... and a second iteration for fast convergence }
  314. CreateInfo(tfornode(node).t2);
  315. end;
  316. temprefn,
  317. loadn,
  318. typeconvn,
  319. derefn,
  320. assignn:
  321. begin
  322. if not(assigned(node.optinfo^.def)) and
  323. not(assigned(node.optinfo^.use)) then
  324. begin
  325. dfainfo.use:[email protected]^.use;
  326. dfainfo.def:[email protected]^.def;
  327. dfainfo.map:=map;
  328. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  329. end;
  330. calclife(node);
  331. end;
  332. statementn:
  333. begin
  334. { nested statement }
  335. CreateInfo(tstatementnode(node).statement);
  336. { inherit info }
  337. node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;
  338. end;
  339. blockn:
  340. begin
  341. CreateInfo(tblocknode(node).statements);
  342. { ensure that we don't remove life info }
  343. l:=node.optinfo^.life;
  344. if assigned(node.successor) then
  345. DFASetIncludeSet(l,node.successor.optinfo^.life);
  346. UpdateLifeInfo(node,l);
  347. end;
  348. ifn:
  349. begin
  350. { get information from cond. expression }
  351. if not(assigned(node.optinfo^.def)) and
  352. not(assigned(node.optinfo^.use)) then
  353. begin
  354. dfainfo.use:[email protected]^.use;
  355. dfainfo.def:[email protected]^.def;
  356. dfainfo.map:=map;
  357. foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);
  358. end;
  359. { create life info for then and else node }
  360. CreateInfo(tifnode(node).right);
  361. CreateInfo(tifnode(node).t1);
  362. { ensure that we don't remove life info }
  363. l:=node.optinfo^.life;
  364. { get life info from then branch }
  365. if assigned(tifnode(node).right) then
  366. DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);
  367. { get life info from else branch }
  368. if assigned(tifnode(node).t1) then
  369. DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)
  370. else if assigned(node.successor) then
  371. DFASetIncludeSet(l,node.successor.optinfo^.life);
  372. { remove def info from the cond. expression }
  373. DFASetExcludeSet(l,tifnode(node).optinfo^.def);
  374. { add use info from the cond. expression }
  375. DFASetIncludeSet(l,tifnode(node).optinfo^.use);
  376. { finally, update the life info of the node }
  377. UpdateLifeInfo(node,l);
  378. end;
  379. casen:
  380. begin
  381. { get information from "case" expression }
  382. if not(assigned(node.optinfo^.def)) and
  383. not(assigned(node.optinfo^.use)) then
  384. begin
  385. dfainfo.use:[email protected]^.use;
  386. dfainfo.def:[email protected]^.def;
  387. dfainfo.map:=map;
  388. foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);
  389. end;
  390. { create life info for block and else nodes }
  391. for i:=0 to tcasenode(node).blocks.count-1 do
  392. CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);
  393. CreateInfo(tcasenode(node).elseblock);
  394. { ensure that we don't remove life info }
  395. l:=node.optinfo^.life;
  396. { get life info from case branches }
  397. for i:=0 to tcasenode(node).blocks.count-1 do
  398. DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);
  399. { get life info from else branch or the succesor }
  400. if assigned(tcasenode(node).elseblock) then
  401. DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)
  402. else if assigned(node.successor) then
  403. begin
  404. if is_ordinal(tcasenode(node).left.resultdef) then
  405. begin
  406. getrange(tcasenode(node).left.resultdef,lv,hv);
  407. if tcasenode(node).labelcoverage<(hv-lv) then
  408. DFASetIncludeSet(l,node.successor.optinfo^.life);
  409. end
  410. else
  411. DFASetIncludeSet(l,node.successor.optinfo^.life);
  412. end;
  413. { add use info from the "case" expression }
  414. DFASetIncludeSet(l,tcasenode(node).optinfo^.use);
  415. { finally, update the life info of the node }
  416. UpdateLifeInfo(node,l);
  417. end;
  418. exitn:
  419. begin
  420. { in case of inlining, an exit node can have a successor, in this case, we do not have to
  421. use the faked resultnode }
  422. if assigned(node.successor) then
  423. begin
  424. l:=node.optinfo^.life;
  425. DFASetIncludeSet(l,node.successor.optinfo^.life);
  426. UpdateLifeInfo(node,l);
  427. end
  428. else if assigned(resultnode) and (resultnode.nodetype<>nothingn) then
  429. begin
  430. if not(assigned(node.optinfo^.def)) and
  431. not(assigned(node.optinfo^.use)) then
  432. begin
  433. if assigned(texitnode(node).left) then
  434. begin
  435. { this should never happen as
  436. texitnode.pass_typecheck converts the left node into a separate node already
  437. node.optinfo^.def:=resultnode.optinfo^.def;
  438. dfainfo.use:[email protected]^.use;
  439. dfainfo.def:[email protected]^.def;
  440. dfainfo.map:=map;
  441. foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);
  442. calclife(node); }
  443. Internalerror(2020122901);
  444. end
  445. else
  446. begin
  447. { get info from faked resultnode }
  448. node.optinfo^.use:=resultnode.optinfo^.use;
  449. node.optinfo^.life:=node.optinfo^.use;
  450. changed:=true;
  451. end;
  452. end;
  453. end;
  454. end;
  455. {$ifdef JVM}
  456. { all other platforms except jvm translate raise nodes into call nodes during pass_1 }
  457. raisen,
  458. {$endif JVM}
  459. asn,
  460. inlinen,
  461. calln:
  462. begin
  463. if not(assigned(node.optinfo^.def)) and
  464. not(assigned(node.optinfo^.use)) then
  465. begin
  466. dfainfo.use:[email protected]^.use;
  467. dfainfo.def:[email protected]^.def;
  468. dfainfo.map:=map;
  469. foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
  470. end;
  471. calclife(node);
  472. end;
  473. labeln:
  474. begin
  475. calclife(node);
  476. if assigned(tlabelnode(node).left) then
  477. begin
  478. l:=node.optinfo^.life;
  479. DFASetIncludeSet(l,tlabelnode(node).optinfo^.life);
  480. UpdateLifeInfo(node,l);
  481. end;
  482. end;
  483. tempcreaten,
  484. tempdeleten,
  485. nothingn,
  486. continuen,
  487. goton,
  488. breakn:
  489. begin
  490. calclife(node);
  491. end;
  492. else
  493. internalerror(2007050502);
  494. end;
  495. end;
  496. var
  497. runs : integer;
  498. begin
  499. runs:=0;
  500. repeat
  501. inc(runs);
  502. changed:=false;
  503. CreateInfo(node);
  504. foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
  505. { the result node is not reached by foreachnodestatic }
  506. exclude(resultnode.flags,nf_processing);
  507. {$ifdef DEBUG_DFA}
  508. PrintIndexedNodeSet(output,map);
  509. PrintDFAInfo(output,node);
  510. {$endif DEBUG_DFA}
  511. until not(changed);
  512. {$ifdef DEBUG_DFA}
  513. writeln('DFA solver iterations: ',runs);
  514. {$endif DEBUG_DFA}
  515. end;
  516. { reset all dfa info, this is required before creating dfa info
  517. if the tree has been changed without updating dfa }
  518. procedure TDFABuilder.resetdfainfo(node : tnode);
  519. begin
  520. nodemap.Free;
  521. nodemap:=nil;
  522. resultnode.Free;
  523. resultnode:=nil;
  524. foreachnodestatic(pm_postprocess,node,@ResetDFA,nil);
  525. end;
  526. procedure TDFABuilder.createdfainfo(node : tnode);
  527. var
  528. dfarec : tdfainfo;
  529. begin
  530. if not(assigned(nodemap)) then
  531. nodemap:=TIndexedNodeSet.Create;
  532. { create a fake node using the result which will be the last node }
  533. if not(is_void(current_procinfo.procdef.returndef)) then
  534. begin
  535. if current_procinfo.procdef.proctypeoption=potype_constructor then
  536. resultnode:=load_self_node
  537. else
  538. resultnode:=load_result_node;
  539. resultnode.allocoptinfo;
  540. dfarec.use:[email protected]^.use;
  541. dfarec.def:[email protected]^.def;
  542. dfarec.map:=nodemap;
  543. AddDefUse(resultnode,@dfarec);
  544. resultnode.optinfo^.life:=resultnode.optinfo^.use;
  545. end
  546. else
  547. begin
  548. resultnode:=cnothingnode.create;
  549. resultnode.allocoptinfo;
  550. end;
  551. { add controll flow information }
  552. SetNodeSucessors(node,resultnode);
  553. { now, collect life information }
  554. CreateLifeInfo(node,nodemap);
  555. end;
  556. procedure TDFABuilder.redodfainfo(node: tnode);
  557. begin
  558. resetdfainfo(node);
  559. createdfainfo(node);
  560. include(current_procinfo.flags,pi_dfaavailable);
  561. end;
  562. destructor TDFABuilder.Destroy;
  563. begin
  564. Resultnode.free;
  565. nodemap.free;
  566. inherited destroy;
  567. end;
  568. var
  569. { we have to pass the address of SearchNode in a call inside of SearchNode:
  570. @SearchNode does not work because the compiler thinks we take the address of the result
  571. so store the address from outside }
  572. SearchNodeProcPointer : function(var n: tnode; arg: pointer): foreachnoderesult;
  573. type
  574. { helper structure to be able to pass more than one variable to the iterator function }
  575. TSearchNodeInfo = record
  576. nodetosearch : tnode;
  577. { this contains a list of all file locations where a warning was thrown already,
  578. the same location might appear multiple times because nodes might have been copied }
  579. warnedfilelocs : array of tfileposinfo;
  580. end;
  581. PSearchNodeInfo = ^TSearchNodeInfo;
  582. { searches for a given node n and warns if the node is found as being uninitialized. If a node is
  583. found, searching is stopped so each call issues only one warning/hint }
  584. function SearchNode(var n: tnode; arg: pointer): foreachnoderesult;
  585. function WarnedForLocation(f : tfileposinfo) : boolean;
  586. var
  587. i : longint;
  588. begin
  589. result:=true;
  590. for i:=0 to high(PSearchNodeInfo(arg)^.warnedfilelocs) do
  591. with PSearchNodeInfo(arg)^.warnedfilelocs[i] do
  592. begin
  593. if (f.column=column) and (f.fileindex=fileindex) and (f.line=line) and (f.moduleindex=moduleindex) then
  594. exit;
  595. end;
  596. result:=false;
  597. end;
  598. procedure AddFilepos(const f : tfileposinfo);
  599. begin
  600. Setlength(PSearchNodeInfo(arg)^.warnedfilelocs,length(PSearchNodeInfo(arg)^.warnedfilelocs)+1);
  601. PSearchNodeInfo(arg)^.warnedfilelocs[high(PSearchNodeInfo(arg)^.warnedfilelocs)]:=f;
  602. end;
  603. { Checks if the symbol is a candidate for a warning.
  604. Emit warning/note for living locals, result and parameters, but only about the current
  605. symtables }
  606. function SymbolCandidateForWarningOrHint(sym : tabstractnormalvarsym) : Boolean;
  607. begin
  608. Result:=(((sym.owner=current_procinfo.procdef.localst) and
  609. (current_procinfo.procdef.localst.symtablelevel=sym.owner.symtablelevel)
  610. ) or
  611. ((sym.owner=current_procinfo.procdef.parast) and
  612. (sym.typ=paravarsym) and
  613. (current_procinfo.procdef.parast.symtablelevel=sym.owner.symtablelevel) and
  614. { all parameters except out parameters are initialized by the caller }
  615. (tparavarsym(sym).varspez=vs_out)
  616. ) or
  617. ((vo_is_funcret in sym.varoptions) and
  618. (current_procinfo.procdef.parast.symtablelevel=sym.owner.symtablelevel)
  619. )
  620. ) and not(vo_is_external in sym.varoptions) and
  621. not sym.inparentfpstruct;
  622. end;
  623. var
  624. varsym : tabstractnormalvarsym;
  625. methodpointer,
  626. hpt : tnode;
  627. begin
  628. result:=fen_false;
  629. case n.nodetype of
  630. callparan:
  631. begin
  632. { do not warn about variables passed by var, just issue a hint, this
  633. is a workaround for old code e.g. using fillchar }
  634. if assigned(tcallparanode(n).parasym) and (tcallparanode(n).parasym.varspez in [vs_var,vs_out]) then
  635. begin
  636. hpt:=tcallparanode(n).left;
  637. while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn,typeconvn]) do
  638. hpt:=tunarynode(hpt).left;
  639. if assigned(hpt) and (hpt.nodetype=loadn) and not(WarnedForLocation(hpt.fileinfo)) and
  640. SymbolCandidateForWarningOrHint(tabstractnormalvarsym(tloadnode(hpt).symtableentry)) and
  641. PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) then
  642. begin
  643. { issue only a hint for var, when encountering the node passed as out, we need only to stop searching }
  644. if tcallparanode(n).parasym.varspez=vs_var then
  645. UninitializedVariableMessage(hpt.fileinfo,false,
  646. tloadnode(hpt).symtable.symtabletype=localsymtable,
  647. is_managed_type(tloadnode(hpt).resultdef),
  648. tloadnode(hpt).symtableentry.RealName);
  649. AddFilepos(hpt.fileinfo);
  650. result:=fen_norecurse_true;
  651. end
  652. end;
  653. end;
  654. orn,
  655. andn:
  656. begin
  657. { take care of short boolean evaluation: if the expression to be search is found in left,
  658. we do not need to search right }
  659. if foreachnodestatic(pm_postprocess,taddnode(n).left,SearchNodeProcPointer,arg) or
  660. foreachnodestatic(pm_postprocess,taddnode(n).right,SearchNodeProcPointer,arg) then
  661. result:=fen_norecurse_true
  662. else
  663. result:=fen_norecurse_false;
  664. end;
  665. calln:
  666. begin
  667. methodpointer:=tcallnode(n).methodpointer;
  668. if assigned(methodpointer) and (methodpointer.nodetype<>typen) then
  669. begin
  670. { Remove all postfix operators }
  671. hpt:=methodpointer;
  672. while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do
  673. hpt:=tunarynode(hpt).left;
  674. { skip (absolute and other simple) type conversions -- only now,
  675. because the checks above have to take type conversions into
  676. e.g. class reference types account }
  677. hpt:=actualtargetnode(@hpt)^;
  678. { R.Init then R will be initialized by the constructor,
  679. Also allow it for simple loads }
  680. if (tcallnode(n).procdefinition.proctypeoption=potype_constructor) or
  681. (PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) and
  682. (((methodpointer.resultdef.typ=objectdef) and
  683. not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)) or
  684. (methodpointer.resultdef.typ=recorddef)
  685. )
  686. ) then
  687. begin
  688. { don't warn about the method pointer }
  689. AddFilepos(hpt.fileinfo);
  690. if not(foreachnodestatic(pm_postprocess,tcallnode(n).left,SearchNodeProcPointer,arg)) then
  691. foreachnodestatic(pm_postprocess,tcallnode(n).right,SearchNodeProcPointer,arg);
  692. result:=fen_norecurse_true
  693. end;
  694. end;
  695. end;
  696. loadn:
  697. begin
  698. if (tloadnode(n).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) and
  699. PSearchNodeInfo(arg)^.nodetosearch.isequal(n) and ((nf_modify in n.flags) or not(nf_write in n.flags)) then
  700. begin
  701. varsym:=tabstractnormalvarsym(tloadnode(n).symtableentry);
  702. if assigned(varsym.owner) and SymbolCandidateForWarningOrHint(varsym) then
  703. begin
  704. if (vo_is_funcret in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then
  705. begin
  706. if is_managed_type(varsym.vardef) then
  707. MessagePos(n.fileinfo,sym_w_managed_function_result_uninitialized)
  708. else
  709. MessagePos(n.fileinfo,sym_w_function_result_uninitialized);
  710. AddFilepos(n.fileinfo);
  711. result:=fen_norecurse_true;
  712. end
  713. else
  714. begin
  715. { typed consts are initialized, further, warn only once per location }
  716. if not (vo_is_typed_const in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then
  717. begin
  718. UninitializedVariableMessage(n.fileinfo,true,varsym.typ=localvarsym,is_managed_type(varsym.vardef),varsym.realname);
  719. AddFilepos(n.fileinfo);
  720. result:=fen_norecurse_true;
  721. end;
  722. end;
  723. end
  724. {$ifdef dummy}
  725. { if a the variable we are looking for is passed as a var parameter, we stop searching }
  726. else if assigned(varsym.owner) and
  727. (varsym.owner=current_procinfo.procdef.parast) and
  728. (varsym.typ=paravarsym) and
  729. (current_procinfo.procdef.parast.symtablelevel=varsym.owner.symtablelevel) and
  730. (tparavarsym(varsym).varspez=vs_var) then
  731. result:=fen_norecurse_true;
  732. {$endif dummy}
  733. end;
  734. end;
  735. else
  736. ;
  737. end;
  738. end;
  739. procedure CheckAndWarn(code : tnode;nodetosearch : tnode);
  740. var
  741. SearchNodeInfo : TSearchNodeInfo;
  742. function DoCheck(node : tnode) : boolean;
  743. var
  744. i : longint;
  745. touchesnode : Boolean;
  746. procedure MaybeDoCheck(n : tnode);inline;
  747. begin
  748. Result:=Result or DoCheck(n);
  749. end;
  750. procedure MaybeSearchIn(n : tnode);
  751. begin
  752. if touchesnode then
  753. Result:=Result or foreachnodestatic(pm_postprocess,n,@SearchNode,@SearchNodeInfo);
  754. end;
  755. begin
  756. result:=false;
  757. if node=nil then
  758. exit;
  759. if nf_processing in node.flags then
  760. exit;
  761. include(node.flags,nf_processing);
  762. if not(DFASetIn(node.optinfo^.life,nodetosearch.optinfo^.index)) then
  763. exit;
  764. { we do not need this info always, so try to safe some time here, CheckAndWarn
  765. takes a lot of time anyways }
  766. if not(node.nodetype in [statementn,blockn]) then
  767. touchesnode:=DFASetIn(node.optinfo^.use,nodetosearch.optinfo^.index) or
  768. DFASetIn(node.optinfo^.def,nodetosearch.optinfo^.index)
  769. else
  770. touchesnode:=false;
  771. case node.nodetype of
  772. whilerepeatn:
  773. begin
  774. MaybeSearchIn(twhilerepeatnode(node).left);
  775. MaybeDoCheck(twhilerepeatnode(node).right);
  776. end;
  777. forn:
  778. begin
  779. MaybeSearchIn(tfornode(node).right);
  780. MaybeSearchIn(tfornode(node).t1);
  781. MaybeDoCheck(tfornode(node).t2);
  782. end;
  783. statementn:
  784. MaybeDoCheck(tstatementnode(node).statement);
  785. blockn:
  786. MaybeDoCheck(tblocknode(node).statements);
  787. ifn:
  788. begin
  789. MaybeSearchIn(tifnode(node).left);
  790. MaybeDoCheck(tifnode(node).right);
  791. MaybeDoCheck(tifnode(node).t1);
  792. end;
  793. casen:
  794. begin
  795. MaybeSearchIn(tcasenode(node).left);
  796. for i:=0 to tcasenode(node).blocks.count-1 do
  797. MaybeDoCheck(pcaseblock(tcasenode(node).blocks[i])^.statement);
  798. MaybeDoCheck(tcasenode(node).elseblock);
  799. end;
  800. labeln:
  801. MaybeDoCheck(tlabelnode(node).left);
  802. { we are aware of the following nodes so if new node types are added to the compiler
  803. and pop up in the search, the ie below kicks in as a reminder }
  804. exitn:
  805. begin
  806. MaybeSearchIn(texitnode(node).left);
  807. { exit uses the resultnode implicitly, so searching for a matching node is
  808. useless, if we reach the exit node and found the living node not in left, then
  809. it can be only the resultnode
  810. successor might be assigned in case of an inlined exit node, in this case we do not warn about an unassigned
  811. result as this had happened already when the routine has been compiled }
  812. if not(assigned(node.successor)) and not(Result) and not(is_void(current_procinfo.procdef.returndef)) and
  813. not(assigned(texitnode(node).resultexpr)) and
  814. { don't warn about constructors }
  815. not(current_procinfo.procdef.proctypeoption in [potype_class_constructor,potype_constructor]) then
  816. begin
  817. if is_managed_type(current_procinfo.procdef.returndef) then
  818. MessagePos(node.fileinfo,sym_w_managed_function_result_uninitialized)
  819. else
  820. MessagePos(node.fileinfo,sym_w_function_result_uninitialized);
  821. Setlength(SearchNodeInfo.warnedfilelocs,length(SearchNodeInfo.warnedfilelocs)+1);
  822. SearchNodeInfo.warnedfilelocs[high(SearchNodeInfo.warnedfilelocs)]:=node.fileinfo;
  823. end
  824. end;
  825. { could be the implicitly generated load node for the result }
  826. {$ifdef JVM}
  827. { all other platforms except jvm translate raise nodes into call nodes during pass_1 }
  828. raisen,
  829. {$endif JVM}
  830. loadn,
  831. assignn,
  832. calln,
  833. temprefn,
  834. typeconvn,
  835. inlinen,
  836. tempcreaten,
  837. tempdeleten:
  838. MaybeSearchIn(node);
  839. nothingn,
  840. continuen,
  841. goton,
  842. breakn:
  843. ;
  844. else
  845. internalerror(2013111301);
  846. end;
  847. { if already a warning has been issued, then stop }
  848. if Result then
  849. exit;
  850. if assigned(node.successor) then
  851. MaybeDoCheck(node.successor);
  852. end;
  853. begin
  854. SearchNodeInfo.nodetosearch:=nodetosearch;
  855. DoCheck(code);
  856. foreachnodestatic(pm_postprocess,code,@ResetProcessing,nil);
  857. end;
  858. begin
  859. SearchNodeProcPointer:=@SearchNode;
  860. end.