nutils.pas 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Type checking and register allocation for inline nodes
  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 nutils;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,constexp,
  22. symtype,symsym,symbase,symtable,
  23. node;
  24. const
  25. NODE_COMPLEXITY_INF = 255;
  26. type
  27. { resultdef of functions that process on all nodes in a (sub)tree }
  28. foreachnoderesult = (
  29. { false, continue recursion }
  30. fen_false,
  31. { false, stop recursion }
  32. fen_norecurse_false,
  33. { true, continue recursion }
  34. fen_true,
  35. { true, stop recursion }
  36. fen_norecurse_true
  37. );
  38. tforeachprocmethod = (pm_preprocess,pm_postprocess,
  39. pm_postandagain);
  40. foreachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult of object;
  41. staticforeachnodefunction = function(var n: tnode; arg: pointer): foreachnoderesult;
  42. function foreachnode(var n: tnode; f: foreachnodefunction; arg: pointer): boolean;
  43. function foreachnode(procmethod : tforeachprocmethod; var n: tnode; f: foreachnodefunction; arg: pointer): boolean;
  44. function foreachnodestatic(var n: tnode; f: staticforeachnodefunction; arg: pointer): boolean;
  45. function foreachnodestatic(procmethod : tforeachprocmethod; var n: tnode; f: staticforeachnodefunction; arg: pointer): boolean;
  46. { checks if the given node tree contains only nodes of the given type,
  47. if this isn't the case, an ie is thrown
  48. }
  49. procedure checktreenodetypes(n : tnode;typeset : tnodetypeset);
  50. procedure load_procvar_from_calln(var p1:tnode);
  51. function maybe_call_procvar(var p1:tnode;tponly:boolean):boolean;
  52. function get_high_value_sym(vs: tparavarsym):tsym; { marking it as inline causes IE 200311075 during loading from ppu file }
  53. function load_high_value_node(vs:tparavarsym):tnode;
  54. function load_self_node:tnode;
  55. function load_result_node:tnode;
  56. function load_self_pointer_node:tnode;
  57. function load_vmt_pointer_node:tnode;
  58. function is_self_node(p:tnode):boolean;
  59. function call_fail_node:tnode;
  60. function initialize_data_node(p:tnode):tnode;
  61. function finalize_data_node(p:tnode):tnode;
  62. function node_complexity(p: tnode): cardinal;
  63. function node_resources_fpu(p: tnode): cardinal;
  64. procedure node_tree_set_filepos(var n:tnode;const filepos:tfileposinfo);
  65. { tries to simplify the given node after inlining }
  66. procedure doinlinesimplify(var n : tnode);
  67. { creates an ordinal constant, optionally based on the result from a
  68. simplify operation: normally the type is the smallest integer type
  69. that can hold the value, but when inlining the "def" will be used instead,
  70. which was determined during an earlier typecheck pass (because the value
  71. may e.g. be a parameter to a call, which needs to be of the declared
  72. parameter type) }
  73. function create_simplified_ord_const(value: tconstexprint; def: tdef; forinline: boolean): tnode;
  74. { returns true if n is only a tree of administrative nodes
  75. containing no code }
  76. function has_no_code(n : tnode) : boolean;
  77. function getpropaccesslist(propsym:tpropertysym; pap:tpropaccesslisttypes;out propaccesslist:tpropaccesslist):boolean;
  78. procedure propaccesslist_to_node(var p1:tnode;st:TSymtable;pl:tpropaccesslist);
  79. function node_to_propaccesslist(p1:tnode):tpropaccesslist;
  80. { returns true if n is an array element access of a bitpacked array with
  81. elements of the which the vitsize mod 8 <> 0, or if is a field access
  82. with bitsize mod 8 <> 0 or bitoffset mod 8 <> 0 of an element in a
  83. bitpacked structure }
  84. function is_bitpacked_access(n: tnode): boolean;
  85. { creates a load of field 'fieldname' in the record/class/...
  86. represented by n }
  87. function genloadfield(n: tnode; const fieldname: string): tnode;
  88. { returns true, if the tree given might have side effects }
  89. function might_have_sideeffects(n : tnode) : boolean;
  90. implementation
  91. uses
  92. cutils,verbose,globals,
  93. symconst,symdef,
  94. defutil,defcmp,
  95. nbas,ncon,ncnv,nld,nflw,nset,ncal,nadd,nmem,ninl,
  96. cpubase,cgbase,procinfo,
  97. pass_1;
  98. function foreachnode(procmethod : tforeachprocmethod;var n: tnode; f: foreachnodefunction; arg: pointer): boolean;
  99. function process_children(res : boolean) : boolean;
  100. var
  101. i: longint;
  102. begin
  103. result:=res;
  104. case n.nodetype of
  105. asn:
  106. if assigned(tasnode(n).call) then
  107. begin
  108. result := foreachnode(procmethod,tasnode(n).call,f,arg);
  109. exit
  110. end;
  111. calln:
  112. begin
  113. result := foreachnode(procmethod,tnode(tcallnode(n).callinitblock),f,arg) or result;
  114. result := foreachnode(procmethod,tcallnode(n).methodpointer,f,arg) or result;
  115. result := foreachnode(procmethod,tcallnode(n).funcretnode,f,arg) or result;
  116. result := foreachnode(procmethod,tnode(tcallnode(n).callcleanupblock),f,arg) or result;
  117. end;
  118. ifn, whilerepeatn, forn, tryexceptn, tryfinallyn:
  119. begin
  120. { not in one statement, won't work because of b- }
  121. result := foreachnode(procmethod,tloopnode(n).t1,f,arg) or result;
  122. result := foreachnode(procmethod,tloopnode(n).t2,f,arg) or result;
  123. end;
  124. raisen:
  125. { frame tree }
  126. result := foreachnode(traisenode(n).third,f,arg) or result;
  127. tempcreaten:
  128. { temp. initialization code }
  129. if assigned(ttempcreatenode(n).tempinfo^.tempinitcode) then
  130. result := foreachnode(ttempcreatenode(n).tempinfo^.tempinitcode,f,arg) or result;
  131. casen:
  132. begin
  133. for i := 0 to tcasenode(n).blocks.count-1 do
  134. if assigned(tcasenode(n).blocks[i]) then
  135. result := foreachnode(procmethod,pcaseblock(tcasenode(n).blocks[i])^.statement,f,arg) or result;
  136. result := foreachnode(procmethod,tcasenode(n).elseblock,f,arg) or result;
  137. end;
  138. end;
  139. if n.inheritsfrom(tbinarynode) then
  140. begin
  141. { first process the "payload" of statementnodes }
  142. result := foreachnode(procmethod,tbinarynode(n).left,f,arg) or result;
  143. result := foreachnode(procmethod,tbinarynode(n).right,f,arg) or result;
  144. end
  145. else if n.inheritsfrom(tunarynode) then
  146. result := foreachnode(procmethod,tunarynode(n).left,f,arg) or result;
  147. end;
  148. begin
  149. result := false;
  150. if not assigned(n) then
  151. exit;
  152. if procmethod=pm_preprocess then
  153. result:=process_children(result);
  154. case f(n,arg) of
  155. fen_norecurse_false:
  156. exit;
  157. fen_norecurse_true:
  158. begin
  159. result := true;
  160. exit;
  161. end;
  162. fen_true:
  163. result := true;
  164. { result is already false
  165. fen_false:
  166. result := false; }
  167. end;
  168. if (procmethod=pm_postprocess) or (procmethod=pm_postandagain) then
  169. result:=process_children(result);
  170. if procmethod=pm_postandagain then
  171. begin
  172. case f(n,arg) of
  173. fen_norecurse_false:
  174. exit;
  175. fen_norecurse_true:
  176. begin
  177. result := true;
  178. exit;
  179. end;
  180. fen_true:
  181. result := true;
  182. end;
  183. end;
  184. end;
  185. function foreachnode(var n: tnode; f: foreachnodefunction; arg: pointer): boolean;
  186. begin
  187. result:=foreachnode(pm_postprocess,n,f,arg);
  188. end;
  189. function foreachnodestatic(procmethod : tforeachprocmethod;var n: tnode; f: staticforeachnodefunction; arg: pointer): boolean;
  190. function process_children(res : boolean) : boolean;
  191. var
  192. i: longint;
  193. begin
  194. result:=res;
  195. case n.nodetype of
  196. asn:
  197. if assigned(tasnode(n).call) then
  198. begin
  199. result := foreachnodestatic(procmethod,tasnode(n).call,f,arg);
  200. exit
  201. end;
  202. calln:
  203. begin
  204. result := foreachnodestatic(procmethod,tnode(tcallnode(n).callinitblock),f,arg) or result;
  205. result := foreachnodestatic(procmethod,tcallnode(n).methodpointer,f,arg) or result;
  206. result := foreachnodestatic(procmethod,tcallnode(n).funcretnode,f,arg) or result;
  207. result := foreachnodestatic(procmethod,tnode(tcallnode(n).callcleanupblock),f,arg) or result;
  208. end;
  209. ifn, whilerepeatn, forn, tryexceptn, tryfinallyn:
  210. begin
  211. { not in one statement, won't work because of b- }
  212. result := foreachnodestatic(procmethod,tloopnode(n).t1,f,arg) or result;
  213. result := foreachnodestatic(procmethod,tloopnode(n).t2,f,arg) or result;
  214. end;
  215. raisen:
  216. { frame tree }
  217. result := foreachnodestatic(traisenode(n).third,f,arg) or result;
  218. tempcreaten:
  219. { temp. initialization code }
  220. if assigned(ttempcreatenode(n).tempinfo^.tempinitcode) then
  221. result := foreachnodestatic(ttempcreatenode(n).tempinfo^.tempinitcode,f,arg) or result;
  222. casen:
  223. begin
  224. for i := 0 to tcasenode(n).blocks.count-1 do
  225. if assigned(tcasenode(n).blocks[i]) then
  226. result := foreachnodestatic(procmethod,pcaseblock(tcasenode(n).blocks[i])^.statement,f,arg) or result;
  227. result := foreachnodestatic(procmethod,tcasenode(n).elseblock,f,arg) or result;
  228. end;
  229. end;
  230. if n.inheritsfrom(tbinarynode) then
  231. begin
  232. { first process the "payload" of statementnodes }
  233. result := foreachnodestatic(procmethod,tbinarynode(n).left,f,arg) or result;
  234. result := foreachnodestatic(procmethod,tbinarynode(n).right,f,arg) or result;
  235. end
  236. else if n.inheritsfrom(tunarynode) then
  237. result := foreachnodestatic(procmethod,tunarynode(n).left,f,arg) or result;
  238. end;
  239. begin
  240. result := false;
  241. if not assigned(n) then
  242. exit;
  243. if procmethod=pm_preprocess then
  244. result:=process_children(result);
  245. case f(n,arg) of
  246. fen_norecurse_false:
  247. exit;
  248. fen_norecurse_true:
  249. begin
  250. result := true;
  251. exit;
  252. end;
  253. fen_true:
  254. result := true;
  255. { result is already false
  256. fen_false:
  257. result := false; }
  258. end;
  259. if (procmethod=pm_postprocess) or (procmethod=pm_postandagain) then
  260. result:=process_children(result);
  261. if procmethod=pm_postandagain then
  262. begin
  263. case f(n,arg) of
  264. fen_norecurse_false:
  265. exit;
  266. fen_norecurse_true:
  267. begin
  268. result := true;
  269. exit;
  270. end;
  271. fen_true:
  272. result := true;
  273. end;
  274. end;
  275. end;
  276. function foreachnodestatic(var n: tnode; f: staticforeachnodefunction; arg: pointer): boolean;
  277. begin
  278. result:=foreachnodestatic(pm_postprocess,n,f,arg);
  279. end;
  280. function do_check(var n: tnode; arg: pointer): foreachnoderesult;
  281. begin
  282. if not(n.nodetype in pnodetypeset(arg)^) then
  283. internalerror(200610141);
  284. result:=fen_true;
  285. end;
  286. procedure checktreenodetypes(n : tnode;typeset : tnodetypeset);
  287. begin
  288. foreachnodestatic(n,@do_check,@typeset);
  289. end;
  290. procedure load_procvar_from_calln(var p1:tnode);
  291. var
  292. p2 : tnode;
  293. begin
  294. if p1.nodetype<>calln then
  295. internalerror(200212251);
  296. { was it a procvar, then we simply remove the calln and
  297. reuse the right }
  298. if assigned(tcallnode(p1).right) then
  299. begin
  300. p2:=tcallnode(p1).right;
  301. tcallnode(p1).right:=nil;
  302. end
  303. else
  304. begin
  305. p2:=cloadnode.create_procvar(tcallnode(p1).symtableprocentry,
  306. tprocdef(tcallnode(p1).procdefinition),tcallnode(p1).symtableproc);
  307. { when the methodpointer is typen we've something like:
  308. tobject.create. Then only the address is needed of the
  309. method without a self pointer }
  310. if assigned(tcallnode(p1).methodpointer) and
  311. (tcallnode(p1).methodpointer.nodetype<>typen) then
  312. tloadnode(p2).set_mp(tcallnode(p1).methodpointer.getcopy);
  313. end;
  314. typecheckpass(p2);
  315. p1.free;
  316. p1:=p2;
  317. end;
  318. function maybe_call_procvar(var p1:tnode;tponly:boolean):boolean;
  319. var
  320. hp : tnode;
  321. begin
  322. result:=false;
  323. if (p1.resultdef.typ<>procvardef) or
  324. (tponly and
  325. not(m_tp_procvar in current_settings.modeswitches)) then
  326. exit;
  327. { ignore vecn,subscriptn }
  328. hp:=p1;
  329. repeat
  330. case hp.nodetype of
  331. vecn,
  332. derefn,
  333. typeconvn,
  334. subscriptn :
  335. hp:=tunarynode(hp).left;
  336. else
  337. break;
  338. end;
  339. until false;
  340. { a tempref is used when it is loaded from a withsymtable }
  341. if (hp.nodetype in [calln,loadn,temprefn]) then
  342. begin
  343. hp:=ccallnode.create_procvar(nil,p1);
  344. typecheckpass(hp);
  345. p1:=hp;
  346. result:=true;
  347. end;
  348. end;
  349. function get_high_value_sym(vs: tparavarsym):tsym;
  350. begin
  351. result := tsym(vs.owner.Find('high'+vs.name));
  352. end;
  353. function get_local_or_para_sym(const aname:string):tsym;
  354. var
  355. pd : tprocdef;
  356. begin
  357. result:=nil;
  358. { is not assigned while parsing a property }
  359. if not assigned(current_procinfo) then
  360. exit;
  361. { we can't use searchsym here, because the
  362. symtablestack is not fully setup when pass1
  363. is run for nested procedures }
  364. pd:=current_procinfo.procdef;
  365. repeat
  366. result := tsym(pd.localst.Find(aname));
  367. if assigned(result) then
  368. break;
  369. result := tsym(pd.parast.Find(aname));
  370. if assigned(result) then
  371. break;
  372. { try the parent of a nested function }
  373. if assigned(pd.owner.defowner) and
  374. (pd.owner.defowner.typ=procdef) then
  375. pd:=tprocdef(pd.owner.defowner)
  376. else
  377. break;
  378. until false;
  379. end;
  380. function load_high_value_node(vs:tparavarsym):tnode;
  381. var
  382. srsym : tsym;
  383. begin
  384. result:=nil;
  385. srsym:=get_high_value_sym(vs);
  386. if assigned(srsym) then
  387. begin
  388. result:=cloadnode.create(srsym,vs.owner);
  389. typecheckpass(result);
  390. end
  391. else
  392. CGMessage(parser_e_illegal_expression);
  393. end;
  394. function load_self_node:tnode;
  395. var
  396. srsym : tsym;
  397. begin
  398. result:=nil;
  399. srsym:=get_local_or_para_sym('self');
  400. if assigned(srsym) then
  401. begin
  402. result:=cloadnode.create(srsym,srsym.owner);
  403. include(tloadnode(result).loadnodeflags,loadnf_is_self);
  404. end
  405. else
  406. begin
  407. result:=cerrornode.create;
  408. CGMessage(parser_e_illegal_expression);
  409. end;
  410. typecheckpass(result);
  411. end;
  412. function load_result_node:tnode;
  413. var
  414. srsym : tsym;
  415. begin
  416. result:=nil;
  417. srsym:=get_local_or_para_sym('result');
  418. if assigned(srsym) then
  419. result:=cloadnode.create(srsym,srsym.owner)
  420. else
  421. begin
  422. result:=cerrornode.create;
  423. CGMessage(parser_e_illegal_expression);
  424. end;
  425. typecheckpass(result);
  426. end;
  427. function load_self_pointer_node:tnode;
  428. var
  429. srsym : tsym;
  430. begin
  431. result:=nil;
  432. srsym:=get_local_or_para_sym('self');
  433. if assigned(srsym) then
  434. begin
  435. result:=cloadnode.create(srsym,srsym.owner);
  436. include(tloadnode(result).loadnodeflags,loadnf_load_self_pointer);
  437. end
  438. else
  439. begin
  440. result:=cerrornode.create;
  441. CGMessage(parser_e_illegal_expression);
  442. end;
  443. typecheckpass(result);
  444. end;
  445. function load_vmt_pointer_node:tnode;
  446. var
  447. srsym : tsym;
  448. begin
  449. result:=nil;
  450. srsym:=get_local_or_para_sym('vmt');
  451. if assigned(srsym) then
  452. result:=cloadnode.create(srsym,srsym.owner)
  453. else
  454. begin
  455. result:=cerrornode.create;
  456. CGMessage(parser_e_illegal_expression);
  457. end;
  458. typecheckpass(result);
  459. end;
  460. function is_self_node(p:tnode):boolean;
  461. begin
  462. is_self_node:=(p.nodetype=loadn) and
  463. (tloadnode(p).symtableentry.typ=paravarsym) and
  464. (vo_is_self in tparavarsym(tloadnode(p).symtableentry).varoptions);
  465. end;
  466. function call_fail_node:tnode;
  467. var
  468. para : tcallparanode;
  469. newstatement : tstatementnode;
  470. srsym : tsym;
  471. begin
  472. result:=internalstatements(newstatement);
  473. { call fail helper and exit normal }
  474. if is_class(current_structdef) then
  475. begin
  476. srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
  477. if assigned(srsym) and
  478. (srsym.typ=procsym) then
  479. begin
  480. { if self<>0 and vmt<>0 then freeinstance }
  481. addstatement(newstatement,cifnode.create(
  482. caddnode.create(andn,
  483. caddnode.create(unequaln,
  484. load_self_pointer_node,
  485. cnilnode.create),
  486. caddnode.create(unequaln,
  487. load_vmt_pointer_node,
  488. cnilnode.create)),
  489. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  490. nil));
  491. end
  492. else
  493. internalerror(200305108);
  494. end
  495. else
  496. if is_object(current_structdef) then
  497. begin
  498. { parameter 3 : vmt_offset }
  499. { parameter 2 : pointer to vmt }
  500. { parameter 1 : self pointer }
  501. para:=ccallparanode.create(
  502. cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
  503. ccallparanode.create(
  504. ctypeconvnode.create_internal(
  505. load_vmt_pointer_node,
  506. voidpointertype),
  507. ccallparanode.create(
  508. ctypeconvnode.create_internal(
  509. load_self_pointer_node,
  510. voidpointertype),
  511. nil)));
  512. addstatement(newstatement,
  513. ccallnode.createintern('fpc_help_fail',para));
  514. end
  515. else
  516. internalerror(200305132);
  517. { self:=nil }
  518. addstatement(newstatement,cassignmentnode.create(
  519. load_self_pointer_node,
  520. cnilnode.create));
  521. { exit }
  522. addstatement(newstatement,cexitnode.create(nil));
  523. end;
  524. function initialize_data_node(p:tnode):tnode;
  525. begin
  526. if not assigned(p.resultdef) then
  527. typecheckpass(p);
  528. if is_ansistring(p.resultdef) or
  529. is_wide_or_unicode_string(p.resultdef) or
  530. is_interfacecom_or_dispinterface(p.resultdef) or
  531. is_dynamic_array(p.resultdef) then
  532. begin
  533. result:=cassignmentnode.create(
  534. ctypeconvnode.create_internal(p,voidpointertype),
  535. cnilnode.create
  536. );
  537. end
  538. else if (p.resultdef.typ=variantdef) then
  539. begin
  540. result:=ccallnode.createintern('fpc_variant_init',
  541. ccallparanode.create(
  542. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  543. nil));
  544. end
  545. else
  546. begin
  547. result:=ccallnode.createintern('fpc_initialize',
  548. ccallparanode.create(
  549. caddrnode.create_internal(
  550. crttinode.create(
  551. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  552. ccallparanode.create(
  553. caddrnode.create_internal(p),
  554. nil)));
  555. end;
  556. end;
  557. function finalize_data_node(p:tnode):tnode;
  558. var
  559. newstatement : tstatementnode;
  560. begin
  561. if not assigned(p.resultdef) then
  562. typecheckpass(p);
  563. if is_ansistring(p.resultdef) then
  564. begin
  565. result:=internalstatements(newstatement);
  566. addstatement(newstatement,ccallnode.createintern('fpc_ansistr_decr_ref',
  567. ccallparanode.create(
  568. ctypeconvnode.create_internal(p,voidpointertype),
  569. nil)));
  570. addstatement(newstatement,cassignmentnode.create(
  571. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  572. cnilnode.create
  573. ));
  574. end
  575. else if is_widestring(p.resultdef) then
  576. begin
  577. result:=internalstatements(newstatement);
  578. addstatement(newstatement,ccallnode.createintern('fpc_widestr_decr_ref',
  579. ccallparanode.create(
  580. ctypeconvnode.create_internal(p,voidpointertype),
  581. nil)));
  582. addstatement(newstatement,cassignmentnode.create(
  583. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  584. cnilnode.create
  585. ));
  586. end
  587. else if is_unicodestring(p.resultdef) then
  588. begin
  589. result:=internalstatements(newstatement);
  590. addstatement(newstatement,ccallnode.createintern('fpc_unicodestr_decr_ref',
  591. ccallparanode.create(
  592. ctypeconvnode.create_internal(p,voidpointertype),
  593. nil)));
  594. addstatement(newstatement,cassignmentnode.create(
  595. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  596. cnilnode.create
  597. ));
  598. end
  599. else if is_interfacecom_or_dispinterface(p.resultdef) then
  600. begin
  601. result:=internalstatements(newstatement);
  602. addstatement(newstatement,ccallnode.createintern('fpc_intf_decr_ref',
  603. ccallparanode.create(
  604. ctypeconvnode.create_internal(p,voidpointertype),
  605. nil)));
  606. addstatement(newstatement,cassignmentnode.create(
  607. ctypeconvnode.create_internal(p.getcopy,voidpointertype),
  608. cnilnode.create
  609. ));
  610. end
  611. else if p.resultdef.typ=variantdef then
  612. begin
  613. result:=ccallnode.createintern('fpc_variant_clear',
  614. ccallparanode.create(
  615. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  616. nil));
  617. end
  618. else
  619. result:=ccallnode.createintern('fpc_finalize',
  620. ccallparanode.create(
  621. caddrnode.create_internal(
  622. crttinode.create(
  623. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  624. ccallparanode.create(
  625. caddrnode.create_internal(p),
  626. nil)));
  627. end;
  628. { this function must return a very high value ("infinity") for }
  629. { trees containing a call, the rest can be balanced more or less }
  630. { at will, probably best mainly in terms of required memory }
  631. { accesses }
  632. function node_complexity(p: tnode): cardinal;
  633. var
  634. correction: byte;
  635. {$ifdef ARM}
  636. dummy : byte;
  637. {$endif ARM}
  638. begin
  639. result := 0;
  640. while assigned(p) do
  641. begin
  642. case p.nodetype of
  643. { floating point constants usually need loading from memory }
  644. realconstn,
  645. temprefn,
  646. loadvmtaddrn,
  647. { main reason for the next one: we can't take the address of }
  648. { loadparentfpnode, so replacing it by a temp which is the }
  649. { address of this node's location and then dereferencing }
  650. { doesn't work. If changed, check whether webtbs/tw0935 }
  651. { still works with nodeinlining (JM) }
  652. loadparentfpn:
  653. begin
  654. result := 1;
  655. exit;
  656. end;
  657. loadn:
  658. begin
  659. if assigned(tloadnode(p).left) then
  660. inc(result,node_complexity(tloadnode(p).left));
  661. { threadvars need a helper call }
  662. if (tloadnode(p).symtableentry.typ=staticvarsym) and
  663. (vo_is_thread_var in tstaticvarsym(tloadnode(p).symtableentry).varoptions) then
  664. inc(result,5)
  665. else
  666. inc(result);
  667. if (result >= NODE_COMPLEXITY_INF) then
  668. result := NODE_COMPLEXITY_INF;
  669. exit;
  670. end;
  671. subscriptn:
  672. begin
  673. if is_implicit_pointer_object_type(tunarynode(p).left.resultdef) then
  674. inc(result,2);
  675. if (result = NODE_COMPLEXITY_INF) then
  676. exit;
  677. p := tunarynode(p).left;
  678. end;
  679. blockn,
  680. callparan:
  681. p := tunarynode(p).left;
  682. notn,
  683. derefn :
  684. begin
  685. inc(result);
  686. if (result = NODE_COMPLEXITY_INF) then
  687. exit;
  688. p := tunarynode(p).left;
  689. end;
  690. typeconvn:
  691. begin
  692. { may be more complex in some cases }
  693. if not(ttypeconvnode(p).convtype in [tc_equal,tc_int_2_int,tc_bool_2_bool,tc_real_2_real,tc_cord_2_pointer]) then
  694. inc(result);
  695. if (result = NODE_COMPLEXITY_INF) then
  696. exit;
  697. p := tunarynode(p).left;
  698. end;
  699. vecn,
  700. statementn:
  701. begin
  702. inc(result,node_complexity(tbinarynode(p).left));
  703. if (result >= NODE_COMPLEXITY_INF) then
  704. begin
  705. result := NODE_COMPLEXITY_INF;
  706. exit;
  707. end;
  708. p := tbinarynode(p).right;
  709. end;
  710. addn,subn,orn,andn,xorn,muln,divn,modn,symdifn,
  711. shln,shrn,
  712. equaln,unequaln,gtn,gten,ltn,lten,
  713. assignn:
  714. begin
  715. {$ifdef CPU64BITALU}
  716. correction:=1;
  717. {$else CPU64BITALU}
  718. correction:=2;
  719. {$endif CPU64BITALU}
  720. inc(result,node_complexity(tbinarynode(p).left)+1*correction);
  721. if (p.nodetype in [muln,divn,modn]) then
  722. inc(result,5*correction*correction);
  723. if (result >= NODE_COMPLEXITY_INF) then
  724. begin
  725. result := NODE_COMPLEXITY_INF;
  726. exit;
  727. end;
  728. p := tbinarynode(p).right;
  729. end;
  730. ordconstn:
  731. begin
  732. {$ifdef ARM}
  733. if not(is_shifter_const(tordconstnode(p).value.svalue,dummy)) then
  734. result:=2;
  735. {$endif ARM}
  736. exit;
  737. end;
  738. stringconstn,
  739. tempcreaten,
  740. tempdeleten,
  741. pointerconstn,
  742. nothingn,
  743. niln:
  744. exit;
  745. inlinen:
  746. begin
  747. { this code assumes that the inline node has }
  748. { already been firstpassed, and consequently }
  749. { that inline nodes which are transformed into }
  750. { calls already have been transformed }
  751. case tinlinenode(p).inlinenumber of
  752. in_lo_qword,
  753. in_hi_qword,
  754. in_lo_long,
  755. in_hi_long,
  756. in_lo_word,
  757. in_hi_word,
  758. in_length_x,
  759. in_assigned_x,
  760. in_pred_x,
  761. in_succ_x,
  762. in_round_real,
  763. in_trunc_real,
  764. in_int_real,
  765. in_frac_real,
  766. in_cos_real,
  767. in_sin_real,
  768. in_arctan_real,
  769. in_pi_real,
  770. in_abs_real,
  771. in_sqr_real,
  772. in_sqrt_real,
  773. in_ln_real,
  774. in_unaligned_x,
  775. in_prefetch_var:
  776. begin
  777. inc(result);
  778. p:=tunarynode(p).left;
  779. end;
  780. in_abs_long:
  781. begin
  782. inc(result,3);
  783. if (result >= NODE_COMPLEXITY_INF) then
  784. begin
  785. result:=NODE_COMPLEXITY_INF;
  786. exit;
  787. end;
  788. p:=tunarynode(p).left;
  789. end;
  790. in_sizeof_x,
  791. in_typeof_x:
  792. begin
  793. inc(result);
  794. if (tinlinenode(p).left.nodetype<>typen) then
  795. { get instance vmt }
  796. p:=tunarynode(p).left
  797. else
  798. { type vmt = global symbol, result is }
  799. { already increased above }
  800. exit;
  801. end;
  802. {$ifdef SUPPORT_MMX}
  803. in_mmx_pcmpeqb..in_mmx_pcmpgtw,
  804. {$endif SUPPORT_MMX}
  805. { load from global symbol }
  806. in_typeinfo_x,
  807. { load frame pointer }
  808. in_get_frame,
  809. in_get_caller_frame,
  810. in_get_caller_addr:
  811. begin
  812. inc(result);
  813. exit;
  814. end;
  815. in_inc_x,
  816. in_dec_x,
  817. in_include_x_y,
  818. in_exclude_x_y,
  819. in_assert_x_y :
  820. begin
  821. { operation (add, sub, or, and }
  822. inc(result);
  823. { left expression }
  824. inc(result,node_complexity(tcallparanode(tunarynode(p).left).left));
  825. if (result >= NODE_COMPLEXITY_INF) then
  826. begin
  827. result := NODE_COMPLEXITY_INF;
  828. exit;
  829. end;
  830. p:=tcallparanode(tunarynode(p).left).right;
  831. if assigned(p) then
  832. p:=tcallparanode(p).left;
  833. end;
  834. else
  835. begin
  836. result := NODE_COMPLEXITY_INF;
  837. exit;
  838. end;
  839. end;
  840. end;
  841. else
  842. begin
  843. result := NODE_COMPLEXITY_INF;
  844. exit;
  845. end;
  846. end;
  847. end;
  848. end;
  849. { this function returns an indication how much fpu registers
  850. will be required.
  851. Note: The algorithms need to be pessimistic to prevent a
  852. fpu stack overflow on i386 }
  853. function node_resources_fpu(p: tnode): cardinal;
  854. var
  855. res1,res2,res3 : cardinal;
  856. begin
  857. result:=0;
  858. res1:=0;
  859. res2:=0;
  860. res3:=0;
  861. if p.inheritsfrom(tunarynode) then
  862. begin
  863. if assigned(tunarynode(p).left) then
  864. res1:=node_resources_fpu(tunarynode(p).left);
  865. if p.inheritsfrom(tbinarynode) then
  866. begin
  867. if assigned(tbinarynode(p).right) then
  868. res2:=node_resources_fpu(tbinarynode(p).right);
  869. if p.inheritsfrom(ttertiarynode) and assigned(ttertiarynode(p).third) then
  870. res3:=node_resources_fpu(ttertiarynode(p).third)
  871. end;
  872. end;
  873. result:=max(max(res1,res2),res3);
  874. case p.nodetype of
  875. calln:
  876. { it could be a recursive call, so we never really know the number of used fpu registers }
  877. result:=maxfpuregs;
  878. realconstn,
  879. typeconvn,
  880. loadn :
  881. begin
  882. if p.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER] then
  883. result:=max(result,1);
  884. end;
  885. assignn,
  886. addn,subn,muln,slashn,
  887. equaln,unequaln,gtn,gten,ltn,lten :
  888. begin
  889. if (tbinarynode(p).left.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) or
  890. (tbinarynode(p).right.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER])then
  891. result:=max(result,2);
  892. if(p.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) then
  893. inc(result);
  894. end;
  895. end;
  896. end;
  897. function setnodefilepos(var n: tnode; arg: pointer): foreachnoderesult;
  898. begin
  899. result:=fen_true;
  900. n.fileinfo:=pfileposinfo(arg)^;
  901. end;
  902. procedure node_tree_set_filepos(var n:tnode;const filepos:tfileposinfo);
  903. begin
  904. foreachnodestatic(n,@setnodefilepos,@filepos);
  905. end;
  906. function callsimplify(var n: tnode; arg: pointer): foreachnoderesult;
  907. var
  908. hn : tnode;
  909. treechanged : ^boolean;
  910. begin
  911. result:=fen_false;
  912. if n.inheritsfrom(tloopnode) and
  913. not (lnf_simplify_processing in tloopnode(n).loopflags) then
  914. begin
  915. // Try to simplify condition
  916. doinlinesimplify(tloopnode(n).left);
  917. // call directly second part below,
  918. // which might change the loopnode into
  919. // something else if the conditino is a constant node
  920. include(tloopnode(n).loopflags,lnf_simplify_processing);
  921. callsimplify(n,arg);
  922. // Be careful, n might have change node type
  923. if n.inheritsfrom(tloopnode) then
  924. exclude(tloopnode(n).loopflags,lnf_simplify_processing);
  925. end
  926. else
  927. begin
  928. hn:=n.simplify(true);
  929. if assigned(hn) then
  930. begin
  931. treechanged := arg;
  932. if assigned(treechanged) then
  933. treechanged^:=true
  934. else
  935. internalerror (201008181);
  936. n.free;
  937. n:=hn;
  938. typecheckpass(n);
  939. end;
  940. end;
  941. end;
  942. { tries to simplify the given node calling the simplify method recursively }
  943. procedure doinlinesimplify(var n : tnode);
  944. var
  945. treechanged : boolean;
  946. begin
  947. // Optimize if code first
  948. repeat
  949. treechanged:=false;
  950. foreachnodestatic(pm_postandagain,n,@callsimplify,@treechanged);
  951. until not(treechanged);
  952. end;
  953. function create_simplified_ord_const(value: tconstexprint; def: tdef; forinline: boolean): tnode;
  954. begin
  955. if not forinline then
  956. result:=genintconstnode(value)
  957. else
  958. result:=cordconstnode.create(value,def,cs_check_range in current_settings.localswitches);
  959. end;
  960. function getpropaccesslist(propsym:tpropertysym; pap:tpropaccesslisttypes;out propaccesslist:tpropaccesslist):boolean;
  961. var
  962. hpropsym : tpropertysym;
  963. begin
  964. result:=false;
  965. { find property in the overridden list }
  966. hpropsym:=propsym;
  967. repeat
  968. propaccesslist:=hpropsym.propaccesslist[pap];
  969. if not propaccesslist.empty then
  970. begin
  971. result:=true;
  972. exit;
  973. end;
  974. hpropsym:=hpropsym.overriddenpropsym;
  975. until not assigned(hpropsym);
  976. end;
  977. procedure propaccesslist_to_node(var p1:tnode;st:TSymtable;pl:tpropaccesslist);
  978. var
  979. plist : ppropaccesslistitem;
  980. begin
  981. plist:=pl.firstsym;
  982. while assigned(plist) do
  983. begin
  984. case plist^.sltype of
  985. sl_load :
  986. begin
  987. addsymref(plist^.sym);
  988. if not assigned(st) then
  989. st:=plist^.sym.owner;
  990. { p1 can already contain the loadnode of
  991. the class variable. When there is no tree yet we
  992. may need to load it for with or objects }
  993. if not assigned(p1) then
  994. begin
  995. case st.symtabletype of
  996. withsymtable :
  997. p1:=tnode(twithsymtable(st).withrefnode).getcopy;
  998. ObjectSymtable :
  999. p1:=load_self_node;
  1000. end;
  1001. end;
  1002. if assigned(p1) then
  1003. p1:=csubscriptnode.create(plist^.sym,p1)
  1004. else
  1005. p1:=cloadnode.create(plist^.sym,st);
  1006. end;
  1007. sl_subscript :
  1008. begin
  1009. addsymref(plist^.sym);
  1010. p1:=csubscriptnode.create(plist^.sym,p1);
  1011. end;
  1012. sl_typeconv :
  1013. p1:=ctypeconvnode.create_explicit(p1,plist^.def);
  1014. sl_absolutetype :
  1015. begin
  1016. p1:=ctypeconvnode.create(p1,plist^.def);
  1017. include(p1.flags,nf_absolute);
  1018. end;
  1019. sl_vec :
  1020. p1:=cvecnode.create(p1,cordconstnode.create(plist^.value,plist^.valuedef,true));
  1021. else
  1022. internalerror(200110205);
  1023. end;
  1024. plist:=plist^.next;
  1025. end;
  1026. end;
  1027. function node_to_propaccesslist(p1:tnode):tpropaccesslist;
  1028. var
  1029. sl : tpropaccesslist;
  1030. procedure addnode(p:tnode);
  1031. begin
  1032. case p.nodetype of
  1033. subscriptn :
  1034. begin
  1035. addnode(tsubscriptnode(p).left);
  1036. sl.addsym(sl_subscript,tsubscriptnode(p).vs);
  1037. end;
  1038. typeconvn :
  1039. begin
  1040. addnode(ttypeconvnode(p).left);
  1041. if nf_absolute in ttypeconvnode(p).flags then
  1042. sl.addtype(sl_absolutetype,ttypeconvnode(p).totypedef)
  1043. else
  1044. sl.addtype(sl_typeconv,ttypeconvnode(p).totypedef);
  1045. end;
  1046. vecn :
  1047. begin
  1048. addnode(tvecnode(p).left);
  1049. if tvecnode(p).right.nodetype=ordconstn then
  1050. sl.addconst(sl_vec,tordconstnode(tvecnode(p).right).value,tvecnode(p).right.resultdef)
  1051. else
  1052. begin
  1053. Message(parser_e_illegal_expression);
  1054. { recovery }
  1055. sl.addconst(sl_vec,0,tvecnode(p).right.resultdef);
  1056. end;
  1057. end;
  1058. loadn :
  1059. sl.addsym(sl_load,tloadnode(p).symtableentry);
  1060. else
  1061. internalerror(200310282);
  1062. end;
  1063. end;
  1064. begin
  1065. sl:=tpropaccesslist.create;
  1066. addnode(p1);
  1067. result:=sl;
  1068. end;
  1069. function is_bitpacked_access(n: tnode): boolean;
  1070. begin
  1071. case n.nodetype of
  1072. vecn:
  1073. result:=
  1074. is_packed_array(tvecnode(n).left.resultdef) and
  1075. { only orddefs and enumdefs are actually bitpacked. Don't consider
  1076. e.g. an access to a 3-byte record as "bitpacked", since it
  1077. isn't }
  1078. (tvecnode(n).left.resultdef.typ in [orddef,enumdef]) and
  1079. not(tarraydef(tvecnode(n).left.resultdef).elepackedbitsize in [8,16,32,64]);
  1080. subscriptn:
  1081. result:=
  1082. is_packed_record_or_object(tsubscriptnode(n).left.resultdef) and
  1083. { see above }
  1084. (tsubscriptnode(n).vs.vardef.typ in [orddef,enumdef]) and
  1085. (not(tsubscriptnode(n).vs.vardef.packedbitsize in [8,16,32,64]) or
  1086. (tsubscriptnode(n).vs.fieldoffset mod 8 <> 0));
  1087. else
  1088. result:=false;
  1089. end;
  1090. end;
  1091. function genloadfield(n: tnode; const fieldname: string): tnode;
  1092. var
  1093. vs : tsym;
  1094. begin
  1095. if not assigned(n.resultdef) then
  1096. typecheckpass(n);
  1097. vs:=tsym(tabstractrecorddef(n.resultdef).symtable.find(fieldname));
  1098. if not assigned(vs) or
  1099. (vs.typ<>fieldvarsym) then
  1100. internalerror(2010061902);
  1101. result:=csubscriptnode.create(vs,n);
  1102. end;
  1103. function has_no_code(n : tnode) : boolean;
  1104. begin
  1105. if n=nil then
  1106. begin
  1107. result:=true;
  1108. exit;
  1109. end;
  1110. result:=false;
  1111. case n.nodetype of
  1112. nothingn:
  1113. begin
  1114. result:=true;
  1115. exit;
  1116. end;
  1117. blockn:
  1118. begin
  1119. result:=has_no_code(tblocknode(n).left);
  1120. exit;
  1121. end;
  1122. statementn:
  1123. begin
  1124. repeat
  1125. result:=has_no_code(tstatementnode(n).left);
  1126. n:=tstatementnode(n).right;
  1127. until not(result) or not assigned(n);
  1128. exit;
  1129. end;
  1130. end;
  1131. end;
  1132. function check_for_sideeffect(var n: tnode; arg: pointer): foreachnoderesult;
  1133. begin
  1134. result:=fen_false;
  1135. if (n.nodetype in [assignn,calln,asmn]) or
  1136. ((n.nodetype=inlinen) and
  1137. (tinlinenode(n).inlinenumber in [in_write_x,in_writeln_x,in_read_x,in_readln_x,in_str_x_string,
  1138. in_val_x,in_reset_x,in_rewrite_x,in_reset_typedfile,in_rewrite_typedfile,in_settextbuf_file_x,
  1139. in_inc_x,in_dec_x,in_include_x_y,in_exclude_x_y,in_break,in_continue,in_setlength_x,
  1140. in_finalize_x,in_new_x,in_dispose_x,in_exit,in_copy_x,in_initialize_x,in_leave,in_cycle])
  1141. ) then
  1142. result:=fen_norecurse_true;
  1143. end;
  1144. function might_have_sideeffects(n : tnode) : boolean;
  1145. begin
  1146. result:=foreachnodestatic(n,@check_for_sideeffect,nil);
  1147. end;
  1148. end.