nld.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Type checking and register allocation for load/assignment 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 nld;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,
  22. {$ifdef state_tracking}
  23. nstate,
  24. {$endif}
  25. symconst,symbase,symtype,symsym,symdef;
  26. type
  27. tloadnode = class(tunarynode)
  28. symtableentry : tsym;
  29. symtableentryderef : tderef;
  30. symtable : tsymtable;
  31. procdef : tprocdef;
  32. procdefderef : tderef;
  33. constructor create(v : tsym;st : tsymtable);virtual;
  34. constructor create_procvar(v : tsym;d:tprocdef;st : tsymtable);virtual;
  35. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  36. procedure ppuwrite(ppufile:tcompilerppufile);override;
  37. procedure buildderefimpl;override;
  38. procedure derefimpl;override;
  39. procedure set_mp(p:tnode);
  40. function is_addr_param_load:boolean;
  41. function _getcopy : tnode;override;
  42. function pass_1 : tnode;override;
  43. function det_resulttype:tnode;override;
  44. procedure mark_write;override;
  45. function docompare(p: tnode): boolean; override;
  46. procedure printnodedata(var t:text);override;
  47. end;
  48. tloadnodeclass = class of tloadnode;
  49. { different assignment types }
  50. tassigntype = (at_normal,at_plus,at_minus,at_star,at_slash);
  51. tassignmentnode = class(tbinarynode)
  52. assigntype : tassigntype;
  53. constructor create(l,r : tnode);virtual;
  54. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  55. procedure ppuwrite(ppufile:tcompilerppufile);override;
  56. function _getcopy : tnode;override;
  57. function pass_1 : tnode;override;
  58. function det_resulttype:tnode;override;
  59. {$ifdef state_tracking}
  60. function track_state_pass(exec_known:boolean):boolean;override;
  61. {$endif state_tracking}
  62. function docompare(p: tnode): boolean; override;
  63. end;
  64. tassignmentnodeclass = class of tassignmentnode;
  65. tarrayconstructorrangenode = class(tbinarynode)
  66. constructor create(l,r : tnode);virtual;
  67. function pass_1 : tnode;override;
  68. function det_resulttype:tnode;override;
  69. end;
  70. tarrayconstructorrangenodeclass = class of tarrayconstructorrangenode;
  71. tarrayconstructornode = class(tbinarynode)
  72. constructor create(l,r : tnode);virtual;
  73. function _getcopy : tnode;override;
  74. function pass_1 : tnode;override;
  75. function det_resulttype:tnode;override;
  76. function docompare(p: tnode): boolean; override;
  77. procedure force_type(tt:ttype);
  78. procedure insert_typeconvs;
  79. end;
  80. tarrayconstructornodeclass = class of tarrayconstructornode;
  81. ttypenode = class(tnode)
  82. allowed : boolean;
  83. restype : ttype;
  84. constructor create(t : ttype);virtual;
  85. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  86. procedure ppuwrite(ppufile:tcompilerppufile);override;
  87. procedure buildderefimpl;override;
  88. procedure derefimpl;override;
  89. function pass_1 : tnode;override;
  90. function det_resulttype:tnode;override;
  91. function docompare(p: tnode): boolean; override;
  92. end;
  93. ttypenodeclass = class of ttypenode;
  94. trttinode = class(tnode)
  95. l1,l2 : longint;
  96. rttitype : trttitype;
  97. rttidef : tstoreddef;
  98. rttidefderef : tderef;
  99. constructor create(def:tstoreddef;rt:trttitype);virtual;
  100. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  101. procedure ppuwrite(ppufile:tcompilerppufile);override;
  102. procedure buildderefimpl;override;
  103. procedure derefimpl;override;
  104. function _getcopy : tnode;override;
  105. function pass_1 : tnode;override;
  106. function det_resulttype:tnode;override;
  107. function docompare(p: tnode): boolean; override;
  108. end;
  109. trttinodeclass = class of trttinode;
  110. var
  111. cloadnode : tloadnodeclass;
  112. cassignmentnode : tassignmentnodeclass;
  113. carrayconstructorrangenode : tarrayconstructorrangenodeclass;
  114. carrayconstructornode : tarrayconstructornodeclass;
  115. ctypenode : ttypenodeclass;
  116. crttinode : trttinodeclass;
  117. { Current assignment node }
  118. aktassignmentnode : tassignmentnode;
  119. implementation
  120. uses
  121. cutils,verbose,globtype,globals,systems,
  122. symnot,
  123. defutil,defcmp,
  124. htypechk,pass_1,procinfo,paramgr,
  125. ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
  126. cgobj,cgbase
  127. ;
  128. {*****************************************************************************
  129. TLOADNODE
  130. *****************************************************************************}
  131. constructor tloadnode.create(v : tsym;st : tsymtable);
  132. begin
  133. inherited create(loadn,nil);
  134. if not assigned(v) then
  135. internalerror(200108121);
  136. symtableentry:=v;
  137. symtable:=st;
  138. procdef:=nil;
  139. end;
  140. constructor tloadnode.create_procvar(v : tsym;d:tprocdef;st : tsymtable);
  141. begin
  142. inherited create(loadn,nil);
  143. if not assigned(v) then
  144. internalerror(200108121);
  145. symtableentry:=v;
  146. symtable:=st;
  147. procdef:=d;
  148. end;
  149. constructor tloadnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  150. begin
  151. inherited ppuload(t,ppufile);
  152. ppufile.getderef(symtableentryderef);
  153. symtable:=nil;
  154. ppufile.getderef(procdefderef);
  155. end;
  156. procedure tloadnode.ppuwrite(ppufile:tcompilerppufile);
  157. begin
  158. inherited ppuwrite(ppufile);
  159. ppufile.putderef(symtableentryderef);
  160. ppufile.putderef(procdefderef);
  161. end;
  162. procedure tloadnode.buildderefimpl;
  163. begin
  164. inherited buildderefimpl;
  165. symtableentryderef.build(symtableentry);
  166. procdefderef.build(procdef);
  167. end;
  168. procedure tloadnode.derefimpl;
  169. begin
  170. inherited derefimpl;
  171. symtableentry:=tsym(symtableentryderef.resolve);
  172. symtable:=symtableentry.owner;
  173. procdef:=tprocdef(procdefderef.resolve);
  174. end;
  175. procedure tloadnode.set_mp(p:tnode);
  176. begin
  177. { typen nodes should not be set }
  178. if p.nodetype=typen then
  179. internalerror(200301042);
  180. left:=p;
  181. end;
  182. function tloadnode._getcopy : tnode;
  183. var
  184. n : tloadnode;
  185. begin
  186. n:=tloadnode(inherited _getcopy);
  187. n.symtable:=symtable;
  188. n.symtableentry:=symtableentry;
  189. n.procdef:=procdef;
  190. result:=n;
  191. end;
  192. function tloadnode.is_addr_param_load:boolean;
  193. begin
  194. result:=(symtable.symtabletype=parasymtable) and
  195. (symtableentry.typ=paravarsym) and
  196. not(vo_has_local_copy in tparavarsym(symtableentry).varoptions) and
  197. not(nf_load_self_pointer in flags) and
  198. paramanager.push_addr_param(tparavarsym(symtableentry).varspez,tparavarsym(symtableentry).vartype.def,tprocdef(symtable.defowner).proccalloption);
  199. end;
  200. function tloadnode.det_resulttype:tnode;
  201. begin
  202. result:=nil;
  203. case symtableentry.typ of
  204. absolutevarsym :
  205. resulttype:=tabsolutevarsym(symtableentry).vartype;
  206. constsym:
  207. begin
  208. if tconstsym(symtableentry).consttyp=constresourcestring then
  209. resulttype:=cansistringtype
  210. else
  211. internalerror(22799);
  212. end;
  213. globalvarsym,
  214. paravarsym,
  215. localvarsym :
  216. begin
  217. inc(tabstractvarsym(symtableentry).refs);
  218. { Nested variable? The we need to load the framepointer of
  219. the parent procedure }
  220. if assigned(current_procinfo) then
  221. begin
  222. if (symtable.symtabletype in [localsymtable,parasymtable]) and
  223. (symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) then
  224. begin
  225. if assigned(left) then
  226. internalerror(200309289);
  227. left:=cloadparentfpnode.create(tprocdef(symtable.defowner));
  228. { we can't inline the referenced parent procedure }
  229. exclude(tprocdef(symtable.defowner).procoptions,po_inline);
  230. { reference in nested procedures, variable needs to be in memory }
  231. make_not_regable(self,vr_none);
  232. end;
  233. { static variables referenced in procedures or from finalization,
  234. variable needs to be in memory.
  235. It is too hard and the benefit is too small to detect whether a
  236. variable is only used in the finalization to add support for it (PFV) }
  237. if (symtable.symtabletype=staticsymtable) and
  238. (
  239. (symtable.symtablelevel<>current_procinfo.procdef.localst.symtablelevel) or
  240. (current_procinfo.procdef.proctypeoption=potype_unitfinalize)
  241. ) then
  242. make_not_regable(self,vr_none);
  243. end;
  244. { fix self type which is declared as voidpointer in the
  245. definition }
  246. if vo_is_self in tabstractvarsym(symtableentry).varoptions then
  247. begin
  248. resulttype.setdef(tprocdef(symtableentry.owner.defowner)._class);
  249. if (po_classmethod in tprocdef(symtableentry.owner.defowner).procoptions) or
  250. (po_staticmethod in tprocdef(symtableentry.owner.defowner).procoptions) then
  251. resulttype.setdef(tclassrefdef.create(resulttype))
  252. else if is_object(resulttype.def) and
  253. (nf_load_self_pointer in flags) then
  254. resulttype.setdef(tpointerdef.create(resulttype));
  255. end
  256. else if vo_is_vmt in tabstractvarsym(symtableentry).varoptions then
  257. begin
  258. resulttype.setdef(tprocdef(symtableentry.owner.defowner)._class);
  259. resulttype.setdef(tclassrefdef.create(resulttype));
  260. end
  261. else
  262. resulttype:=tabstractvarsym(symtableentry).vartype;
  263. end;
  264. typedconstsym :
  265. resulttype:=ttypedconstsym(symtableentry).typedconsttype;
  266. procsym :
  267. begin
  268. { Return the first procdef. In case of overlaoded
  269. procdefs the matching procdef will be choosen
  270. when the expected procvardef is known, see get_information
  271. in htypechk.pas (PFV) }
  272. if not assigned(procdef) then
  273. procdef:=tprocsym(symtableentry).first_procdef;
  274. { the result is a procdef, addrn and proc_to_procvar
  275. typeconvn need this as resulttype so they know
  276. that the address needs to be returned }
  277. resulttype.setdef(procdef);
  278. { process methodpointer }
  279. if assigned(left) then
  280. resulttypepass(left);
  281. end;
  282. labelsym:
  283. resulttype:=voidtype;
  284. else
  285. internalerror(200104141);
  286. end;
  287. end;
  288. procedure Tloadnode.mark_write;
  289. begin
  290. include(flags,nf_write);
  291. end;
  292. function tloadnode.pass_1 : tnode;
  293. begin
  294. result:=nil;
  295. expectloc:=LOC_REFERENCE;
  296. registersint:=0;
  297. registersfpu:=0;
  298. {$ifdef SUPPORT_MMX}
  299. registersmmx:=0;
  300. {$endif SUPPORT_MMX}
  301. if (cs_create_pic in aktmoduleswitches) and
  302. not(symtableentry.typ in [paravarsym,localvarsym]) then
  303. include(current_procinfo.flags,pi_needs_got);
  304. case symtableentry.typ of
  305. absolutevarsym :
  306. ;
  307. constsym:
  308. begin
  309. if tconstsym(symtableentry).consttyp=constresourcestring then
  310. expectloc:=LOC_CREFERENCE;
  311. end;
  312. globalvarsym,
  313. localvarsym,
  314. paravarsym :
  315. begin
  316. if assigned(left) then
  317. firstpass(left);
  318. if not is_addr_param_load and
  319. tabstractvarsym(symtableentry).is_regvar(is_addr_param_load) then
  320. begin
  321. case tabstractvarsym(symtableentry).varregable of
  322. vr_intreg,
  323. vr_addr :
  324. expectloc:=LOC_CREGISTER;
  325. vr_fpureg :
  326. expectloc:=LOC_CFPUREGISTER;
  327. vr_mmreg :
  328. expectloc:=LOC_CMMREGISTER;
  329. end
  330. end
  331. else
  332. if (tabstractvarsym(symtableentry).varspez=vs_const) then
  333. expectloc:=LOC_CREFERENCE;
  334. { we need a register for call by reference parameters }
  335. if paramanager.push_addr_param(tabstractvarsym(symtableentry).varspez,tabstractvarsym(symtableentry).vartype.def,pocall_default) then
  336. registersint:=1;
  337. if ([vo_is_thread_var,vo_is_dll_var]*tabstractvarsym(symtableentry).varoptions)<>[] then
  338. registersint:=1;
  339. if (target_info.system=system_powerpc_darwin) and
  340. ([vo_is_dll_var,vo_is_external] * tabstractvarsym(symtableentry).varoptions <> []) then
  341. include(current_procinfo.flags,pi_needs_got);
  342. { call to get address of threadvar }
  343. if (vo_is_thread_var in tabstractvarsym(symtableentry).varoptions) then
  344. include(current_procinfo.flags,pi_do_call);
  345. if nf_write in flags then
  346. Tabstractvarsym(symtableentry).trigger_notifications(vn_onwrite)
  347. else
  348. Tabstractvarsym(symtableentry).trigger_notifications(vn_onread);
  349. { count variable references }
  350. if cg.t_times>1 then
  351. inc(tabstractvarsym(symtableentry).refs,cg.t_times-1);
  352. end;
  353. typedconstsym :
  354. ;
  355. procsym :
  356. begin
  357. { method pointer ? }
  358. if assigned(left) then
  359. begin
  360. expectloc:=LOC_CREFERENCE;
  361. firstpass(left);
  362. registersint:=max(registersint,left.registersint);
  363. registersfpu:=max(registersfpu,left.registersfpu);
  364. {$ifdef SUPPORT_MMX}
  365. registersmmx:=max(registersmmx,left.registersmmx);
  366. {$endif SUPPORT_MMX}
  367. end;
  368. end;
  369. labelsym :
  370. ;
  371. else
  372. internalerror(200104143);
  373. end;
  374. end;
  375. function tloadnode.docompare(p: tnode): boolean;
  376. begin
  377. docompare :=
  378. inherited docompare(p) and
  379. (symtableentry = tloadnode(p).symtableentry) and
  380. (procdef = tloadnode(p).procdef) and
  381. (symtable = tloadnode(p).symtable);
  382. end;
  383. procedure Tloadnode.printnodedata(var t:text);
  384. begin
  385. inherited printnodedata(t);
  386. write(t,printnodeindention,'symbol = ',symtableentry.name);
  387. if symtableentry.typ=procsym then
  388. write(t,printnodeindention,'procdef = ',procdef.mangledname);
  389. writeln(t,'');
  390. end;
  391. {*****************************************************************************
  392. TASSIGNMENTNODE
  393. *****************************************************************************}
  394. constructor tassignmentnode.create(l,r : tnode);
  395. begin
  396. inherited create(assignn,l,r);
  397. l.mark_write;
  398. assigntype:=at_normal;
  399. end;
  400. constructor tassignmentnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  401. begin
  402. inherited ppuload(t,ppufile);
  403. assigntype:=tassigntype(ppufile.getbyte);
  404. end;
  405. procedure tassignmentnode.ppuwrite(ppufile:tcompilerppufile);
  406. begin
  407. inherited ppuwrite(ppufile);
  408. ppufile.putbyte(byte(assigntype));
  409. end;
  410. function tassignmentnode._getcopy : tnode;
  411. var
  412. n : tassignmentnode;
  413. begin
  414. n:=tassignmentnode(inherited _getcopy);
  415. n.assigntype:=assigntype;
  416. result:=n;
  417. end;
  418. function tassignmentnode.det_resulttype:tnode;
  419. var
  420. hp : tnode;
  421. useshelper : boolean;
  422. begin
  423. result:=nil;
  424. resulttype:=voidtype;
  425. { must be made unique }
  426. set_unique(left);
  427. resulttypepass(left);
  428. {$ifdef old_append_str}
  429. if is_ansistring(left.resulttype.def) then
  430. begin
  431. { fold <ansistring>:=<ansistring>+<char|shortstring|ansistring> }
  432. if (right.nodetype=addn) and
  433. left.isequal(tbinarynode(right).left) and
  434. { don't fold multiple concatenations else we could get trouble
  435. with multiple uses of s
  436. }
  437. (tbinarynode(right).left.nodetype<>addn) and
  438. (tbinarynode(right).right.nodetype<>addn) then
  439. begin
  440. { don't do a resulttypepass(right), since then the addnode }
  441. { may insert typeconversions that make this optimization }
  442. { opportunity quite difficult to detect (JM) }
  443. resulttypepass(tbinarynode(right).left);
  444. resulttypepass(tbinarynode(right).right);
  445. if (tbinarynode(right).right.nodetype=stringconstn) or
  446. is_char(tbinarynode(right).right.resulttype.def) or
  447. is_shortstring(tbinarynode(right).right.resulttype.def) or
  448. is_ansistring(tbinarynode(right).right.resulttype.def) then
  449. begin
  450. { remove property flag so it'll not trigger an error }
  451. exclude(left.flags,nf_isproperty);
  452. { generate call to helper }
  453. hp:=ccallparanode.create(tbinarynode(right).right,
  454. ccallparanode.create(left,nil));
  455. if is_char(tbinarynode(right).right.resulttype.def) then
  456. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resulttype.def).stringtypname+'_append_char',hp)
  457. else if is_shortstring(tbinarynode(right).right.resulttype.def) then
  458. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resulttype.def).stringtypname+'_append_shortstring',hp)
  459. else
  460. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resulttype.def).stringtypname+'_append_ansistring',hp);
  461. tbinarynode(right).right:=nil;
  462. left:=nil;
  463. exit;
  464. end;
  465. end;
  466. end
  467. else
  468. if is_shortstring(left.resulttype.def) then
  469. begin
  470. { fold <shortstring>:=<shortstring>+<shortstring>,
  471. <shortstring>+<char> is handled by an optimized node }
  472. if (right.nodetype=addn) and
  473. left.isequal(tbinarynode(right).left) and
  474. { don't fold multiple concatenations else we could get trouble
  475. with multiple uses of s }
  476. (tbinarynode(right).left.nodetype<>addn) and
  477. (tbinarynode(right).right.nodetype<>addn) then
  478. begin
  479. { don't do a resulttypepass(right), since then the addnode }
  480. { may insert typeconversions that make this optimization }
  481. { opportunity quite difficult to detect (JM) }
  482. resulttypepass(tbinarynode(right).left);
  483. resulttypepass(tbinarynode(right).right);
  484. if is_shortstring(tbinarynode(right).right.resulttype.def) then
  485. begin
  486. { remove property flag so it'll not trigger an error }
  487. exclude(left.flags,nf_isproperty);
  488. { generate call to helper }
  489. hp:=ccallparanode.create(tbinarynode(right).right,
  490. ccallparanode.create(left,nil));
  491. if is_shortstring(tbinarynode(right).right.resulttype.def) then
  492. result:=ccallnode.createintern('fpc_shortstr_append_shortstr',hp);
  493. tbinarynode(right).right:=nil;
  494. left:=nil;
  495. exit;
  496. end;
  497. end;
  498. end;
  499. {$endif old_append_str}
  500. resulttypepass(right);
  501. set_varstate(right,vs_read,[vsf_must_be_valid]);
  502. set_varstate(left,vs_written,[]);
  503. if codegenerror then
  504. exit;
  505. { tp procvar support, when we don't expect a procvar
  506. then we need to call the procvar }
  507. if (left.resulttype.def.deftype<>procvardef) then
  508. maybe_call_procvar(right,true);
  509. { assignments to formaldefs and open arrays aren't allowed }
  510. if (left.resulttype.def.deftype=formaldef) or
  511. is_open_array(left.resulttype.def) then
  512. CGMessage(type_e_operator_not_allowed);
  513. { test if node can be assigned, properties are allowed }
  514. valid_for_assignment(left,true);
  515. { assigning nil to a dynamic array clears the array }
  516. if is_dynamic_array(left.resulttype.def) and
  517. (right.nodetype=niln) then
  518. begin
  519. hp:=ccallparanode.create(caddrnode.create_internal
  520. (crttinode.create(tstoreddef(left.resulttype.def),initrtti)),
  521. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),nil));
  522. result := ccallnode.createintern('fpc_dynarray_clear',hp);
  523. left:=nil;
  524. exit;
  525. end;
  526. { shortstring helpers can do the conversion directly,
  527. so treat them separatly }
  528. if (is_shortstring(left.resulttype.def)) then
  529. begin
  530. { insert typeconv, except for chars that are handled in
  531. secondpass and except for ansi/wide string that can
  532. be converted immediatly }
  533. if not(is_char(right.resulttype.def) or
  534. (right.resulttype.def.deftype=stringdef)) then
  535. inserttypeconv(right,left.resulttype);
  536. if right.resulttype.def.deftype=stringdef then
  537. begin
  538. useshelper:=true;
  539. { convert constant strings to shortstrings. But
  540. skip empty constant strings, that will be handled
  541. in secondpass }
  542. if (right.nodetype=stringconstn) then
  543. begin
  544. { verify if range fits within shortstring }
  545. { just emit a warning, delphi gives an }
  546. { error, only if the type definition of }
  547. { of the string is less < 255 characters }
  548. if not is_open_string(left.resulttype.def) and
  549. (tstringconstnode(right).len > tstringdef(left.resulttype.def).len) then
  550. cgmessage(type_w_string_too_long);
  551. inserttypeconv(right,left.resulttype);
  552. if (tstringconstnode(right).len=0) then
  553. useshelper:=false;
  554. end;
  555. { rest is done in pass 1 (JM) }
  556. if useshelper then
  557. exit;
  558. end
  559. end
  560. else
  561. begin
  562. { check if the assignment may cause a range check error }
  563. check_ranges(fileinfo,right,left.resulttype.def);
  564. inserttypeconv(right,left.resulttype);
  565. end;
  566. { call helpers for interface }
  567. if is_interfacecom(left.resulttype.def) then
  568. begin
  569. {
  570. hp:=
  571. ccallparanode.create(
  572. ctypeconvnode.create_internal(right,voidpointertype),
  573. ccallparanode.create(
  574. ctypeconvnode.create_internal(left,voidpointertype),
  575. nil));
  576. result:=ccallnode.createintern('fpc_intf_assign',hp);
  577. }
  578. hp:=
  579. ccallparanode.create(
  580. cguidconstnode.create(tobjectdef(left.resulttype.def).iidguid^),
  581. ccallparanode.create(
  582. ctypeconvnode.create_internal(right,voidpointertype),
  583. ccallparanode.create(
  584. ctypeconvnode.create_internal(left,voidpointertype),
  585. nil)));
  586. result:=ccallnode.createintern('fpc_intf_assign_by_iid',hp);
  587. left:=nil;
  588. right:=nil;
  589. exit;
  590. end;
  591. { call helpers for variant, they can contain non ref. counted types like
  592. vararrays which must be really copied }
  593. if left.resulttype.def.deftype=variantdef then
  594. begin
  595. hp:=ccallparanode.create(ctypeconvnode.create_internal(
  596. caddrnode.create_internal(right),voidpointertype),
  597. ccallparanode.create(ctypeconvnode.create_internal(
  598. caddrnode.create_internal(left),voidpointertype),
  599. nil));
  600. result:=ccallnode.createintern('fpc_variant_copy',hp);
  601. left:=nil;
  602. right:=nil;
  603. exit;
  604. end;
  605. { call helpers for windows widestrings, they aren't ref. counted }
  606. if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resulttype.def) then
  607. begin
  608. hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
  609. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
  610. nil));
  611. result:=ccallnode.createintern('fpc_widestr_assign',hp);
  612. left:=nil;
  613. right:=nil;
  614. exit;
  615. end;
  616. { check if local proc/func is assigned to procvar }
  617. if right.resulttype.def.deftype=procvardef then
  618. test_local_to_procvar(tprocvardef(right.resulttype.def),left.resulttype.def);
  619. end;
  620. function tassignmentnode.pass_1 : tnode;
  621. var
  622. hp: tnode;
  623. oldassignmentnode : tassignmentnode;
  624. begin
  625. result:=nil;
  626. expectloc:=LOC_VOID;
  627. firstpass(left);
  628. { Optimize the reuse of the destination of the assingment in left.
  629. Allow the use of the left inside the tree generated on the right.
  630. This is especially usefull for string routines where the destination
  631. is pushed as a parameter. Using the final destination of left directly
  632. save a temp allocation and copy of data (PFV) }
  633. oldassignmentnode:=aktassignmentnode;
  634. if right.nodetype=addn then
  635. aktassignmentnode:=self
  636. else
  637. aktassignmentnode:=nil;
  638. firstpass(right);
  639. aktassignmentnode:=oldassignmentnode;
  640. if nf_assign_done_in_right in flags then
  641. begin
  642. result:=right;
  643. right:=nil;
  644. exit;
  645. end;
  646. if codegenerror then
  647. exit;
  648. if (cs_opt_level1 in aktoptimizerswitches) and
  649. (right.nodetype = calln) and
  650. (right.resulttype.def=left.resulttype.def) and
  651. { left must be a temp, since otherwise as soon as you modify the }
  652. { result, the current left node is modified and that one may }
  653. { still be an argument to the function or even accessed in the }
  654. { function }
  655. (
  656. (
  657. (left.nodetype = temprefn) and
  658. paramanager.ret_in_param(right.resulttype.def,tcallnode(right).procdefinition.proccalloption)
  659. ) or
  660. { there's special support for ansi/widestrings in the callnode }
  661. is_ansistring(right.resulttype.def) or
  662. is_widestring(right.resulttype.def)
  663. ) then
  664. begin
  665. make_not_regable(left,vr_addr);
  666. tcallnode(right).funcretnode := left;
  667. result := right;
  668. left := nil;
  669. right := nil;
  670. exit;
  671. end;
  672. { assignment to refcounted variable -> inc/decref }
  673. if (not is_class(left.resulttype.def) and
  674. left.resulttype.def.needs_inittable) then
  675. include(current_procinfo.flags,pi_do_call);
  676. if (is_shortstring(left.resulttype.def)) then
  677. begin
  678. if right.resulttype.def.deftype=stringdef then
  679. begin
  680. if (right.nodetype<>stringconstn) or
  681. (tstringconstnode(right).len<>0) then
  682. begin
  683. {$ifdef old_append_str}
  684. if (cs_opt_level1 in aktoptimizerswitches) and
  685. (right.nodetype in [calln,blockn]) and
  686. (left.nodetype = temprefn) and
  687. is_shortstring(right.resulttype.def) and
  688. not is_open_string(left.resulttype.def) and
  689. (tstringdef(left.resulttype.def).len = 255) then
  690. begin
  691. { the blocknode case is handled in pass_2 at the temp }
  692. { reference level (mainly for callparatemp) (JM) }
  693. if (right.nodetype = calln) then
  694. begin
  695. tcallnode(right).funcretnode := left;
  696. result := right;
  697. end
  698. else
  699. exit;
  700. end
  701. else
  702. {$endif old_append_str}
  703. begin
  704. hp:=ccallparanode.create
  705. (right,
  706. ccallparanode.create(cinlinenode.create
  707. (in_high_x,false,left.getcopy),nil));
  708. result:=ccallnode.createinternreturn('fpc_'+tstringdef(right.resulttype.def).stringtypname+'_to_shortstr',hp,left);
  709. firstpass(result);
  710. end;
  711. left:=nil;
  712. right:=nil;
  713. exit;
  714. end;
  715. end;
  716. end;
  717. registersint:=left.registersint+right.registersint;
  718. registersfpu:=max(left.registersfpu,right.registersfpu);
  719. {$ifdef SUPPORT_MMX}
  720. registersmmx:=max(left.registersmmx,right.registersmmx);
  721. {$endif SUPPORT_MMX}
  722. end;
  723. function tassignmentnode.docompare(p: tnode): boolean;
  724. begin
  725. docompare :=
  726. inherited docompare(p) and
  727. (assigntype = tassignmentnode(p).assigntype);
  728. end;
  729. {$ifdef state_tracking}
  730. function Tassignmentnode.track_state_pass(exec_known:boolean):boolean;
  731. var se:Tstate_entry;
  732. begin
  733. track_state_pass:=false;
  734. if exec_known then
  735. begin
  736. track_state_pass:=right.track_state_pass(exec_known);
  737. {Force a new resulttype pass.}
  738. right.resulttype.def:=nil;
  739. do_resulttypepass(right);
  740. resulttypepass(right);
  741. aktstate.store_fact(left.getcopy,right.getcopy);
  742. end
  743. else
  744. aktstate.delete_fact(left);
  745. end;
  746. {$endif}
  747. {*****************************************************************************
  748. TARRAYCONSTRUCTORRANGENODE
  749. *****************************************************************************}
  750. constructor tarrayconstructorrangenode.create(l,r : tnode);
  751. begin
  752. inherited create(arrayconstructorrangen,l,r);
  753. end;
  754. function tarrayconstructorrangenode.det_resulttype:tnode;
  755. begin
  756. result:=nil;
  757. resulttypepass(left);
  758. resulttypepass(right);
  759. set_varstate(left,vs_read,[vsf_must_be_valid]);
  760. set_varstate(right,vs_read,[vsf_must_be_valid]);
  761. if codegenerror then
  762. exit;
  763. resulttype:=left.resulttype;
  764. end;
  765. function tarrayconstructorrangenode.pass_1 : tnode;
  766. begin
  767. firstpass(left);
  768. firstpass(right);
  769. expectloc:=LOC_CREFERENCE;
  770. calcregisters(self,0,0,0);
  771. result:=nil;
  772. end;
  773. {****************************************************************************
  774. TARRAYCONSTRUCTORNODE
  775. *****************************************************************************}
  776. constructor tarrayconstructornode.create(l,r : tnode);
  777. begin
  778. inherited create(arrayconstructorn,l,r);
  779. end;
  780. function tarrayconstructornode._getcopy : tnode;
  781. var
  782. n : tarrayconstructornode;
  783. begin
  784. n:=tarrayconstructornode(inherited _getcopy);
  785. result:=n;
  786. end;
  787. function tarrayconstructornode.det_resulttype:tnode;
  788. var
  789. htype : ttype;
  790. hp : tarrayconstructornode;
  791. len : longint;
  792. varia : boolean;
  793. begin
  794. result:=nil;
  795. { are we allowing array constructor? Then convert it to a set.
  796. Do this only if we didn't convert the arrayconstructor yet. This
  797. is needed for the cases where the resulttype is forced for a second
  798. run }
  799. if (not allow_array_constructor) then
  800. begin
  801. hp:=tarrayconstructornode(getcopy);
  802. arrayconstructor_to_set(tnode(hp));
  803. result:=hp;
  804. exit;
  805. end;
  806. { only pass left tree, right tree contains next construct if any }
  807. htype.reset;
  808. len:=0;
  809. varia:=false;
  810. if assigned(left) then
  811. begin
  812. hp:=self;
  813. while assigned(hp) do
  814. begin
  815. resulttypepass(hp.left);
  816. set_varstate(hp.left,vs_read,[vsf_must_be_valid]);
  817. if (htype.def=nil) then
  818. htype:=hp.left.resulttype
  819. else
  820. begin
  821. if (not varia) and (not equal_defs(htype.def,hp.left.resulttype.def)) then
  822. begin
  823. { If both are integers we need to take the type that can hold both
  824. defs }
  825. if is_integer(htype.def) and is_integer(hp.left.resulttype.def) then
  826. begin
  827. if is_in_limit(htype.def,hp.left.resulttype.def) then
  828. htype:=hp.left.resulttype;
  829. end
  830. else
  831. if (nf_novariaallowed in flags) then
  832. varia:=true;
  833. end;
  834. end;
  835. inc(len);
  836. hp:=tarrayconstructornode(hp.right);
  837. end;
  838. end;
  839. { Set the type of empty or varia arrays to void. Also
  840. do this if the type is array of const/open array
  841. because those can't be used with setelementtype }
  842. if not assigned(htype.def) or
  843. varia or
  844. is_array_of_const(htype.def) or
  845. is_open_array(htype.def) then
  846. htype:=voidtype;
  847. resulttype.setdef(tarraydef.create(0,len-1,s32inttype));
  848. tarraydef(resulttype.def).setelementtype(htype);
  849. include(tarraydef(resulttype.def).arrayoptions,ado_IsConstructor);
  850. if varia then
  851. include(tarraydef(resulttype.def).arrayoptions,ado_IsVariant);
  852. end;
  853. procedure tarrayconstructornode.force_type(tt:ttype);
  854. var
  855. hp : tarrayconstructornode;
  856. begin
  857. tarraydef(resulttype.def).setelementtype(tt);
  858. include(tarraydef(resulttype.def).arrayoptions,ado_IsConstructor);
  859. exclude(tarraydef(resulttype.def).arrayoptions,ado_IsVariant);
  860. if assigned(left) then
  861. begin
  862. hp:=self;
  863. while assigned(hp) do
  864. begin
  865. inserttypeconv(hp.left,tt);
  866. hp:=tarrayconstructornode(hp.right);
  867. end;
  868. end;
  869. end;
  870. procedure tarrayconstructornode.insert_typeconvs;
  871. var
  872. hp : tarrayconstructornode;
  873. dovariant : boolean;
  874. begin
  875. dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resulttype.def).arrayoptions);
  876. { only pass left tree, right tree contains next construct if any }
  877. if assigned(left) then
  878. begin
  879. hp:=self;
  880. while assigned(hp) do
  881. begin
  882. resulttypepass(hp.left);
  883. { Insert typeconvs for array of const }
  884. if dovariant then
  885. { at this time C varargs are no longer an arrayconstructornode }
  886. insert_varargstypeconv(hp.left,false);
  887. hp:=tarrayconstructornode(hp.right);
  888. end;
  889. end;
  890. end;
  891. function tarrayconstructornode.pass_1 : tnode;
  892. var
  893. hp : tarrayconstructornode;
  894. do_variant:boolean;
  895. begin
  896. do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resulttype.def).arrayoptions);
  897. result:=nil;
  898. { Insert required type convs, this must be
  899. done in pass 1, because the call must be
  900. resulttypepassed already }
  901. if assigned(left) then
  902. begin
  903. insert_typeconvs;
  904. { call firstpass for all nodes }
  905. hp:=self;
  906. while assigned(hp) do
  907. begin
  908. if hp.left<>nil then
  909. begin
  910. {This check is pessimistic; a call will happen depending
  911. on the location in which the elements will be found in
  912. pass 2.}
  913. if not do_variant then
  914. include(current_procinfo.flags,pi_do_call);
  915. firstpass(hp.left);
  916. end;
  917. hp:=tarrayconstructornode(hp.right);
  918. end;
  919. end;
  920. expectloc:=LOC_CREFERENCE;
  921. calcregisters(self,0,0,0);
  922. end;
  923. function tarrayconstructornode.docompare(p: tnode): boolean;
  924. begin
  925. docompare:=inherited docompare(p);
  926. end;
  927. {*****************************************************************************
  928. TTYPENODE
  929. *****************************************************************************}
  930. constructor ttypenode.create(t : ttype);
  931. begin
  932. inherited create(typen);
  933. restype:=t;
  934. allowed:=false;
  935. end;
  936. constructor ttypenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  937. begin
  938. inherited ppuload(t,ppufile);
  939. ppufile.gettype(restype);
  940. allowed:=boolean(ppufile.getbyte);
  941. end;
  942. procedure ttypenode.ppuwrite(ppufile:tcompilerppufile);
  943. begin
  944. inherited ppuwrite(ppufile);
  945. ppufile.puttype(restype);
  946. ppufile.putbyte(byte(allowed));
  947. end;
  948. procedure ttypenode.buildderefimpl;
  949. begin
  950. inherited buildderefimpl;
  951. restype.buildderef;
  952. end;
  953. procedure ttypenode.derefimpl;
  954. begin
  955. inherited derefimpl;
  956. restype.resolve;
  957. end;
  958. function ttypenode.det_resulttype:tnode;
  959. begin
  960. result:=nil;
  961. resulttype:=restype;
  962. { check if it's valid }
  963. if restype.def.deftype = errordef then
  964. CGMessage(parser_e_illegal_expression);
  965. end;
  966. function ttypenode.pass_1 : tnode;
  967. begin
  968. result:=nil;
  969. expectloc:=LOC_VOID;
  970. { a typenode can't generate code, so we give here
  971. an error. Else it'll be an abstract error in pass_2.
  972. Only when the allowed flag is set we don't generate
  973. an error }
  974. if not allowed then
  975. Message(parser_e_no_type_not_allowed_here);
  976. end;
  977. function ttypenode.docompare(p: tnode): boolean;
  978. begin
  979. docompare :=
  980. inherited docompare(p);
  981. end;
  982. {*****************************************************************************
  983. TRTTINODE
  984. *****************************************************************************}
  985. constructor trttinode.create(def:tstoreddef;rt:trttitype);
  986. begin
  987. inherited create(rttin);
  988. rttidef:=def;
  989. rttitype:=rt;
  990. end;
  991. constructor trttinode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  992. begin
  993. inherited ppuload(t,ppufile);
  994. ppufile.getderef(rttidefderef);
  995. rttitype:=trttitype(ppufile.getbyte);
  996. end;
  997. procedure trttinode.ppuwrite(ppufile:tcompilerppufile);
  998. begin
  999. inherited ppuwrite(ppufile);
  1000. ppufile.putderef(rttidefderef);
  1001. ppufile.putbyte(byte(rttitype));
  1002. end;
  1003. procedure trttinode.buildderefimpl;
  1004. begin
  1005. inherited buildderefimpl;
  1006. rttidefderef.build(rttidef);
  1007. end;
  1008. procedure trttinode.derefimpl;
  1009. begin
  1010. inherited derefimpl;
  1011. rttidef:=tstoreddef(rttidefderef.resolve);
  1012. end;
  1013. function trttinode._getcopy : tnode;
  1014. var
  1015. n : trttinode;
  1016. begin
  1017. n:=trttinode(inherited _getcopy);
  1018. n.rttidef:=rttidef;
  1019. n.rttitype:=rttitype;
  1020. result:=n;
  1021. end;
  1022. function trttinode.det_resulttype:tnode;
  1023. begin
  1024. { rtti information will be returned as a void pointer }
  1025. result:=nil;
  1026. resulttype:=voidpointertype;
  1027. end;
  1028. function trttinode.pass_1 : tnode;
  1029. begin
  1030. result:=nil;
  1031. expectloc:=LOC_CREFERENCE;
  1032. end;
  1033. function trttinode.docompare(p: tnode): boolean;
  1034. begin
  1035. docompare :=
  1036. inherited docompare(p) and
  1037. (rttidef = trttinode(p).rttidef) and
  1038. (rttitype = trttinode(p).rttitype);
  1039. end;
  1040. begin
  1041. cloadnode:=tloadnode;
  1042. cassignmentnode:=tassignmentnode;
  1043. carrayconstructorrangenode:=tarrayconstructorrangenode;
  1044. carrayconstructornode:=tarrayconstructornode;
  1045. ctypenode:=ttypenode;
  1046. crttinode:=trttinode;
  1047. end.