nutils.pas 42 KB

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