nld.pas 42 KB

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