nutils.pas 42 KB

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