nbas.pas 33 KB

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