nutils.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Type checking and register allocation for inline nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit nutils;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. symsym,node;
  23. type
  24. { resulttype of functions that process on all nodes in a (sub)tree }
  25. foreachnoderesult = (
  26. { false, continue recursion }
  27. fen_false,
  28. { false, stop recursion }
  29. fen_norecurse_false,
  30. { true, continue recursion }
  31. fen_true,
  32. { true, stop recursion }
  33. fen_norecurse_true
  34. );
  35. foreachnodefunction = function(var n: tnode): foreachnoderesult of object;
  36. staticforeachnodefunction = function(var n: tnode): foreachnoderesult;
  37. function foreachnode(var n: tnode; f: foreachnodefunction): boolean;
  38. function foreachnodestatic(var n: tnode; f: staticforeachnodefunction): boolean;
  39. procedure load_procvar_from_calln(var p1:tnode);
  40. function maybe_call_procvar(var p1:tnode;tponly:boolean):boolean;
  41. function load_high_value_node(vs:tvarsym):tnode;
  42. function load_self_node:tnode;
  43. function load_result_node:tnode;
  44. function load_self_pointer_node:tnode;
  45. function load_vmt_pointer_node:tnode;
  46. function is_self_node(p:tnode):boolean;
  47. function call_fail_node:tnode;
  48. function initialize_data_node(p:tnode):tnode;
  49. function finalize_data_node(p:tnode):tnode;
  50. implementation
  51. uses
  52. globtype,globals,verbose,
  53. symconst,symbase,symtype,symdef,symtable,
  54. defutil,
  55. nbas,ncon,ncnv,nld,nflw,nset,ncal,nadd,nmem,
  56. cgbase,procinfo,
  57. pass_1;
  58. function foreachnode(var n: tnode; f: foreachnodefunction): boolean;
  59. begin
  60. result := false;
  61. if not assigned(n) then
  62. exit;
  63. case f(n) of
  64. fen_norecurse_false:
  65. exit;
  66. fen_norecurse_true:
  67. begin
  68. result := true;
  69. exit;
  70. end;
  71. fen_true:
  72. result := true;
  73. { result is already false
  74. fen_false:
  75. result := false; }
  76. end;
  77. case n.nodetype of
  78. calln:
  79. begin
  80. { not in one statement, won't work because of b- }
  81. result := foreachnode(tcallnode(n).methodpointer,f) or result;
  82. result := foreachnode(tcallnode(n).inlinecode,f) or result;
  83. end;
  84. ifn, whilerepeatn, forn:
  85. begin
  86. { not in one statement, won't work because of b- }
  87. result := foreachnode(tloopnode(n).t1,f) or result;
  88. result := foreachnode(tloopnode(n).t2,f) or result;
  89. end;
  90. raisen:
  91. result := foreachnode(traisenode(n).frametree,f) or result;
  92. casen:
  93. result := foreachnode(tcasenode(n). elseblock,f) or result;
  94. end;
  95. if n.inheritsfrom(tbinarynode) then
  96. begin
  97. result := foreachnode(tbinarynode(n).right,f) or result;
  98. result := foreachnode(tbinarynode(n).left,f) or result;
  99. end
  100. else if n.inheritsfrom(tunarynode) then
  101. result := foreachnode(tunarynode(n).left,f) or result;
  102. end;
  103. function foreachnodestatic(var n: tnode; f: staticforeachnodefunction): boolean;
  104. begin
  105. result := false;
  106. if not assigned(n) then
  107. exit;
  108. case f(n) of
  109. fen_norecurse_false:
  110. exit;
  111. fen_norecurse_true:
  112. begin
  113. result := true;
  114. exit;
  115. end;
  116. fen_true:
  117. result := true;
  118. { result is already false
  119. fen_false:
  120. result := false; }
  121. end;
  122. case n.nodetype of
  123. calln:
  124. begin
  125. result := foreachnodestatic(tcallnode(n).methodpointer,f) or result;
  126. result := foreachnodestatic(tcallnode(n).inlinecode,f) or result;
  127. end;
  128. ifn, whilerepeatn, forn:
  129. begin
  130. { not in one statement, won't work because of b- }
  131. result := foreachnodestatic(tloopnode(n).t1,f) or result;
  132. result := foreachnodestatic(tloopnode(n).t2,f) or result;
  133. end;
  134. raisen:
  135. result := foreachnodestatic(traisenode(n).frametree,f) or result;
  136. casen:
  137. result := foreachnodestatic(tcasenode(n). elseblock,f) or result;
  138. end;
  139. if n.inheritsfrom(tbinarynode) then
  140. begin
  141. result := foreachnodestatic(tbinarynode(n).right,f) or result;
  142. result := foreachnodestatic(tbinarynode(n).left,f) or result;
  143. end
  144. else if n.inheritsfrom(tunarynode) then
  145. result := foreachnodestatic(tunarynode(n).left,f) or result;
  146. end;
  147. procedure load_procvar_from_calln(var p1:tnode);
  148. var
  149. p2 : tnode;
  150. begin
  151. if p1.nodetype<>calln then
  152. internalerror(200212251);
  153. { was it a procvar, then we simply remove the calln and
  154. reuse the right }
  155. if assigned(tcallnode(p1).right) then
  156. begin
  157. p2:=tcallnode(p1).right;
  158. tcallnode(p1).right:=nil;
  159. end
  160. else
  161. begin
  162. p2:=cloadnode.create_procvar(tcallnode(p1).symtableprocentry,
  163. tprocdef(tcallnode(p1).procdefinition),tcallnode(p1).symtableproc);
  164. { when the methodpointer is typen we've something like:
  165. tobject.create. Then only the address is needed of the
  166. method without a self pointer }
  167. if assigned(tcallnode(p1).methodpointer) and
  168. (tcallnode(p1).methodpointer.nodetype<>typen) then
  169. begin
  170. tloadnode(p2).set_mp(tcallnode(p1).methodpointer);
  171. tcallnode(p1).methodpointer:=nil;
  172. end;
  173. end;
  174. resulttypepass(p2);
  175. p1.free;
  176. p1:=p2;
  177. end;
  178. function maybe_call_procvar(var p1:tnode;tponly:boolean):boolean;
  179. var
  180. hp : tnode;
  181. begin
  182. result:=false;
  183. if (p1.resulttype.def.deftype<>procvardef) or
  184. (tponly and
  185. not(m_tp_procvar in aktmodeswitches)) then
  186. exit;
  187. { ignore vecn,subscriptn }
  188. hp:=p1;
  189. repeat
  190. case hp.nodetype of
  191. vecn,
  192. derefn,
  193. typeconvn,
  194. subscriptn :
  195. hp:=tunarynode(hp).left;
  196. else
  197. break;
  198. end;
  199. until false;
  200. if (hp.nodetype=loadn) then
  201. begin
  202. hp:=ccallnode.create_procvar(nil,p1);
  203. resulttypepass(hp);
  204. p1:=hp;
  205. result:=true;
  206. end;
  207. end;
  208. function load_high_value_node(vs:tvarsym):tnode;
  209. var
  210. srsym : tsym;
  211. srsymtable : tsymtable;
  212. begin
  213. result:=nil;
  214. srsymtable:=vs.owner;
  215. srsym:=searchsymonlyin(srsymtable,'high'+vs.name);
  216. if assigned(srsym) then
  217. begin
  218. result:=cloadnode.create(srsym,srsymtable);
  219. resulttypepass(result);
  220. end
  221. else
  222. CGMessage(cg_e_illegal_expression);
  223. end;
  224. function load_self_node:tnode;
  225. var
  226. srsym : tsym;
  227. srsymtable : tsymtable;
  228. begin
  229. result:=nil;
  230. searchsym('self',srsym,srsymtable);
  231. if assigned(srsym) then
  232. begin
  233. result:=cloadnode.create(srsym,srsymtable);
  234. resulttypepass(result);
  235. end
  236. else
  237. CGMessage(cg_e_illegal_expression);
  238. end;
  239. function load_result_node:tnode;
  240. var
  241. srsym : tsym;
  242. srsymtable : tsymtable;
  243. begin
  244. result:=nil;
  245. searchsym('result',srsym,srsymtable);
  246. if assigned(srsym) then
  247. begin
  248. result:=cloadnode.create(srsym,srsymtable);
  249. resulttypepass(result);
  250. end
  251. else
  252. CGMessage(cg_e_illegal_expression);
  253. end;
  254. function load_self_pointer_node:tnode;
  255. var
  256. srsym : tsym;
  257. srsymtable : tsymtable;
  258. begin
  259. result:=nil;
  260. searchsym('self',srsym,srsymtable);
  261. if assigned(srsym) then
  262. begin
  263. result:=cloadnode.create(srsym,srsymtable);
  264. include(result.flags,nf_load_self_pointer);
  265. resulttypepass(result);
  266. end
  267. else
  268. CGMessage(cg_e_illegal_expression);
  269. end;
  270. function load_vmt_pointer_node:tnode;
  271. var
  272. srsym : tsym;
  273. srsymtable : tsymtable;
  274. begin
  275. result:=nil;
  276. searchsym('vmt',srsym,srsymtable);
  277. if assigned(srsym) then
  278. begin
  279. result:=cloadnode.create(srsym,srsymtable);
  280. resulttypepass(result);
  281. end
  282. else
  283. CGMessage(cg_e_illegal_expression);
  284. end;
  285. function is_self_node(p:tnode):boolean;
  286. begin
  287. is_self_node:=(p.nodetype=loadn) and
  288. (tloadnode(p).symtableentry.typ=varsym) and
  289. (vo_is_self in tvarsym(tloadnode(p).symtableentry).varoptions);
  290. end;
  291. function call_fail_node:tnode;
  292. var
  293. para : tcallparanode;
  294. newstatement : tstatementnode;
  295. srsym : tsym;
  296. begin
  297. result:=internalstatements(newstatement);
  298. { call fail helper and exit normal }
  299. if is_class(current_procinfo.procdef._class) then
  300. begin
  301. srsym:=search_class_member(current_procinfo.procdef._class,'FREEINSTANCE');
  302. if assigned(srsym) and
  303. (srsym.typ=procsym) then
  304. begin
  305. { if self<>0 and vmt=1 then freeinstance }
  306. addstatement(newstatement,cifnode.create(
  307. caddnode.create(andn,
  308. caddnode.create(unequaln,
  309. load_self_pointer_node,
  310. cnilnode.create),
  311. caddnode.create(equaln,
  312. ctypeconvnode.create(
  313. load_vmt_pointer_node,
  314. voidpointertype),
  315. cpointerconstnode.create(1,voidpointertype))),
  316. ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[]),
  317. nil));
  318. end
  319. else
  320. internalerror(200305108);
  321. end
  322. else
  323. if is_object(current_procinfo.procdef._class) then
  324. begin
  325. { parameter 3 : vmt_offset }
  326. { parameter 2 : pointer to vmt }
  327. { parameter 1 : self pointer }
  328. para:=ccallparanode.create(
  329. cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
  330. ccallparanode.create(
  331. ctypeconvnode.create_explicit(
  332. load_vmt_pointer_node,
  333. voidpointertype),
  334. ccallparanode.create(
  335. ctypeconvnode.create_explicit(
  336. load_self_pointer_node,
  337. voidpointertype),
  338. nil)));
  339. addstatement(newstatement,
  340. ccallnode.createintern('fpc_help_fail',para));
  341. end
  342. else
  343. internalerror(200305132);
  344. { self:=nil }
  345. addstatement(newstatement,cassignmentnode.create(
  346. load_self_pointer_node,
  347. cnilnode.create));
  348. { exit }
  349. addstatement(newstatement,cexitnode.create(nil));
  350. end;
  351. function initialize_data_node(p:tnode):tnode;
  352. begin
  353. if not assigned(p.resulttype.def) then
  354. resulttypepass(p);
  355. if is_ansistring(p.resulttype.def) or
  356. is_widestring(p.resulttype.def) or
  357. is_interfacecom(p.resulttype.def) or
  358. is_dynamic_array(p.resulttype.def) then
  359. begin
  360. result:=cassignmentnode.create(
  361. ctypeconvnode.create_explicit(p,voidpointertype),
  362. cnilnode.create
  363. );
  364. end
  365. else
  366. begin
  367. result:=ccallnode.createintern('fpc_initialize',
  368. ccallparanode.create(
  369. caddrnode.create(
  370. crttinode.create(
  371. tstoreddef(p.resulttype.def),initrtti)),
  372. ccallparanode.create(
  373. caddrnode.create(p),
  374. nil)));
  375. end;
  376. end;
  377. function finalize_data_node(p:tnode):tnode;
  378. begin
  379. if not assigned(p.resulttype.def) then
  380. resulttypepass(p);
  381. result:=ccallnode.createintern('fpc_finalize',
  382. ccallparanode.create(
  383. caddrnode.create(
  384. crttinode.create(
  385. tstoreddef(p.resulttype.def),initrtti)),
  386. ccallparanode.create(
  387. caddrnode.create(p),
  388. nil)));
  389. end;
  390. end.
  391. {
  392. $Log$
  393. Revision 1.12 2004-05-23 18:28:41 peter
  394. * methodpointer is loaded into a temp when it was a calln
  395. Revision 1.11 2004/05/23 15:04:49 peter
  396. * generate better code for ansistring initialization
  397. Revision 1.10 2004/02/20 21:55:59 peter
  398. * procvar cleanup
  399. Revision 1.9 2004/02/03 22:32:54 peter
  400. * renamed xNNbittype to xNNinttype
  401. * renamed registers32 to registersint
  402. * replace some s32bit,u32bit with torddef([su]inttype).def.typ
  403. Revision 1.8 2003/11/10 22:02:52 peter
  404. * cross unit inlining fixed
  405. Revision 1.7 2003/10/01 20:34:49 peter
  406. * procinfo unit contains tprocinfo
  407. * cginfo renamed to cgbase
  408. * moved cgmessage to verbose
  409. * fixed ppc and sparc compiles
  410. Revision 1.6 2003/06/13 21:19:30 peter
  411. * current_procdef removed, use current_procinfo.procdef instead
  412. Revision 1.5 2003/05/26 21:17:17 peter
  413. * procinlinenode removed
  414. * aktexit2label removed, fast exit removed
  415. + tcallnode.inlined_pass_2 added
  416. Revision 1.4 2003/05/16 14:33:31 peter
  417. * regvar fixes
  418. Revision 1.3 2003/05/13 20:54:06 peter
  419. * fail checks vmt value before calling dispose
  420. Revision 1.2 2003/05/13 19:14:41 peter
  421. * failn removed
  422. * inherited result code check moven to pexpr
  423. Revision 1.1 2003/04/23 12:35:34 florian
  424. * fixed several issues with powerpc
  425. + applied a patch from Jonas for nested function calls (PowerPC only)
  426. * ...
  427. }