nutils.pas 35 KB

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