nutils.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222
  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. hs : string;
  561. begin
  562. if not assigned(p.resultdef) then
  563. typecheckpass(p);
  564. { 'decr_ref' suffix is somewhat misleading, all these helpers
  565. set the passed pointer to nil now }
  566. if is_ansistring(p.resultdef) then
  567. hs:='fpc_ansistr_decr_ref'
  568. else if is_widestring(p.resultdef) then
  569. hs:='fpc_widestr_decr_ref'
  570. else if is_unicodestring(p.resultdef) then
  571. hs:='fpc_unicodestr_decr_ref'
  572. else if is_interfacecom_or_dispinterface(p.resultdef) then
  573. hs:='fpc_intf_decr_ref'
  574. else
  575. hs:='';
  576. if hs<>'' then
  577. result:=ccallnode.createintern(hs,
  578. ccallparanode.create(
  579. ctypeconvnode.create_internal(p,voidpointertype),
  580. nil))
  581. else if p.resultdef.typ=variantdef then
  582. begin
  583. result:=ccallnode.createintern('fpc_variant_clear',
  584. ccallparanode.create(
  585. ctypeconvnode.create_internal(p,search_system_type('TVARDATA').typedef),
  586. nil));
  587. end
  588. else
  589. result:=ccallnode.createintern('fpc_finalize',
  590. ccallparanode.create(
  591. caddrnode.create_internal(
  592. crttinode.create(
  593. tstoreddef(p.resultdef),initrtti,rdt_normal)),
  594. ccallparanode.create(
  595. caddrnode.create_internal(p),
  596. nil)));
  597. end;
  598. { this function must return a very high value ("infinity") for }
  599. { trees containing a call, the rest can be balanced more or less }
  600. { at will, probably best mainly in terms of required memory }
  601. { accesses }
  602. function node_complexity(p: tnode): cardinal;
  603. var
  604. correction: byte;
  605. {$ifdef ARM}
  606. dummy : byte;
  607. {$endif ARM}
  608. begin
  609. result := 0;
  610. while assigned(p) do
  611. begin
  612. case p.nodetype of
  613. { floating point constants usually need loading from memory }
  614. realconstn,
  615. temprefn,
  616. loadvmtaddrn,
  617. { main reason for the next one: we can't take the address of }
  618. { loadparentfpnode, so replacing it by a temp which is the }
  619. { address of this node's location and then dereferencing }
  620. { doesn't work. If changed, check whether webtbs/tw0935 }
  621. { still works with nodeinlining (JM) }
  622. loadparentfpn:
  623. begin
  624. result := 1;
  625. exit;
  626. end;
  627. loadn:
  628. begin
  629. if assigned(tloadnode(p).left) then
  630. inc(result,node_complexity(tloadnode(p).left));
  631. { threadvars need a helper call }
  632. if (tloadnode(p).symtableentry.typ=staticvarsym) and
  633. (vo_is_thread_var in tstaticvarsym(tloadnode(p).symtableentry).varoptions) then
  634. inc(result,5)
  635. else
  636. inc(result);
  637. if (result >= NODE_COMPLEXITY_INF) then
  638. result := NODE_COMPLEXITY_INF;
  639. exit;
  640. end;
  641. subscriptn:
  642. begin
  643. if is_implicit_pointer_object_type(tunarynode(p).left.resultdef) then
  644. inc(result,2);
  645. if (result = NODE_COMPLEXITY_INF) then
  646. exit;
  647. p := tunarynode(p).left;
  648. end;
  649. blockn,
  650. callparan:
  651. p := tunarynode(p).left;
  652. notn,
  653. derefn :
  654. begin
  655. inc(result);
  656. if (result = NODE_COMPLEXITY_INF) then
  657. exit;
  658. p := tunarynode(p).left;
  659. end;
  660. typeconvn:
  661. begin
  662. { may be more complex in some cases }
  663. 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
  664. inc(result);
  665. if (result = NODE_COMPLEXITY_INF) then
  666. exit;
  667. p := tunarynode(p).left;
  668. end;
  669. vecn,
  670. statementn:
  671. begin
  672. inc(result,node_complexity(tbinarynode(p).left));
  673. if (result >= NODE_COMPLEXITY_INF) then
  674. begin
  675. result := NODE_COMPLEXITY_INF;
  676. exit;
  677. end;
  678. p := tbinarynode(p).right;
  679. end;
  680. addn,subn,orn,andn,xorn,muln,divn,modn,symdifn,
  681. shln,shrn,
  682. equaln,unequaln,gtn,gten,ltn,lten,
  683. assignn:
  684. begin
  685. {$ifdef CPU64BITALU}
  686. correction:=1;
  687. {$else CPU64BITALU}
  688. correction:=2;
  689. {$endif CPU64BITALU}
  690. inc(result,node_complexity(tbinarynode(p).left)+1*correction);
  691. if (p.nodetype in [muln,divn,modn]) then
  692. inc(result,5*correction*correction);
  693. if (result >= NODE_COMPLEXITY_INF) then
  694. begin
  695. result := NODE_COMPLEXITY_INF;
  696. exit;
  697. end;
  698. p := tbinarynode(p).right;
  699. end;
  700. ordconstn:
  701. begin
  702. {$ifdef ARM}
  703. if not(is_shifter_const(tordconstnode(p).value.svalue,dummy)) then
  704. result:=2;
  705. {$endif ARM}
  706. exit;
  707. end;
  708. stringconstn,
  709. tempcreaten,
  710. tempdeleten,
  711. pointerconstn,
  712. nothingn,
  713. niln:
  714. exit;
  715. inlinen:
  716. begin
  717. { this code assumes that the inline node has }
  718. { already been firstpassed, and consequently }
  719. { that inline nodes which are transformed into }
  720. { calls already have been transformed }
  721. case tinlinenode(p).inlinenumber of
  722. in_lo_qword,
  723. in_hi_qword,
  724. in_lo_long,
  725. in_hi_long,
  726. in_lo_word,
  727. in_hi_word,
  728. in_length_x,
  729. in_assigned_x,
  730. in_pred_x,
  731. in_succ_x,
  732. in_round_real,
  733. in_trunc_real,
  734. in_int_real,
  735. in_frac_real,
  736. in_cos_real,
  737. in_sin_real,
  738. in_arctan_real,
  739. in_pi_real,
  740. in_abs_real,
  741. in_sqr_real,
  742. in_sqrt_real,
  743. in_ln_real,
  744. in_unaligned_x,
  745. in_prefetch_var:
  746. begin
  747. inc(result);
  748. p:=tunarynode(p).left;
  749. end;
  750. in_abs_long:
  751. begin
  752. inc(result,3);
  753. if (result >= NODE_COMPLEXITY_INF) then
  754. begin
  755. result:=NODE_COMPLEXITY_INF;
  756. exit;
  757. end;
  758. p:=tunarynode(p).left;
  759. end;
  760. in_sizeof_x,
  761. in_typeof_x:
  762. begin
  763. inc(result);
  764. if (tinlinenode(p).left.nodetype<>typen) then
  765. { get instance vmt }
  766. p:=tunarynode(p).left
  767. else
  768. { type vmt = global symbol, result is }
  769. { already increased above }
  770. exit;
  771. end;
  772. {$ifdef SUPPORT_MMX}
  773. in_mmx_pcmpeqb..in_mmx_pcmpgtw,
  774. {$endif SUPPORT_MMX}
  775. { load from global symbol }
  776. in_typeinfo_x,
  777. { load frame pointer }
  778. in_get_frame,
  779. in_get_caller_frame,
  780. in_get_caller_addr:
  781. begin
  782. inc(result);
  783. exit;
  784. end;
  785. in_inc_x,
  786. in_dec_x,
  787. in_include_x_y,
  788. in_exclude_x_y,
  789. in_assert_x_y :
  790. begin
  791. { operation (add, sub, or, and }
  792. inc(result);
  793. { left expression }
  794. inc(result,node_complexity(tcallparanode(tunarynode(p).left).left));
  795. if (result >= NODE_COMPLEXITY_INF) then
  796. begin
  797. result := NODE_COMPLEXITY_INF;
  798. exit;
  799. end;
  800. p:=tcallparanode(tunarynode(p).left).right;
  801. if assigned(p) then
  802. p:=tcallparanode(p).left;
  803. end;
  804. else
  805. begin
  806. result := NODE_COMPLEXITY_INF;
  807. exit;
  808. end;
  809. end;
  810. end;
  811. else
  812. begin
  813. result := NODE_COMPLEXITY_INF;
  814. exit;
  815. end;
  816. end;
  817. end;
  818. end;
  819. { this function returns an indication how much fpu registers
  820. will be required.
  821. Note: The algorithms need to be pessimistic to prevent a
  822. fpu stack overflow on i386 }
  823. function node_resources_fpu(p: tnode): cardinal;
  824. var
  825. res1,res2,res3 : cardinal;
  826. begin
  827. result:=0;
  828. res1:=0;
  829. res2:=0;
  830. res3:=0;
  831. if p.inheritsfrom(tunarynode) then
  832. begin
  833. if assigned(tunarynode(p).left) then
  834. res1:=node_resources_fpu(tunarynode(p).left);
  835. if p.inheritsfrom(tbinarynode) then
  836. begin
  837. if assigned(tbinarynode(p).right) then
  838. res2:=node_resources_fpu(tbinarynode(p).right);
  839. if p.inheritsfrom(ttertiarynode) and assigned(ttertiarynode(p).third) then
  840. res3:=node_resources_fpu(ttertiarynode(p).third)
  841. end;
  842. end;
  843. result:=max(max(res1,res2),res3);
  844. case p.nodetype of
  845. calln:
  846. { it could be a recursive call, so we never really know the number of used fpu registers }
  847. result:=maxfpuregs;
  848. realconstn,
  849. typeconvn,
  850. loadn :
  851. begin
  852. if p.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER] then
  853. result:=max(result,1);
  854. end;
  855. assignn,
  856. addn,subn,muln,slashn,
  857. equaln,unequaln,gtn,gten,ltn,lten :
  858. begin
  859. if (tbinarynode(p).left.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) or
  860. (tbinarynode(p).right.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER])then
  861. result:=max(result,2);
  862. if(p.expectloc in [LOC_CFPUREGISTER,LOC_FPUREGISTER]) then
  863. inc(result);
  864. end;
  865. end;
  866. end;
  867. function setnodefilepos(var n: tnode; arg: pointer): foreachnoderesult;
  868. begin
  869. result:=fen_true;
  870. n.fileinfo:=pfileposinfo(arg)^;
  871. end;
  872. procedure node_tree_set_filepos(var n:tnode;const filepos:tfileposinfo);
  873. begin
  874. foreachnodestatic(n,@setnodefilepos,@filepos);
  875. end;
  876. function callsimplify(var n: tnode; arg: pointer): foreachnoderesult;
  877. var
  878. hn : tnode;
  879. treechanged : ^boolean;
  880. begin
  881. result:=fen_false;
  882. if n.inheritsfrom(tloopnode) and
  883. not (lnf_simplify_processing in tloopnode(n).loopflags) then
  884. begin
  885. // Try to simplify condition
  886. doinlinesimplify(tloopnode(n).left);
  887. // call directly second part below,
  888. // which might change the loopnode into
  889. // something else if the conditino is a constant node
  890. include(tloopnode(n).loopflags,lnf_simplify_processing);
  891. callsimplify(n,arg);
  892. // Be careful, n might have change node type
  893. if n.inheritsfrom(tloopnode) then
  894. exclude(tloopnode(n).loopflags,lnf_simplify_processing);
  895. end
  896. else
  897. begin
  898. hn:=n.simplify(true);
  899. if assigned(hn) then
  900. begin
  901. treechanged := arg;
  902. if assigned(treechanged) then
  903. treechanged^:=true
  904. else
  905. internalerror (201008181);
  906. n.free;
  907. n:=hn;
  908. typecheckpass(n);
  909. end;
  910. end;
  911. end;
  912. { tries to simplify the given node calling the simplify method recursively }
  913. procedure doinlinesimplify(var n : tnode);
  914. var
  915. treechanged : boolean;
  916. begin
  917. // Optimize if code first
  918. repeat
  919. treechanged:=false;
  920. foreachnodestatic(pm_postandagain,n,@callsimplify,@treechanged);
  921. until not(treechanged);
  922. end;
  923. function create_simplified_ord_const(value: tconstexprint; def: tdef; forinline: boolean): tnode;
  924. begin
  925. if not forinline then
  926. result:=genintconstnode(value)
  927. else
  928. result:=cordconstnode.create(value,def,cs_check_range in current_settings.localswitches);
  929. end;
  930. function getpropaccesslist(propsym:tpropertysym; pap:tpropaccesslisttypes;out propaccesslist:tpropaccesslist):boolean;
  931. var
  932. hpropsym : tpropertysym;
  933. begin
  934. result:=false;
  935. { find property in the overridden list }
  936. hpropsym:=propsym;
  937. repeat
  938. propaccesslist:=hpropsym.propaccesslist[pap];
  939. if not propaccesslist.empty then
  940. begin
  941. result:=true;
  942. exit;
  943. end;
  944. hpropsym:=hpropsym.overriddenpropsym;
  945. until not assigned(hpropsym);
  946. end;
  947. procedure propaccesslist_to_node(var p1:tnode;st:TSymtable;pl:tpropaccesslist);
  948. var
  949. plist : ppropaccesslistitem;
  950. begin
  951. plist:=pl.firstsym;
  952. while assigned(plist) do
  953. begin
  954. case plist^.sltype of
  955. sl_load :
  956. begin
  957. addsymref(plist^.sym);
  958. if not assigned(st) then
  959. st:=plist^.sym.owner;
  960. { p1 can already contain the loadnode of
  961. the class variable. When there is no tree yet we
  962. may need to load it for with or objects }
  963. if not assigned(p1) then
  964. begin
  965. case st.symtabletype of
  966. withsymtable :
  967. p1:=tnode(twithsymtable(st).withrefnode).getcopy;
  968. ObjectSymtable :
  969. p1:=load_self_node;
  970. end;
  971. end;
  972. if assigned(p1) then
  973. p1:=csubscriptnode.create(plist^.sym,p1)
  974. else
  975. p1:=cloadnode.create(plist^.sym,st);
  976. end;
  977. sl_subscript :
  978. begin
  979. addsymref(plist^.sym);
  980. p1:=csubscriptnode.create(plist^.sym,p1);
  981. end;
  982. sl_typeconv :
  983. p1:=ctypeconvnode.create_explicit(p1,plist^.def);
  984. sl_absolutetype :
  985. begin
  986. p1:=ctypeconvnode.create(p1,plist^.def);
  987. include(p1.flags,nf_absolute);
  988. end;
  989. sl_vec :
  990. p1:=cvecnode.create(p1,cordconstnode.create(plist^.value,plist^.valuedef,true));
  991. else
  992. internalerror(200110205);
  993. end;
  994. plist:=plist^.next;
  995. end;
  996. end;
  997. function node_to_propaccesslist(p1:tnode):tpropaccesslist;
  998. var
  999. sl : tpropaccesslist;
  1000. procedure addnode(p:tnode);
  1001. begin
  1002. case p.nodetype of
  1003. subscriptn :
  1004. begin
  1005. addnode(tsubscriptnode(p).left);
  1006. sl.addsym(sl_subscript,tsubscriptnode(p).vs);
  1007. end;
  1008. typeconvn :
  1009. begin
  1010. addnode(ttypeconvnode(p).left);
  1011. if nf_absolute in ttypeconvnode(p).flags then
  1012. sl.addtype(sl_absolutetype,ttypeconvnode(p).totypedef)
  1013. else
  1014. sl.addtype(sl_typeconv,ttypeconvnode(p).totypedef);
  1015. end;
  1016. vecn :
  1017. begin
  1018. addnode(tvecnode(p).left);
  1019. if tvecnode(p).right.nodetype=ordconstn then
  1020. sl.addconst(sl_vec,tordconstnode(tvecnode(p).right).value,tvecnode(p).right.resultdef)
  1021. else
  1022. begin
  1023. Message(parser_e_illegal_expression);
  1024. { recovery }
  1025. sl.addconst(sl_vec,0,tvecnode(p).right.resultdef);
  1026. end;
  1027. end;
  1028. loadn :
  1029. sl.addsym(sl_load,tloadnode(p).symtableentry);
  1030. else
  1031. internalerror(200310282);
  1032. end;
  1033. end;
  1034. begin
  1035. sl:=tpropaccesslist.create;
  1036. addnode(p1);
  1037. result:=sl;
  1038. end;
  1039. function is_bitpacked_access(n: tnode): boolean;
  1040. begin
  1041. case n.nodetype of
  1042. vecn:
  1043. result:=
  1044. is_packed_array(tvecnode(n).left.resultdef) and
  1045. { only orddefs and enumdefs are actually bitpacked. Don't consider
  1046. e.g. an access to a 3-byte record as "bitpacked", since it
  1047. isn't }
  1048. (tvecnode(n).left.resultdef.typ in [orddef,enumdef]) and
  1049. not(tarraydef(tvecnode(n).left.resultdef).elepackedbitsize in [8,16,32,64]);
  1050. subscriptn:
  1051. result:=
  1052. is_packed_record_or_object(tsubscriptnode(n).left.resultdef) and
  1053. { see above }
  1054. (tsubscriptnode(n).vs.vardef.typ in [orddef,enumdef]) and
  1055. (not(tsubscriptnode(n).vs.vardef.packedbitsize in [8,16,32,64]) or
  1056. (tsubscriptnode(n).vs.fieldoffset mod 8 <> 0));
  1057. else
  1058. result:=false;
  1059. end;
  1060. end;
  1061. function genloadfield(n: tnode; const fieldname: string): tnode;
  1062. var
  1063. vs : tsym;
  1064. begin
  1065. if not assigned(n.resultdef) then
  1066. typecheckpass(n);
  1067. vs:=tsym(tabstractrecorddef(n.resultdef).symtable.find(fieldname));
  1068. if not assigned(vs) or
  1069. (vs.typ<>fieldvarsym) then
  1070. internalerror(2010061902);
  1071. result:=csubscriptnode.create(vs,n);
  1072. end;
  1073. function has_no_code(n : tnode) : boolean;
  1074. begin
  1075. if n=nil then
  1076. begin
  1077. result:=true;
  1078. exit;
  1079. end;
  1080. result:=false;
  1081. case n.nodetype of
  1082. nothingn:
  1083. begin
  1084. result:=true;
  1085. exit;
  1086. end;
  1087. blockn:
  1088. begin
  1089. result:=has_no_code(tblocknode(n).left);
  1090. exit;
  1091. end;
  1092. statementn:
  1093. begin
  1094. repeat
  1095. result:=has_no_code(tstatementnode(n).left);
  1096. n:=tstatementnode(n).right;
  1097. until not(result) or not assigned(n);
  1098. exit;
  1099. end;
  1100. end;
  1101. end;
  1102. function check_for_sideeffect(var n: tnode; arg: pointer): foreachnoderesult;
  1103. begin
  1104. result:=fen_false;
  1105. if (n.nodetype in [assignn,calln,asmn]) or
  1106. ((n.nodetype=inlinen) and
  1107. (tinlinenode(n).inlinenumber in [in_write_x,in_writeln_x,in_read_x,in_readln_x,in_str_x_string,
  1108. in_val_x,in_reset_x,in_rewrite_x,in_reset_typedfile,in_rewrite_typedfile,in_settextbuf_file_x,
  1109. in_inc_x,in_dec_x,in_include_x_y,in_exclude_x_y,in_break,in_continue,in_setlength_x,
  1110. in_finalize_x,in_new_x,in_dispose_x,in_exit,in_copy_x,in_initialize_x,in_leave,in_cycle])
  1111. ) then
  1112. result:=fen_norecurse_true;
  1113. end;
  1114. function might_have_sideeffects(n : tnode) : boolean;
  1115. begin
  1116. result:=foreachnodestatic(n,@check_for_sideeffect,nil);
  1117. end;
  1118. end.