nbas.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. This unit implements some basic 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 nbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cpuinfo,cpubase,cgbase,cgutils,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. node,
  25. symtype;
  26. type
  27. tnothingnode = class(tnode)
  28. constructor create;virtual;
  29. function pass_1 : tnode;override;
  30. function pass_typecheck:tnode;override;
  31. end;
  32. tnothingnodeclass = class of tnothingnode;
  33. terrornode = class(tnode)
  34. constructor create;virtual;
  35. function pass_1 : tnode;override;
  36. function pass_typecheck:tnode;override;
  37. procedure mark_write;override;
  38. end;
  39. terrornodeclass = class of terrornode;
  40. tasmnode = class(tnode)
  41. p_asm : TAsmList;
  42. currenttai : tai;
  43. { Used registers in assembler block }
  44. used_regs_int,
  45. used_regs_fpu : tcpuregisterset;
  46. constructor create(p : TAsmList);virtual;
  47. constructor create_get_position;
  48. destructor destroy;override;
  49. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  50. procedure ppuwrite(ppufile:tcompilerppufile);override;
  51. procedure buildderefimpl;override;
  52. procedure derefimpl;override;
  53. function dogetcopy : tnode;override;
  54. function pass_1 : tnode;override;
  55. function pass_typecheck:tnode;override;
  56. function docompare(p: tnode): boolean; override;
  57. end;
  58. tasmnodeclass = class of tasmnode;
  59. tstatementnode = class(tbinarynode)
  60. constructor create(l,r : tnode);virtual;
  61. function pass_1 : tnode;override;
  62. function pass_typecheck:tnode;override;
  63. procedure printnodetree(var t:text);override;
  64. end;
  65. tstatementnodeclass = class of tstatementnode;
  66. tblocknode = class(tunarynode)
  67. constructor create(l : tnode);virtual;
  68. destructor destroy; override;
  69. function pass_1 : tnode;override;
  70. function pass_typecheck:tnode;override;
  71. {$ifdef state_tracking}
  72. function track_state_pass(exec_known:boolean):boolean;override;
  73. {$endif state_tracking}
  74. end;
  75. tblocknodeclass = class of tblocknode;
  76. ttempcreatenode = class;
  77. { to allow access to the location by temp references even after the temp has }
  78. { already been disposed and to make sure the coherency between temps and }
  79. { temp references is kept after a getcopy }
  80. ptempinfo = ^ttempinfo;
  81. ttempinfo = record
  82. { set to the copy of a tempcreate pnode (if it gets copied) so that the }
  83. { refs and deletenode can hook to this copy once they get copied too }
  84. hookoncopy : ptempinfo;
  85. typedef : tdef;
  86. typedefderef : tderef;
  87. temptype : ttemptype;
  88. owner : ttempcreatenode;
  89. may_be_in_reg : boolean;
  90. valid : boolean;
  91. nextref_set_hookoncopy_nil : boolean;
  92. location : tlocation;
  93. end;
  94. { a node which will create a (non)persistent temp of a given type with a given }
  95. { size (the size is separate to allow creating "void" temps with a custom size) }
  96. ttempcreatenode = class(tnode)
  97. size: aint;
  98. tempinfo: ptempinfo;
  99. { * persistent temps are used in manually written code where the temp }
  100. { be usable among different statements and where you can manually say }
  101. { when the temp has to be freed (using a ttempdeletenode) }
  102. { * non-persistent temps are mostly used in typeconversion helpers, }
  103. { where the node that receives the temp becomes responsible for }
  104. { freeing it. In this last case, you must use only one reference }
  105. { to it and *not* generate a ttempdeletenode }
  106. constructor create(_typedef: tdef; _size: aint; _temptype: ttemptype;allowreg:boolean); virtual;
  107. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  108. procedure ppuwrite(ppufile:tcompilerppufile);override;
  109. procedure buildderefimpl;override;
  110. procedure derefimpl;override;
  111. function dogetcopy: tnode; override;
  112. function pass_1 : tnode; override;
  113. function pass_typecheck: tnode; override;
  114. function docompare(p: tnode): boolean; override;
  115. procedure printnodedata(var t:text);override;
  116. end;
  117. ttempcreatenodeclass = class of ttempcreatenode;
  118. { a node which is a reference to a certain temp }
  119. ttemprefnode = class(tnode)
  120. tempinfo: ptempinfo;
  121. constructor create(const temp: ttempcreatenode); virtual;
  122. constructor create_offset(const temp: ttempcreatenode;aoffset:longint);
  123. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  124. procedure ppuwrite(ppufile:tcompilerppufile);override;
  125. function dogetcopy: tnode; override;
  126. procedure derefnode;override;
  127. function pass_1 : tnode; override;
  128. function pass_typecheck : tnode; override;
  129. procedure mark_write;override;
  130. function docompare(p: tnode): boolean; override;
  131. procedure printnodedata(var t:text);override;
  132. protected
  133. offset : longint;
  134. private
  135. tempidx : longint;
  136. end;
  137. ttemprefnodeclass = class of ttemprefnode;
  138. { a node which removes a temp }
  139. ttempdeletenode = class(tnode)
  140. tempinfo: ptempinfo;
  141. constructor create(const temp: ttempcreatenode); virtual;
  142. { this will convert the persistant temp to a normal temp
  143. for returning to the other nodes }
  144. constructor create_normal_temp(const temp: ttempcreatenode);
  145. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  146. procedure ppuwrite(ppufile:tcompilerppufile);override;
  147. function dogetcopy: tnode; override;
  148. procedure derefnode;override;
  149. function pass_1: tnode; override;
  150. function pass_typecheck: tnode; override;
  151. function docompare(p: tnode): boolean; override;
  152. destructor destroy; override;
  153. procedure printnodedata(var t:text);override;
  154. protected
  155. release_to_normal : boolean;
  156. private
  157. tempidx : longint;
  158. end;
  159. ttempdeletenodeclass = class of ttempdeletenode;
  160. var
  161. cnothingnode : tnothingnodeclass;
  162. cerrornode : terrornodeclass;
  163. casmnode : tasmnodeclass;
  164. cstatementnode : tstatementnodeclass;
  165. cblocknode : tblocknodeclass;
  166. ctempcreatenode : ttempcreatenodeclass;
  167. ctemprefnode : ttemprefnodeclass;
  168. ctempdeletenode : ttempdeletenodeclass;
  169. { Create a blocknode and statement node for multiple statements
  170. generated internally by the parser }
  171. function internalstatements(var laststatement:tstatementnode):tblocknode;
  172. function laststatement(block:tblocknode):tstatementnode;
  173. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  174. implementation
  175. uses
  176. cutils,
  177. verbose,globals,systems,
  178. symconst,symdef,defutil,defcmp,
  179. pass_1,
  180. nld,ncal,nflw,
  181. procinfo
  182. ;
  183. {*****************************************************************************
  184. Helpers
  185. *****************************************************************************}
  186. function internalstatements(var laststatement:tstatementnode):tblocknode;
  187. begin
  188. { create dummy initial statement }
  189. laststatement := cstatementnode.create(cnothingnode.create,nil);
  190. internalstatements := cblocknode.create(laststatement);
  191. end;
  192. function laststatement(block:tblocknode):tstatementnode;
  193. begin
  194. result:=tstatementnode(block.left);
  195. while assigned(result) and assigned(result.right) do
  196. result:=tstatementnode(result.right);
  197. end;
  198. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  199. begin
  200. if assigned(laststatement.right) then
  201. internalerror(200204201);
  202. laststatement.right:=cstatementnode.create(n,nil);
  203. laststatement:=tstatementnode(laststatement.right);
  204. end;
  205. {*****************************************************************************
  206. TFIRSTNOTHING
  207. *****************************************************************************}
  208. constructor tnothingnode.create;
  209. begin
  210. inherited create(nothingn);
  211. end;
  212. function tnothingnode.pass_typecheck:tnode;
  213. begin
  214. result:=nil;
  215. resultdef:=voidtype;
  216. end;
  217. function tnothingnode.pass_1 : tnode;
  218. begin
  219. result:=nil;
  220. expectloc:=LOC_VOID;
  221. end;
  222. {*****************************************************************************
  223. TFIRSTERROR
  224. *****************************************************************************}
  225. constructor terrornode.create;
  226. begin
  227. inherited create(errorn);
  228. end;
  229. function terrornode.pass_typecheck:tnode;
  230. begin
  231. result:=nil;
  232. include(flags,nf_error);
  233. codegenerror:=true;
  234. resultdef:=generrordef;
  235. end;
  236. function terrornode.pass_1 : tnode;
  237. begin
  238. result:=nil;
  239. expectloc:=LOC_VOID;
  240. codegenerror:=true;
  241. end;
  242. procedure terrornode.mark_write;
  243. begin
  244. end;
  245. {*****************************************************************************
  246. TSTATEMENTNODE
  247. *****************************************************************************}
  248. constructor tstatementnode.create(l,r : tnode);
  249. begin
  250. inherited create(statementn,l,r);
  251. end;
  252. function tstatementnode.pass_typecheck:tnode;
  253. begin
  254. result:=nil;
  255. resultdef:=voidtype;
  256. { left is the statement itself calln assignn or a complex one }
  257. typecheckpass(left);
  258. if (not (cs_extsyntax in current_settings.moduleswitches)) and
  259. assigned(left.resultdef) and
  260. not((left.nodetype=calln) and
  261. { don't complain when funcretrefnode is set, because then the
  262. value is already used. And also not for constructors }
  263. (assigned(tcallnode(left).funcretnode) or
  264. (tcallnode(left).procdefinition.proctypeoption=potype_constructor))) and
  265. not(is_void(left.resultdef)) then
  266. CGMessage(parser_e_illegal_expression);
  267. if codegenerror then
  268. exit;
  269. { right is the next statement in the list }
  270. if assigned(right) then
  271. typecheckpass(right);
  272. if codegenerror then
  273. exit;
  274. end;
  275. function tstatementnode.pass_1 : tnode;
  276. begin
  277. result:=nil;
  278. { left is the statement itself calln assignn or a complex one }
  279. firstpass(left);
  280. if codegenerror then
  281. exit;
  282. expectloc:=left.expectloc;
  283. registersint:=left.registersint;
  284. registersfpu:=left.registersfpu;
  285. {$ifdef SUPPORT_MMX}
  286. registersmmx:=left.registersmmx;
  287. {$endif SUPPORT_MMX}
  288. { right is the next in the list }
  289. if assigned(right) then
  290. firstpass(right);
  291. if codegenerror then
  292. exit;
  293. end;
  294. procedure tstatementnode.printnodetree(var t:text);
  295. begin
  296. printnodelist(t);
  297. end;
  298. {*****************************************************************************
  299. TBLOCKNODE
  300. *****************************************************************************}
  301. constructor tblocknode.create(l : tnode);
  302. begin
  303. inherited create(blockn,l);
  304. end;
  305. destructor tblocknode.destroy;
  306. var
  307. hp, next: tstatementnode;
  308. begin
  309. hp := tstatementnode(left);
  310. left := nil;
  311. while assigned(hp) do
  312. begin
  313. next := tstatementnode(hp.right);
  314. hp.right := nil;
  315. hp.free;
  316. hp := next;
  317. end;
  318. inherited destroy;
  319. end;
  320. function tblocknode.pass_typecheck:tnode;
  321. var
  322. hp : tstatementnode;
  323. begin
  324. result:=nil;
  325. resultdef:=voidtype;
  326. hp:=tstatementnode(left);
  327. while assigned(hp) do
  328. begin
  329. if assigned(hp.left) then
  330. begin
  331. codegenerror:=false;
  332. typecheckpass(hp.left);
  333. if not(codegenerror) and
  334. not(cs_extsyntax in current_settings.moduleswitches) and
  335. (hp.left.nodetype=calln) and
  336. not(is_void(hp.left.resultdef)) and
  337. not(cnf_return_value_used in tcallnode(hp.left).callnodeflags) and
  338. not((tcallnode(hp.left).procdefinition.proctypeoption=potype_constructor) and
  339. assigned(tprocdef(tcallnode(hp.left).procdefinition)._class) and
  340. is_object(tprocdef(tcallnode(hp.left).procdefinition)._class)) then
  341. CGMessagePos(hp.left.fileinfo,parser_e_illegal_expression);
  342. { the resultdef of the block is the last type that is
  343. returned. Normally this is a voidtype. But when the
  344. compiler inserts a block of multiple statements then the
  345. last entry can return a value }
  346. resultdef:=hp.left.resultdef;
  347. end;
  348. hp:=tstatementnode(hp.right);
  349. end;
  350. end;
  351. function tblocknode.pass_1 : tnode;
  352. var
  353. hp : tstatementnode;
  354. count : longint;
  355. begin
  356. result:=nil;
  357. expectloc:=LOC_VOID;
  358. count:=0;
  359. hp:=tstatementnode(left);
  360. while assigned(hp) do
  361. begin
  362. if assigned(hp.left) then
  363. begin
  364. codegenerror:=false;
  365. firstpass(hp.left);
  366. hp.expectloc:=hp.left.expectloc;
  367. hp.registersint:=hp.left.registersint;
  368. hp.registersfpu:=hp.left.registersfpu;
  369. {$ifdef SUPPORT_MMX}
  370. hp.registersmmx:=hp.left.registersmmx;
  371. {$endif SUPPORT_MMX}
  372. end
  373. else
  374. hp.registersint:=0;
  375. if hp.registersint>registersint then
  376. registersint:=hp.registersint;
  377. if hp.registersfpu>registersfpu then
  378. registersfpu:=hp.registersfpu;
  379. {$ifdef SUPPORT_MMX}
  380. if hp.registersmmx>registersmmx then
  381. registersmmx:=hp.registersmmx;
  382. {$endif}
  383. expectloc:=hp.expectloc;
  384. inc(count);
  385. hp:=tstatementnode(hp.right);
  386. end;
  387. end;
  388. {$ifdef state_tracking}
  389. function Tblocknode.track_state_pass(exec_known:boolean):boolean;
  390. var hp:Tstatementnode;
  391. begin
  392. track_state_pass:=false;
  393. hp:=Tstatementnode(left);
  394. while assigned(hp) do
  395. begin
  396. if hp.left.track_state_pass(exec_known) then
  397. track_state_pass:=true;
  398. hp:=Tstatementnode(hp.right);
  399. end;
  400. end;
  401. {$endif state_tracking}
  402. {*****************************************************************************
  403. TASMNODE
  404. *****************************************************************************}
  405. constructor tasmnode.create(p : TAsmList);
  406. begin
  407. inherited create(asmn);
  408. p_asm:=p;
  409. currenttai:=nil;
  410. used_regs_int:=[];
  411. used_regs_fpu:=[];
  412. end;
  413. constructor tasmnode.create_get_position;
  414. begin
  415. inherited create(asmn);
  416. p_asm:=nil;
  417. include(flags,nf_get_asm_position);
  418. currenttai:=nil;
  419. end;
  420. destructor tasmnode.destroy;
  421. begin
  422. if assigned(p_asm) then
  423. p_asm.free;
  424. inherited destroy;
  425. end;
  426. constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  427. var
  428. hp : tai;
  429. begin
  430. inherited ppuload(t,ppufile);
  431. if not(nf_get_asm_position in flags) then
  432. begin
  433. p_asm:=TAsmList.create;
  434. repeat
  435. hp:=ppuloadai(ppufile);
  436. if hp=nil then
  437. break;
  438. p_asm.concat(hp);
  439. until false;
  440. end
  441. else
  442. p_asm:=nil;
  443. currenttai:=nil;
  444. end;
  445. procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
  446. var
  447. hp : tai;
  448. begin
  449. inherited ppuwrite(ppufile);
  450. {$warning FIXME Add saving of register sets}
  451. if not(nf_get_asm_position in flags) then
  452. begin
  453. hp:=tai(p_asm.first);
  454. while assigned(hp) do
  455. begin
  456. ppuwriteai(ppufile,hp);
  457. hp:=tai(hp.next);
  458. end;
  459. { end is marked by a nil }
  460. ppuwriteai(ppufile,nil);
  461. end;
  462. end;
  463. procedure tasmnode.buildderefimpl;
  464. var
  465. hp : tai;
  466. begin
  467. inherited buildderefimpl;
  468. if not(nf_get_asm_position in flags) then
  469. begin
  470. hp:=tai(p_asm.first);
  471. while assigned(hp) do
  472. begin
  473. hp.buildderefimpl;
  474. hp:=tai(hp.next);
  475. end;
  476. end;
  477. end;
  478. procedure tasmnode.derefimpl;
  479. var
  480. hp : tai;
  481. begin
  482. inherited derefimpl;
  483. if not(nf_get_asm_position in flags) then
  484. begin
  485. hp:=tai(p_asm.first);
  486. while assigned(hp) do
  487. begin
  488. hp.derefimpl;
  489. hp:=tai(hp.next);
  490. end;
  491. end;
  492. end;
  493. function tasmnode.dogetcopy: tnode;
  494. var
  495. n: tasmnode;
  496. begin
  497. n := tasmnode(inherited dogetcopy);
  498. if assigned(p_asm) then
  499. begin
  500. n.p_asm:=TAsmList.create;
  501. n.p_asm.concatlistcopy(p_asm);
  502. end
  503. else n.p_asm := nil;
  504. n.currenttai:=currenttai;
  505. result:=n;
  506. end;
  507. function tasmnode.pass_typecheck:tnode;
  508. begin
  509. result:=nil;
  510. resultdef:=voidtype;
  511. if not(nf_get_asm_position in flags) then
  512. include(current_procinfo.flags,pi_has_assembler_block);
  513. end;
  514. function tasmnode.pass_1 : tnode;
  515. begin
  516. result:=nil;
  517. expectloc:=LOC_VOID;
  518. end;
  519. function tasmnode.docompare(p: tnode): boolean;
  520. begin
  521. { comparing of asmlists is not implemented (JM) }
  522. docompare := false;
  523. end;
  524. {*****************************************************************************
  525. TEMPCREATENODE
  526. *****************************************************************************}
  527. constructor ttempcreatenode.create(_typedef:tdef; _size: aint; _temptype: ttemptype;allowreg:boolean);
  528. begin
  529. inherited create(tempcreaten);
  530. size := _size;
  531. new(tempinfo);
  532. fillchar(tempinfo^,sizeof(tempinfo^),0);
  533. tempinfo^.typedef := _typedef;
  534. tempinfo^.temptype := _temptype;
  535. tempinfo^.owner:=self;
  536. tempinfo^.may_be_in_reg:=
  537. allowreg and
  538. { temp must fit a single register }
  539. (tstoreddef(_typedef).is_fpuregable or
  540. (tstoreddef(_typedef).is_intregable and
  541. (_size<=TCGSize2Size[OS_64]))) and
  542. { size of register operations must be known }
  543. (def_cgsize(_typedef)<>OS_NO) and
  544. { no init/final needed }
  545. not (_typedef.needs_inittable) and
  546. ((_typedef.deftype <> pointerdef) or
  547. (not tpointerdef(_typedef).pointeddef.needs_inittable));
  548. end;
  549. function ttempcreatenode.dogetcopy: tnode;
  550. var
  551. n: ttempcreatenode;
  552. begin
  553. n := ttempcreatenode(inherited dogetcopy);
  554. n.size := size;
  555. new(n.tempinfo);
  556. fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
  557. n.tempinfo^.owner:=n;
  558. n.tempinfo^.typedef := tempinfo^.typedef;
  559. n.tempinfo^.temptype := tempinfo^.temptype;
  560. { when the tempinfo has already a hookoncopy then it is not
  561. reset by a tempdeletenode }
  562. if assigned(tempinfo^.hookoncopy) then
  563. internalerror(200211262);
  564. { signal the temprefs that the temp they point to has been copied, }
  565. { so that if the refs get copied as well, they can hook themselves }
  566. { to the copy of the temp }
  567. tempinfo^.hookoncopy := n.tempinfo;
  568. tempinfo^.nextref_set_hookoncopy_nil := false;
  569. result := n;
  570. end;
  571. constructor ttempcreatenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  572. begin
  573. inherited ppuload(t,ppufile);
  574. size:=ppufile.getlongint;
  575. new(tempinfo);
  576. fillchar(tempinfo^,sizeof(tempinfo^),0);
  577. tempinfo^.may_be_in_reg:=boolean(ppufile.getbyte);
  578. ppufile.getderef(tempinfo^.typedefderef);
  579. tempinfo^.temptype := ttemptype(ppufile.getbyte);
  580. tempinfo^.owner:=self;
  581. end;
  582. procedure ttempcreatenode.ppuwrite(ppufile:tcompilerppufile);
  583. begin
  584. inherited ppuwrite(ppufile);
  585. ppufile.putlongint(size);
  586. ppufile.putbyte(byte(tempinfo^.may_be_in_reg));
  587. ppufile.putderef(tempinfo^.typedefderef);
  588. ppufile.putbyte(byte(tempinfo^.temptype));
  589. end;
  590. procedure ttempcreatenode.buildderefimpl;
  591. begin
  592. tempinfo^.typedefderef.build(tempinfo^.typedef);
  593. end;
  594. procedure ttempcreatenode.derefimpl;
  595. begin
  596. tempinfo^.typedef:=tdef(tempinfo^.typedefderef.resolve);
  597. end;
  598. function ttempcreatenode.pass_1 : tnode;
  599. begin
  600. result := nil;
  601. expectloc:=LOC_VOID;
  602. if (tempinfo^.typedef.needs_inittable) then
  603. include(current_procinfo.flags,pi_needs_implicit_finally);
  604. end;
  605. function ttempcreatenode.pass_typecheck: tnode;
  606. begin
  607. result := nil;
  608. { a tempcreatenode doesn't have a resultdef, only temprefnodes do }
  609. resultdef := voidtype;
  610. end;
  611. function ttempcreatenode.docompare(p: tnode): boolean;
  612. begin
  613. result :=
  614. inherited docompare(p) and
  615. (ttempcreatenode(p).size = size) and
  616. (ttempcreatenode(p).tempinfo^.may_be_in_reg = tempinfo^.may_be_in_reg) and
  617. equal_defs(ttempcreatenode(p).tempinfo^.typedef,tempinfo^.typedef);
  618. end;
  619. procedure ttempcreatenode.printnodedata(var t:text);
  620. begin
  621. inherited printnodedata(t);
  622. writeln(t,printnodeindention,'size = ',size,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptruint(tempinfo),sizeof(ptruint)*2));
  623. end;
  624. {*****************************************************************************
  625. TEMPREFNODE
  626. *****************************************************************************}
  627. constructor ttemprefnode.create(const temp: ttempcreatenode);
  628. begin
  629. inherited create(temprefn);
  630. tempinfo := temp.tempinfo;
  631. offset:=0;
  632. end;
  633. constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
  634. begin
  635. self.create(temp);
  636. offset := aoffset;
  637. end;
  638. function ttemprefnode.dogetcopy: tnode;
  639. var
  640. n: ttemprefnode;
  641. begin
  642. n := ttemprefnode(inherited dogetcopy);
  643. n.offset := offset;
  644. if assigned(tempinfo^.hookoncopy) then
  645. { if the temp has been copied, assume it becomes a new }
  646. { temp which has to be hooked by the copied reference }
  647. begin
  648. { hook the ref to the copied temp }
  649. n.tempinfo := tempinfo^.hookoncopy;
  650. { if we passed a ttempdeletenode that changed the temp }
  651. { from a persistent one into a normal one, we must be }
  652. { the last reference (since our parent should free the }
  653. { temp (JM) }
  654. if (tempinfo^.nextref_set_hookoncopy_nil) then
  655. tempinfo^.hookoncopy := nil;
  656. end
  657. else
  658. { if the temp we refer to hasn't been copied, assume }
  659. { we're just a new reference to that temp }
  660. begin
  661. n.tempinfo := tempinfo;
  662. end;
  663. if not assigned(n.tempinfo) then
  664. internalerror(2005071901);
  665. result := n;
  666. end;
  667. constructor ttemprefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  668. begin
  669. inherited ppuload(t,ppufile);
  670. tempidx:=ppufile.getlongint;
  671. offset:=ppufile.getlongint;
  672. end;
  673. procedure ttemprefnode.ppuwrite(ppufile:tcompilerppufile);
  674. begin
  675. inherited ppuwrite(ppufile);
  676. ppufile.putlongint(tempinfo^.owner.ppuidx);
  677. ppufile.putlongint(offset);
  678. end;
  679. procedure ttemprefnode.derefnode;
  680. var
  681. temp : ttempcreatenode;
  682. begin
  683. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  684. if temp.nodetype<>tempcreaten then
  685. internalerror(200311075);
  686. tempinfo:=temp.tempinfo;
  687. end;
  688. function ttemprefnode.pass_1 : tnode;
  689. begin
  690. expectloc := LOC_REFERENCE;
  691. if not tempinfo^.typedef.needs_inittable and
  692. tempinfo^.may_be_in_reg then
  693. begin
  694. if tempinfo^.typedef.deftype=floatdef then
  695. begin
  696. if (tempinfo^.temptype = tt_persistent) then
  697. expectloc := LOC_CFPUREGISTER
  698. else
  699. expectloc := LOC_FPUREGISTER;
  700. end
  701. else
  702. begin
  703. if (tempinfo^.temptype = tt_persistent) then
  704. expectloc := LOC_CREGISTER
  705. else
  706. expectloc := LOC_REGISTER;
  707. end;
  708. end;
  709. result := nil;
  710. end;
  711. function ttemprefnode.pass_typecheck: tnode;
  712. begin
  713. { check if the temp is already resultdef passed }
  714. if not assigned(tempinfo^.typedef) then
  715. internalerror(200108233);
  716. result := nil;
  717. resultdef := tempinfo^.typedef;
  718. end;
  719. function ttemprefnode.docompare(p: tnode): boolean;
  720. begin
  721. result :=
  722. inherited docompare(p) and
  723. (ttemprefnode(p).tempinfo = tempinfo) and
  724. (ttemprefnode(p).offset = offset);
  725. end;
  726. procedure Ttemprefnode.mark_write;
  727. begin
  728. include(flags,nf_write);
  729. end;
  730. procedure ttemprefnode.printnodedata(var t:text);
  731. begin
  732. inherited printnodedata(t);
  733. writeln(t,printnodeindention,'temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptruint(tempinfo),sizeof(ptruint)*2));
  734. end;
  735. {*****************************************************************************
  736. TEMPDELETENODE
  737. *****************************************************************************}
  738. constructor ttempdeletenode.create(const temp: ttempcreatenode);
  739. begin
  740. inherited create(tempdeleten);
  741. tempinfo := temp.tempinfo;
  742. release_to_normal := false;
  743. end;
  744. constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
  745. begin
  746. inherited create(tempdeleten);
  747. tempinfo := temp.tempinfo;
  748. release_to_normal := true;
  749. if tempinfo^.temptype <> tt_persistent then
  750. internalerror(200204211);
  751. end;
  752. function ttempdeletenode.dogetcopy: tnode;
  753. var
  754. n: ttempdeletenode;
  755. begin
  756. n := ttempdeletenode(inherited dogetcopy);
  757. n.release_to_normal := release_to_normal;
  758. if assigned(tempinfo^.hookoncopy) then
  759. { if the temp has been copied, assume it becomes a new }
  760. { temp which has to be hooked by the copied deletenode }
  761. begin
  762. { hook the tempdeletenode to the copied temp }
  763. n.tempinfo := tempinfo^.hookoncopy;
  764. { the temp shall not be used, reset hookoncopy }
  765. { Only if release_to_normal is false, otherwise }
  766. { the temp can still be referenced once more (JM) }
  767. if (not release_to_normal) then
  768. tempinfo^.hookoncopy:=nil
  769. else
  770. tempinfo^.nextref_set_hookoncopy_nil := true;
  771. end
  772. else
  773. { if the temp we refer to hasn't been copied, we have a }
  774. { problem since that means we now have two delete nodes }
  775. { for one temp }
  776. internalerror(200108234);
  777. result := n;
  778. end;
  779. constructor ttempdeletenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  780. begin
  781. inherited ppuload(t,ppufile);
  782. tempidx:=ppufile.getlongint;
  783. release_to_normal:=(ppufile.getbyte<>0);
  784. end;
  785. procedure ttempdeletenode.ppuwrite(ppufile:tcompilerppufile);
  786. begin
  787. inherited ppuwrite(ppufile);
  788. ppufile.putlongint(tempinfo^.owner.ppuidx);
  789. ppufile.putbyte(byte(release_to_normal));
  790. end;
  791. procedure ttempdeletenode.derefnode;
  792. var
  793. temp : ttempcreatenode;
  794. begin
  795. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  796. if temp.nodetype<>tempcreaten then
  797. internalerror(200311075);
  798. tempinfo:=temp.tempinfo;
  799. end;
  800. function ttempdeletenode.pass_1 : tnode;
  801. begin
  802. expectloc:=LOC_VOID;
  803. result := nil;
  804. end;
  805. function ttempdeletenode.pass_typecheck: tnode;
  806. begin
  807. result := nil;
  808. resultdef := voidtype;
  809. end;
  810. function ttempdeletenode.docompare(p: tnode): boolean;
  811. begin
  812. result :=
  813. inherited docompare(p) and
  814. (ttemprefnode(p).tempinfo = tempinfo);
  815. end;
  816. destructor ttempdeletenode.destroy;
  817. begin
  818. dispose(tempinfo);
  819. end;
  820. procedure ttempdeletenode.printnodedata(var t:text);
  821. begin
  822. inherited printnodedata(t);
  823. writeln(t,printnodeindention,'release_to_normal: ',release_to_normal,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptruint(tempinfo),sizeof(ptruint)*2));
  824. end;
  825. begin
  826. cnothingnode:=tnothingnode;
  827. cerrornode:=terrornode;
  828. casmnode:=tasmnode;
  829. cstatementnode:=tstatementnode;
  830. cblocknode:=tblocknode;
  831. ctempcreatenode:=ttempcreatenode;
  832. ctemprefnode:=ttemprefnode;
  833. ctempdeletenode:=ttempdeletenode;
  834. end.