nmem.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211
  1. {
  2. $Id$
  3. Copyright (c) 2000-2002 by Florian Klaempfl
  4. Type checking and register allocation for memory related 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 nmem;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. node,
  23. symtype,symppu,symdef,symsym,symtable,
  24. cpubase;
  25. type
  26. tloadvmtnode = class(tunarynode)
  27. constructor create(l : tnode);virtual;
  28. function pass_1 : tnode;override;
  29. function det_resulttype:tnode;override;
  30. end;
  31. tloadvmtnodeclass = class of tloadvmtnode;
  32. thnewnode = class(tnode)
  33. objtype : ttype;
  34. constructor create(t:ttype);virtual;
  35. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  36. procedure ppuwrite(ppufile:tcompilerppufile);override;
  37. procedure derefimpl;override;
  38. function pass_1 : tnode;override;
  39. function det_resulttype:tnode;override;
  40. end;
  41. thnewnodeclass = class of thnewnode;
  42. thdisposenode = class(tunarynode)
  43. constructor create(l : tnode);virtual;
  44. function pass_1 : tnode;override;
  45. function det_resulttype:tnode;override;
  46. end;
  47. thdisposenodeclass = class of thdisposenode;
  48. taddrnode = class(tunarynode)
  49. getprocvardef : tprocvardef;
  50. constructor create(l : tnode);virtual;
  51. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  52. procedure ppuwrite(ppufile:tcompilerppufile);override;
  53. procedure mark_write;override;
  54. procedure derefimpl;override;
  55. function getcopy : tnode;override;
  56. function pass_1 : tnode;override;
  57. function det_resulttype:tnode;override;
  58. end;
  59. taddrnodeclass = class of taddrnode;
  60. tdoubleaddrnode = class(tunarynode)
  61. constructor create(l : tnode);virtual;
  62. function pass_1 : tnode;override;
  63. function det_resulttype:tnode;override;
  64. end;
  65. tdoubleaddrnodeclass = class of tdoubleaddrnode;
  66. tderefnode = class(tunarynode)
  67. constructor create(l : tnode);virtual;
  68. function pass_1 : tnode;override;
  69. function det_resulttype:tnode;override;
  70. procedure mark_write;override;
  71. end;
  72. tderefnodeclass = class of tderefnode;
  73. tsubscriptnode = class(tunarynode)
  74. vs : tvarsym;
  75. constructor create(varsym : tsym;l : tnode);virtual;
  76. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  77. procedure ppuwrite(ppufile:tcompilerppufile);override;
  78. procedure derefimpl;override;
  79. function getcopy : tnode;override;
  80. function pass_1 : tnode;override;
  81. function docompare(p: tnode): boolean; override;
  82. function det_resulttype:tnode;override;
  83. procedure mark_write;override;
  84. end;
  85. tsubscriptnodeclass = class of tsubscriptnode;
  86. tvecnode = class(tbinarynode)
  87. constructor create(l,r : tnode);virtual;
  88. function pass_1 : tnode;override;
  89. function det_resulttype:tnode;override;
  90. procedure mark_write;override;
  91. end;
  92. tvecnodeclass = class of tvecnode;
  93. tselfnode = class(tnode)
  94. classdef : tdef; { objectdef or classrefdef }
  95. constructor create(_class : tdef);virtual;
  96. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  97. procedure ppuwrite(ppufile:tcompilerppufile);override;
  98. procedure derefimpl;override;
  99. function pass_1 : tnode;override;
  100. function det_resulttype:tnode;override;
  101. end;
  102. tselfnodeclass = class of tselfnode;
  103. twithnode = class(tbinarynode)
  104. withsymtable : twithsymtable;
  105. tablecount : longint;
  106. withreference : treference;
  107. constructor create(symtable : twithsymtable;l,r : tnode;count : longint);virtual;
  108. destructor destroy;override;
  109. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  110. procedure ppuwrite(ppufile:tcompilerppufile);override;
  111. function getcopy : tnode;override;
  112. function pass_1 : tnode;override;
  113. function docompare(p: tnode): boolean; override;
  114. function det_resulttype:tnode;override;
  115. end;
  116. twithnodeclass = class of twithnode;
  117. var
  118. cloadvmtnode : tloadvmtnodeclass;
  119. chnewnode : thnewnodeclass;
  120. chdisposenode : thdisposenodeclass;
  121. caddrnode : taddrnodeclass;
  122. cdoubleaddrnode : tdoubleaddrnodeclass;
  123. cderefnode : tderefnodeclass;
  124. csubscriptnode : tsubscriptnodeclass;
  125. cvecnode : tvecnodeclass;
  126. cselfnode : tselfnodeclass;
  127. cwithnode : twithnodeclass;
  128. implementation
  129. uses
  130. globtype,systems,
  131. cutils,verbose,globals,
  132. symconst,symbase,defutil,defcmp,
  133. nbas,
  134. htypechk,pass_1,ncal,nld,ncon,ncnv,cginfo,cgbase
  135. ;
  136. {*****************************************************************************
  137. TLOADVMTNODE
  138. *****************************************************************************}
  139. constructor tloadvmtnode.create(l : tnode);
  140. begin
  141. inherited create(loadvmtn,l);
  142. end;
  143. function tloadvmtnode.det_resulttype:tnode;
  144. begin
  145. result:=nil;
  146. resulttypepass(left);
  147. if codegenerror then
  148. exit;
  149. resulttype.setdef(tclassrefdef.create(left.resulttype));
  150. end;
  151. function tloadvmtnode.pass_1 : tnode;
  152. begin
  153. result:=nil;
  154. registers32:=1;
  155. expectloc:=LOC_REGISTER;
  156. end;
  157. {*****************************************************************************
  158. THNEWNODE
  159. *****************************************************************************}
  160. constructor thnewnode.create(t:ttype);
  161. begin
  162. inherited create(hnewn);
  163. objtype:=t;
  164. end;
  165. constructor thnewnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  166. begin
  167. inherited ppuload(t,ppufile);
  168. ppufile.gettype(objtype);
  169. end;
  170. procedure thnewnode.ppuwrite(ppufile:tcompilerppufile);
  171. begin
  172. inherited ppuwrite(ppufile);
  173. ppufile.puttype(objtype);
  174. end;
  175. procedure thnewnode.derefimpl;
  176. begin
  177. inherited derefimpl;
  178. objtype.resolve;
  179. end;
  180. function thnewnode.det_resulttype:tnode;
  181. begin
  182. result:=nil;
  183. if objtype.def.deftype<>objectdef then
  184. Message(parser_e_pointer_to_class_expected);
  185. resulttype:=objtype;
  186. end;
  187. function thnewnode.pass_1 : tnode;
  188. begin
  189. result:=nil;
  190. expectloc:=LOC_VOID;
  191. end;
  192. {*****************************************************************************
  193. THDISPOSENODE
  194. *****************************************************************************}
  195. constructor thdisposenode.create(l : tnode);
  196. begin
  197. inherited create(hdisposen,l);
  198. end;
  199. function thdisposenode.det_resulttype:tnode;
  200. begin
  201. result:=nil;
  202. resulttypepass(left);
  203. if codegenerror then
  204. exit;
  205. if (left.resulttype.def.deftype<>pointerdef) then
  206. CGMessage1(type_e_pointer_type_expected,left.resulttype.def.typename);
  207. resulttype:=tpointerdef(left.resulttype.def).pointertype;
  208. end;
  209. function thdisposenode.pass_1 : tnode;
  210. begin
  211. result:=nil;
  212. firstpass(left);
  213. if codegenerror then
  214. exit;
  215. registers32:=left.registers32;
  216. registersfpu:=left.registersfpu;
  217. {$ifdef SUPPORT_MMX}
  218. registersmmx:=left.registersmmx;
  219. {$endif SUPPORT_MMX}
  220. if registers32<1 then
  221. registers32:=1;
  222. if left.expectloc=LOC_CREGISTER then
  223. inc(registers32);
  224. expectloc:=LOC_REFERENCE;
  225. end;
  226. {*****************************************************************************
  227. TADDRNODE
  228. *****************************************************************************}
  229. constructor taddrnode.create(l : tnode);
  230. begin
  231. inherited create(addrn,l);
  232. getprocvardef:=nil;
  233. end;
  234. constructor taddrnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  235. begin
  236. inherited ppuload(t,ppufile);
  237. getprocvardef:=tprocvardef(ppufile.getderef);
  238. end;
  239. procedure taddrnode.ppuwrite(ppufile:tcompilerppufile);
  240. begin
  241. inherited ppuwrite(ppufile);
  242. ppufile.putderef(getprocvardef);
  243. end;
  244. procedure Taddrnode.mark_write;
  245. begin
  246. {@procvar:=nil is legal in Delphi mode.}
  247. left.mark_write;
  248. end;
  249. procedure taddrnode.derefimpl;
  250. begin
  251. inherited derefimpl;
  252. resolvedef(pointer(getprocvardef));
  253. end;
  254. function taddrnode.getcopy : tnode;
  255. var
  256. p : taddrnode;
  257. begin
  258. p:=taddrnode(inherited getcopy);
  259. p.getprocvardef:=getprocvardef;
  260. getcopy:=p;
  261. end;
  262. function taddrnode.det_resulttype:tnode;
  263. var
  264. hp : tnode;
  265. hp2 : TParaItem;
  266. hp3 : tabstractprocdef;
  267. begin
  268. result:=nil;
  269. resulttypepass(left);
  270. if codegenerror then
  271. exit;
  272. { don't allow constants }
  273. if is_constnode(left) then
  274. begin
  275. aktfilepos:=left.fileinfo;
  276. CGMessage(type_e_no_addr_of_constant);
  277. exit;
  278. end;
  279. { tp @procvar support (type of @procvar is a void pointer)
  280. Note: we need to leave the addrn in the tree,
  281. else we can't see the difference between @procvar and procvar.
  282. we set the procvarload flag so a secondpass does nothing for
  283. this node (PFV) }
  284. if (m_tp_procvar in aktmodeswitches) then
  285. begin
  286. case left.nodetype of
  287. calln :
  288. begin
  289. { a load of a procvar can't have parameters }
  290. if assigned(tcallnode(left).left) then
  291. CGMessage(cg_e_illegal_expression);
  292. { is it a procvar? }
  293. hp:=tcallnode(left).right;
  294. if assigned(hp) then
  295. begin
  296. { remove calln node }
  297. tcallnode(left).right:=nil;
  298. left.free;
  299. left:=hp;
  300. include(flags,nf_procvarload);
  301. end;
  302. end;
  303. loadn,
  304. subscriptn,
  305. typeconvn,
  306. vecn,
  307. derefn :
  308. begin
  309. if left.resulttype.def.deftype=procvardef then
  310. include(flags,nf_procvarload);
  311. end;
  312. end;
  313. if nf_procvarload in flags then
  314. begin
  315. resulttype:=voidpointertype;
  316. exit;
  317. end;
  318. end;
  319. { proc 2 procvar ? }
  320. if left.nodetype=calln then
  321. { if it were a valid construct, the addr node would already have }
  322. { been removed in the parser. This happens for (in FPC mode) }
  323. { procvar1 := @procvar2(parameters); }
  324. CGMessage(cg_e_illegal_expression)
  325. else
  326. if (left.nodetype=loadn) and (tloadnode(left).symtableentry.typ=procsym) then
  327. begin
  328. { the address is already available when loading a procedure of object }
  329. if assigned(tloadnode(left).left) then
  330. include(flags,nf_procvarload);
  331. { result is a procedure variable }
  332. { No, to be TP compatible, you must return a voidpointer to
  333. the procedure that is stored in the procvar.}
  334. if not(m_tp_procvar in aktmodeswitches) then
  335. begin
  336. if assigned(getprocvardef) then
  337. begin
  338. hp3:=tprocsym(tloadnode(left).symtableentry).search_procdef_byprocvardef(getprocvardef);
  339. if not assigned(hp3) then
  340. begin
  341. CGMessage2(type_e_incompatible_types,tprocsym(tloadnode(left).symtableentry).first_procdef.typename,getprocvardef.typename);
  342. exit;
  343. end;
  344. end
  345. else
  346. hp3:=tabstractprocdef(tprocsym(tloadnode(left).symtableentry).first_procdef);
  347. { create procvardef }
  348. resulttype.setdef(tprocvardef.create(hp3.parast.symtablelevel));
  349. tprocvardef(resulttype.def).proctypeoption:=hp3.proctypeoption;
  350. tprocvardef(resulttype.def).proccalloption:=hp3.proccalloption;
  351. tprocvardef(resulttype.def).procoptions:=hp3.procoptions;
  352. tprocvardef(resulttype.def).rettype:=hp3.rettype;
  353. { method ? then set the methodpointer flag }
  354. if (hp3.owner.symtabletype=objectsymtable) then
  355. include(tprocvardef(resulttype.def).procoptions,po_methodpointer);
  356. { only need the address of the method? this is needed
  357. for @tobject.create }
  358. if not assigned(tloadnode(left).left) then
  359. include(tprocvardef(resulttype.def).procoptions,po_addressonly);
  360. { Add parameters in left to right order }
  361. hp2:=TParaItem(hp3.Para.first);
  362. while assigned(hp2) do
  363. begin
  364. tprocvardef(resulttype.def).concatpara(nil,hp2.paratype,hp2.parasym,
  365. hp2.defaultvalue,hp2.is_hidden);
  366. hp2:=TParaItem(hp2.next);
  367. end;
  368. end
  369. else
  370. resulttype:=voidpointertype;
  371. end
  372. else
  373. begin
  374. { what are we getting the address from an absolute sym? }
  375. hp:=left;
  376. while assigned(hp) and (hp.nodetype in [vecn,derefn,subscriptn]) do
  377. hp:=tunarynode(hp).left;
  378. if assigned(hp) and (hp.nodetype=loadn) and
  379. ((tloadnode(hp).symtableentry.typ=absolutesym) and
  380. tabsolutesym(tloadnode(hp).symtableentry).absseg) then
  381. begin
  382. if not(cs_typed_addresses in aktlocalswitches) then
  383. resulttype:=voidfarpointertype
  384. else
  385. resulttype.setdef(tpointerdef.createfar(left.resulttype));
  386. end
  387. else
  388. begin
  389. if not(cs_typed_addresses in aktlocalswitches) then
  390. resulttype:=voidpointertype
  391. else
  392. resulttype.setdef(tpointerdef.create(left.resulttype));
  393. end;
  394. end;
  395. { this is like the function addr }
  396. inc(parsing_para_level);
  397. set_varstate(left,false);
  398. dec(parsing_para_level);
  399. end;
  400. function taddrnode.pass_1 : tnode;
  401. begin
  402. result:=nil;
  403. firstpass(left);
  404. if codegenerror then
  405. exit;
  406. make_not_regable(left);
  407. if nf_procvarload in flags then
  408. begin
  409. registers32:=left.registers32;
  410. registersfpu:=left.registersfpu;
  411. {$ifdef SUPPORT_MMX}
  412. registersmmx:=left.registersmmx;
  413. {$endif SUPPORT_MMX}
  414. if registers32<1 then
  415. registers32:=1;
  416. expectloc:=left.expectloc;
  417. exit;
  418. end;
  419. { we should allow loc_mem for @string }
  420. if not(left.expectloc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  421. begin
  422. aktfilepos:=left.fileinfo;
  423. CGMessage(cg_e_illegal_expression);
  424. end;
  425. registers32:=left.registers32;
  426. registersfpu:=left.registersfpu;
  427. {$ifdef SUPPORT_MMX}
  428. registersmmx:=left.registersmmx;
  429. {$endif SUPPORT_MMX}
  430. if registers32<1 then
  431. registers32:=1;
  432. { is this right for object of methods ?? }
  433. expectloc:=LOC_REGISTER;
  434. end;
  435. {*****************************************************************************
  436. TDOUBLEADDRNODE
  437. *****************************************************************************}
  438. constructor tdoubleaddrnode.create(l : tnode);
  439. begin
  440. inherited create(doubleaddrn,l);
  441. end;
  442. function tdoubleaddrnode.det_resulttype:tnode;
  443. begin
  444. result:=nil;
  445. resulttypepass(left);
  446. if codegenerror then
  447. exit;
  448. inc(parsing_para_level);
  449. set_varstate(left,false);
  450. dec(parsing_para_level);
  451. if (left.resulttype.def.deftype)<>procvardef then
  452. CGMessage(cg_e_illegal_expression);
  453. resulttype:=voidpointertype;
  454. end;
  455. function tdoubleaddrnode.pass_1 : tnode;
  456. begin
  457. result:=nil;
  458. make_not_regable(left);
  459. firstpass(left);
  460. if codegenerror then
  461. exit;
  462. if (left.expectloc<>LOC_REFERENCE) then
  463. CGMessage(cg_e_illegal_expression);
  464. registers32:=left.registers32;
  465. registersfpu:=left.registersfpu;
  466. {$ifdef SUPPORT_MMX}
  467. registersmmx:=left.registersmmx;
  468. {$endif SUPPORT_MMX}
  469. if registers32<1 then
  470. registers32:=1;
  471. expectloc:=LOC_REGISTER;
  472. end;
  473. {*****************************************************************************
  474. TDEREFNODE
  475. *****************************************************************************}
  476. constructor tderefnode.create(l : tnode);
  477. begin
  478. inherited create(derefn,l);
  479. end;
  480. function tderefnode.det_resulttype:tnode;
  481. begin
  482. result:=nil;
  483. resulttypepass(left);
  484. set_varstate(left,true);
  485. if codegenerror then
  486. exit;
  487. if left.resulttype.def.deftype=pointerdef then
  488. resulttype:=tpointerdef(left.resulttype.def).pointertype
  489. else
  490. CGMessage(cg_e_invalid_qualifier);
  491. end;
  492. procedure Tderefnode.mark_write;
  493. begin
  494. include(flags,nf_write);
  495. end;
  496. function tderefnode.pass_1 : tnode;
  497. begin
  498. result:=nil;
  499. firstpass(left);
  500. if codegenerror then
  501. exit;
  502. registers32:=max(left.registers32,1);
  503. registersfpu:=left.registersfpu;
  504. {$ifdef SUPPORT_MMX}
  505. registersmmx:=left.registersmmx;
  506. {$endif SUPPORT_MMX}
  507. expectloc:=LOC_REFERENCE;
  508. end;
  509. {*****************************************************************************
  510. TSUBSCRIPTNODE
  511. *****************************************************************************}
  512. constructor tsubscriptnode.create(varsym : tsym;l : tnode);
  513. begin
  514. inherited create(subscriptn,l);
  515. { vs should be changed to tsym! }
  516. vs:=tvarsym(varsym);
  517. end;
  518. constructor tsubscriptnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  519. begin
  520. inherited ppuload(t,ppufile);
  521. vs:=tvarsym(ppufile.getderef);
  522. end;
  523. procedure tsubscriptnode.ppuwrite(ppufile:tcompilerppufile);
  524. begin
  525. inherited ppuwrite(ppufile);
  526. ppufile.putderef(vs);
  527. end;
  528. procedure tsubscriptnode.derefimpl;
  529. begin
  530. inherited derefimpl;
  531. resolvesym(pointer(vs));
  532. end;
  533. function tsubscriptnode.getcopy : tnode;
  534. var
  535. p : tsubscriptnode;
  536. begin
  537. p:=tsubscriptnode(inherited getcopy);
  538. p.vs:=vs;
  539. getcopy:=p;
  540. end;
  541. function tsubscriptnode.det_resulttype:tnode;
  542. begin
  543. result:=nil;
  544. resulttypepass(left);
  545. resulttype:=vs.vartype;
  546. end;
  547. procedure Tsubscriptnode.mark_write;
  548. begin
  549. include(flags,nf_write);
  550. end;
  551. function tsubscriptnode.pass_1 : tnode;
  552. begin
  553. result:=nil;
  554. firstpass(left);
  555. if codegenerror then
  556. exit;
  557. registers32:=left.registers32;
  558. registersfpu:=left.registersfpu;
  559. {$ifdef SUPPORT_MMX}
  560. registersmmx:=left.registersmmx;
  561. {$endif SUPPORT_MMX}
  562. { classes must be dereferenced implicit }
  563. if is_class_or_interface(left.resulttype.def) then
  564. begin
  565. if registers32=0 then
  566. registers32:=1;
  567. expectloc:=LOC_REFERENCE;
  568. end
  569. else
  570. begin
  571. if (left.expectloc<>LOC_CREFERENCE) and
  572. (left.expectloc<>LOC_REFERENCE) then
  573. CGMessage(cg_e_illegal_expression);
  574. expectloc:=left.expectloc;
  575. end;
  576. end;
  577. function tsubscriptnode.docompare(p: tnode): boolean;
  578. begin
  579. docompare :=
  580. inherited docompare(p) and
  581. (vs = tsubscriptnode(p).vs);
  582. end;
  583. {*****************************************************************************
  584. TVECNODE
  585. *****************************************************************************}
  586. constructor tvecnode.create(l,r : tnode);
  587. begin
  588. inherited create(vecn,l,r);
  589. end;
  590. function tvecnode.det_resulttype:tnode;
  591. var
  592. htype : ttype;
  593. begin
  594. result:=nil;
  595. resulttypepass(left);
  596. resulttypepass(right);
  597. if codegenerror then
  598. exit;
  599. { maybe type conversion for the index value, but
  600. do not convert enums,booleans,char }
  601. if (right.resulttype.def.deftype<>enumdef) and
  602. not(is_char(right.resulttype.def)) and
  603. not(is_boolean(right.resulttype.def)) then
  604. begin
  605. inserttypeconv(right,s32bittype);
  606. end;
  607. case left.resulttype.def.deftype of
  608. arraydef :
  609. begin
  610. { check type of the index value }
  611. if (compare_defs(right.resulttype.def,tarraydef(left.resulttype.def).rangetype.def,right.nodetype)=te_incompatible) then
  612. CGMessage(type_e_mismatch);
  613. resulttype:=tarraydef(left.resulttype.def).elementtype;
  614. end;
  615. pointerdef :
  616. begin
  617. { are we accessing a pointer[], then convert the pointer to
  618. an array first, in FPC this is allowed for all pointers in
  619. delphi/tp7 it's only allowed for pchars }
  620. if (m_fpc in aktmodeswitches) or
  621. is_pchar(left.resulttype.def) or
  622. is_pwidechar(left.resulttype.def) then
  623. begin
  624. { convert pointer to array }
  625. htype.setdef(tarraydef.create(0,$7fffffff,s32bittype));
  626. tarraydef(htype.def).setelementtype(tpointerdef(left.resulttype.def).pointertype);
  627. inserttypeconv(left,htype);
  628. resulttype:=tarraydef(htype.def).elementtype;
  629. end
  630. else
  631. CGMessage(type_e_array_required);
  632. end;
  633. stringdef :
  634. begin
  635. { indexed access to 0 element is only allowed for shortstrings }
  636. if (right.nodetype=ordconstn) and
  637. (tordconstnode(right).value=0) and
  638. not(is_shortstring(left.resulttype.def)) then
  639. CGMessage(cg_e_can_access_element_zero);
  640. case tstringdef(left.resulttype.def).string_typ of
  641. st_widestring :
  642. resulttype:=cwidechartype;
  643. st_ansistring :
  644. resulttype:=cchartype;
  645. st_longstring :
  646. resulttype:=cchartype;
  647. st_shortstring :
  648. resulttype:=cchartype;
  649. end;
  650. end
  651. else
  652. CGMessage(type_e_array_required);
  653. end;
  654. end;
  655. procedure Tvecnode.mark_write;
  656. begin
  657. include(flags,nf_write);
  658. end;
  659. function tvecnode.pass_1 : tnode;
  660. {$ifdef consteval}
  661. var
  662. tcsym : ttypedconstsym;
  663. {$endif}
  664. begin
  665. result:=nil;
  666. firstpass(left);
  667. firstpass(right);
  668. if codegenerror then
  669. exit;
  670. { the register calculation is easy if a const index is used }
  671. if right.nodetype=ordconstn then
  672. begin
  673. {$ifdef consteval}
  674. { constant evaluation }
  675. if (left.nodetype=loadn) and
  676. (left.symtableentry.typ=typedconstsym) then
  677. begin
  678. tcsym:=ttypedconstsym(left.symtableentry);
  679. if tcsym.defintion^.typ=stringdef then
  680. begin
  681. end;
  682. end;
  683. {$endif}
  684. registers32:=left.registers32;
  685. { for ansi/wide strings, we need at least one register }
  686. if is_ansistring(left.resulttype.def) or
  687. is_widestring(left.resulttype.def) or
  688. { ... as well as for dynamic arrays }
  689. is_dynamic_array(left.resulttype.def) then
  690. registers32:=max(registers32,1);
  691. end
  692. else
  693. begin
  694. { this rules are suboptimal, but they should give }
  695. { good results }
  696. registers32:=max(left.registers32,right.registers32);
  697. { for ansi/wide strings, we need at least one register }
  698. if is_ansistring(left.resulttype.def) or
  699. is_widestring(left.resulttype.def) or
  700. { ... as well as for dynamic arrays }
  701. is_dynamic_array(left.resulttype.def) then
  702. registers32:=max(registers32,1);
  703. { need we an extra register when doing the restore ? }
  704. if (left.registers32<=right.registers32) and
  705. { only if the node needs less than 3 registers }
  706. { two for the right node and one for the }
  707. { left address }
  708. (registers32<3) then
  709. inc(registers32);
  710. { need we an extra register for the index ? }
  711. if (right.expectloc<>LOC_REGISTER)
  712. { only if the right node doesn't need a register }
  713. and (right.registers32<1) then
  714. inc(registers32);
  715. { not correct, but what works better ?
  716. if left.registers32>0 then
  717. registers32:=max(registers32,2)
  718. else
  719. min. one register
  720. registers32:=max(registers32,1);
  721. }
  722. end;
  723. registersfpu:=max(left.registersfpu,right.registersfpu);
  724. {$ifdef SUPPORT_MMX}
  725. registersmmx:=max(left.registersmmx,right.registersmmx);
  726. {$endif SUPPORT_MMX}
  727. if left.expectloc=LOC_CREFERENCE then
  728. expectloc:=LOC_CREFERENCE
  729. else
  730. expectloc:=LOC_REFERENCE;
  731. end;
  732. {*****************************************************************************
  733. TSELFNODE
  734. *****************************************************************************}
  735. constructor tselfnode.create(_class : tdef);
  736. begin
  737. inherited create(selfn);
  738. classdef:=_class;
  739. end;
  740. constructor tselfnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  741. begin
  742. inherited ppuload(t,ppufile);
  743. classdef:=tdef(ppufile.getderef);
  744. end;
  745. procedure tselfnode.ppuwrite(ppufile:tcompilerppufile);
  746. begin
  747. inherited ppuwrite(ppufile);
  748. ppufile.putderef(classdef);
  749. end;
  750. procedure tselfnode.derefimpl;
  751. begin
  752. inherited derefimpl;
  753. resolvedef(pointer(classdef));
  754. end;
  755. function tselfnode.det_resulttype:tnode;
  756. begin
  757. result:=nil;
  758. resulttype.setdef(classdef);
  759. end;
  760. function tselfnode.pass_1 : tnode;
  761. begin
  762. result:=nil;
  763. if (resulttype.def.deftype=classrefdef) or
  764. is_class(resulttype.def) or
  765. (po_staticmethod in current_procdef.procoptions) then
  766. expectloc:=LOC_REGISTER
  767. else
  768. expectloc:=LOC_CREFERENCE;
  769. end;
  770. {*****************************************************************************
  771. TWITHNODE
  772. *****************************************************************************}
  773. constructor twithnode.create(symtable : twithsymtable;l,r : tnode;count : longint);
  774. begin
  775. inherited create(withn,l,r);
  776. withsymtable:=symtable;
  777. tablecount:=count;
  778. FillChar(withreference,sizeof(withreference),0);
  779. set_file_line(l);
  780. end;
  781. destructor twithnode.destroy;
  782. var
  783. hsymt,
  784. symt : tsymtable;
  785. i : longint;
  786. begin
  787. symt:=withsymtable;
  788. for i:=1 to tablecount do
  789. begin
  790. if assigned(symt) then
  791. begin
  792. hsymt:=symt.next;
  793. symt.free;
  794. symt:=hsymt;
  795. end;
  796. end;
  797. inherited destroy;
  798. end;
  799. constructor twithnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  800. begin
  801. inherited ppuload(t,ppufile);
  802. internalerror(200208192);
  803. end;
  804. procedure twithnode.ppuwrite(ppufile:tcompilerppufile);
  805. begin
  806. inherited ppuwrite(ppufile);
  807. internalerror(200208193);
  808. end;
  809. function twithnode.getcopy : tnode;
  810. var
  811. p : twithnode;
  812. begin
  813. p:=twithnode(inherited getcopy);
  814. p.withsymtable:=withsymtable;
  815. p.tablecount:=tablecount;
  816. p.withreference:=withreference;
  817. result:=p;
  818. end;
  819. function twithnode.det_resulttype:tnode;
  820. var
  821. symtable : tsymtable;
  822. i : longint;
  823. begin
  824. result:=nil;
  825. resulttype:=voidtype;
  826. if assigned(left) and assigned(right) then
  827. begin
  828. resulttypepass(left);
  829. unset_varstate(left);
  830. set_varstate(left,true);
  831. if codegenerror then
  832. exit;
  833. symtable:=withsymtable;
  834. for i:=1 to tablecount do
  835. begin
  836. if (left.nodetype=loadn) and
  837. (tloadnode(left).symtable=current_procdef.localst) then
  838. twithsymtable(symtable).direct_with:=true;
  839. twithsymtable(symtable).withnode:=self;
  840. symtable:=symtable.next;
  841. end;
  842. resulttypepass(right);
  843. if codegenerror then
  844. exit;
  845. end;
  846. resulttype:=voidtype;
  847. end;
  848. function twithnode.pass_1 : tnode;
  849. begin
  850. result:=nil;
  851. expectloc:=LOC_VOID;
  852. if assigned(left) and assigned(right) then
  853. begin
  854. firstpass(left);
  855. firstpass(right);
  856. if codegenerror then
  857. exit;
  858. left_right_max;
  859. end
  860. else
  861. begin
  862. { optimization }
  863. result:=nil;
  864. end;
  865. end;
  866. function twithnode.docompare(p: tnode): boolean;
  867. begin
  868. docompare :=
  869. inherited docompare(p) and
  870. (withsymtable = twithnode(p).withsymtable) and
  871. (tablecount = twithnode(p).tablecount);
  872. end;
  873. begin
  874. cloadvmtnode := tloadvmtnode;
  875. chnewnode := thnewnode;
  876. chdisposenode := thdisposenode;
  877. caddrnode := taddrnode;
  878. cdoubleaddrnode := tdoubleaddrnode;
  879. cderefnode := tderefnode;
  880. csubscriptnode := tsubscriptnode;
  881. cvecnode := tvecnode;
  882. cselfnode := tselfnode;
  883. cwithnode := twithnode;
  884. end.
  885. {
  886. $Log$
  887. Revision 1.52 2003-05-05 14:53:16 peter
  888. * vs_hidden replaced by is_hidden boolean
  889. Revision 1.51 2003/04/27 11:21:33 peter
  890. * aktprocdef renamed to current_procdef
  891. * procinfo renamed to current_procinfo
  892. * procinfo will now be stored in current_module so it can be
  893. cleaned up properly
  894. * gen_main_procsym changed to create_main_proc and release_main_proc
  895. to also generate a tprocinfo structure
  896. * fixed unit implicit initfinal
  897. Revision 1.50 2003/04/27 07:29:50 peter
  898. * current_procdef cleanup, current_procdef is now always nil when parsing
  899. a new procdef declaration
  900. * aktprocsym removed
  901. * lexlevel removed, use symtable.symtablelevel instead
  902. * implicit init/final code uses the normal genentry/genexit
  903. * funcret state checking updated for new funcret handling
  904. Revision 1.49 2003/04/23 10:10:54 peter
  905. * procvar is not compared in addrn
  906. Revision 1.48 2003/04/22 23:50:23 peter
  907. * firstpass uses expectloc
  908. * checks if there are differences between the expectloc and
  909. location.loc from secondpass in EXTDEBUG
  910. Revision 1.47 2003/04/10 17:57:52 peter
  911. * vs_hidden released
  912. Revision 1.46 2003/01/30 21:46:57 peter
  913. * self fixes for static methods (merged)
  914. Revision 1.45 2003/01/09 21:52:37 peter
  915. * merged some verbosity options.
  916. * V_LineInfo is a verbosity flag to include line info
  917. Revision 1.44 2003/01/06 21:16:52 peter
  918. * po_addressonly added to retrieve the address of a methodpointer
  919. only, this is used for @tclass.method which has no self pointer
  920. Revision 1.43 2003/01/04 15:54:03 daniel
  921. * Fixed mark_write for @ operator
  922. (can happen when compiling @procvar:=nil (Delphi mode construction))
  923. Revision 1.42 2003/01/03 12:15:56 daniel
  924. * Removed ifdefs around notifications
  925. ifdefs around for loop optimizations remain
  926. Revision 1.41 2002/11/25 17:43:20 peter
  927. * splitted defbase in defutil,symutil,defcmp
  928. * merged isconvertable and is_equal into compare_defs(_ext)
  929. * made operator search faster by walking the list only once
  930. Revision 1.40 2002/09/27 21:13:28 carl
  931. * low-highval always checked if limit ober 2GB is reached (to avoid overflow)
  932. Revision 1.39 2002/09/01 18:44:17 peter
  933. * cleanup of tvecnode.det_resulttype
  934. * move 0 element of string access check to resulttype
  935. Revision 1.38 2002/09/01 13:28:38 daniel
  936. - write_access fields removed in favor of a flag
  937. Revision 1.37 2002/09/01 08:01:16 daniel
  938. * Removed sets from Tcallnode.det_resulttype
  939. + Added read/write notifications of variables. These will be usefull
  940. for providing information for several optimizations. For example
  941. the value of the loop variable of a for loop does matter is the
  942. variable is read after the for loop, but if it's no longer used
  943. or written, it doesn't matter and this can be used to optimize
  944. the loop code generation.
  945. Revision 1.36 2002/08/19 19:36:43 peter
  946. * More fixes for cross unit inlining, all tnodes are now implemented
  947. * Moved pocall_internconst to po_internconst because it is not a
  948. calling type at all and it conflicted when inlining of these small
  949. functions was requested
  950. Revision 1.35 2002/07/23 09:51:23 daniel
  951. * Tried to make Tprocsym.defs protected. I didn't succeed but the cleanups
  952. are worth comitting.
  953. Revision 1.34 2002/07/20 11:57:54 florian
  954. * types.pas renamed to defbase.pas because D6 contains a types
  955. unit so this would conflicts if D6 programms are compiled
  956. + Willamette/SSE2 instructions to assembler added
  957. Revision 1.33 2002/05/18 13:34:10 peter
  958. * readded missing revisions
  959. Revision 1.32 2002/05/16 19:46:39 carl
  960. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  961. + try to fix temp allocation (still in ifdef)
  962. + generic constructor calls
  963. + start of tassembler / tmodulebase class cleanup
  964. Revision 1.30 2002/05/12 16:53:07 peter
  965. * moved entry and exitcode to ncgutil and cgobj
  966. * foreach gets extra argument for passing local data to the
  967. iterator function
  968. * -CR checks also class typecasts at runtime by changing them
  969. into as
  970. * fixed compiler to cycle with the -CR option
  971. * fixed stabs with elf writer, finally the global variables can
  972. be watched
  973. * removed a lot of routines from cga unit and replaced them by
  974. calls to cgobj
  975. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  976. u32bit then the other is typecasted also to u32bit without giving
  977. a rangecheck warning/error.
  978. * fixed pascal calling method with reversing also the high tree in
  979. the parast, detected by tcalcst3 test
  980. Revision 1.29 2002/04/21 19:02:04 peter
  981. * removed newn and disposen nodes, the code is now directly
  982. inlined from pexpr
  983. * -an option that will write the secondpass nodes to the .s file, this
  984. requires EXTDEBUG define to actually write the info
  985. * fixed various internal errors and crashes due recent code changes
  986. Revision 1.28 2002/04/20 21:32:23 carl
  987. + generic FPC_CHECKPOINTER
  988. + first parameter offset in stack now portable
  989. * rename some constants
  990. + move some cpu stuff to other units
  991. - remove unused constents
  992. * fix stacksize for some targets
  993. * fix generic size problems which depend now on EXTEND_SIZE constant
  994. Revision 1.27 2002/04/02 17:11:29 peter
  995. * tlocation,treference update
  996. * LOC_CONSTANT added for better constant handling
  997. * secondadd splitted in multiple routines
  998. * location_force_reg added for loading a location to a register
  999. of a specified size
  1000. * secondassignment parses now first the right and then the left node
  1001. (this is compatible with Kylix). This saves a lot of push/pop especially
  1002. with string operations
  1003. * adapted some routines to use the new cg methods
  1004. Revision 1.26 2002/04/01 20:57:13 jonas
  1005. * fixed web bug 1907
  1006. * fixed some other procvar related bugs (all related to accepting procvar
  1007. constructs with either too many or too little parameters)
  1008. (both merged, includes second typo fix of pexpr.pas)
  1009. }