nbas.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057
  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. cpubase,
  23. aasmbase,aasmtai,aasmcpu,
  24. node,
  25. tgobj,
  26. symtype,symppu;
  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. getposition : boolean;
  45. constructor create(p : taasmoutput);virtual;
  46. constructor create_get_position;
  47. destructor destroy;override;
  48. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  49. procedure ppuwrite(ppufile:tcompilerppufile);override;
  50. procedure derefimpl;override;
  51. function getcopy : tnode;override;
  52. function pass_1 : tnode;override;
  53. function det_resulttype:tnode;override;
  54. function docompare(p: tnode): boolean; override;
  55. end;
  56. tasmnodeclass = class of tasmnode;
  57. tstatementnode = class(tbinarynode)
  58. constructor create(l,r : tnode);virtual;
  59. function pass_1 : tnode;override;
  60. function det_resulttype:tnode;override;
  61. procedure printnodetree(var t:text);override;
  62. end;
  63. tstatementnodeclass = class of tstatementnode;
  64. tblocknode = class(tunarynode)
  65. constructor create(l : tnode;releasetemp : boolean);virtual;
  66. function pass_1 : tnode;override;
  67. function det_resulttype:tnode;override;
  68. {$ifdef state_tracking}
  69. function track_state_pass(exec_known:boolean):boolean;override;
  70. {$endif state_tracking}
  71. end;
  72. tblocknodeclass = class of tblocknode;
  73. { to allow access to the location by temp references even after the temp has }
  74. { already been disposed and to make sure the coherency between temps and }
  75. { temp references is kept after a getcopy }
  76. ptempinfo = ^ttempinfo;
  77. ttempinfo = record
  78. { set to the copy of a tempcreate pnode (if it gets copied) so that the }
  79. { refs and deletenode can hook to this copy once they get copied too }
  80. hookoncopy : ptempinfo;
  81. ref : treference;
  82. restype : ttype;
  83. temptype : ttemptype;
  84. valid : boolean;
  85. nextref_set_hookoncopy_nil : boolean;
  86. end;
  87. { a node which will create a (non)persistent temp of a given type with a given }
  88. { size (the size is separate to allow creating "void" temps with a custom size) }
  89. ttempcreatenode = class(tnode)
  90. size: longint;
  91. temptype: ttemptype;
  92. tempinfo: ptempinfo;
  93. { * persistent temps are used in manually written code where the temp }
  94. { be usable among different statements and where you can manually say }
  95. { when the temp has to be freed (using a ttempdeletenode) }
  96. { * non-persistent temps are mostly used in typeconversion helpers, }
  97. { where the node that receives the temp becomes responsible for }
  98. { freeing it. In this last case, you should use only one reference }
  99. { to it and *not* generate a ttempdeletenode }
  100. constructor create(const _restype: ttype; _size: longint; _temptype: ttemptype); virtual;
  101. function getcopy: tnode; override;
  102. function pass_1 : tnode; override;
  103. function det_resulttype: tnode; override;
  104. function docompare(p: tnode): boolean; override;
  105. procedure printnodedata(var t:text);override;
  106. end;
  107. ttempcreatenodeclass = class of ttempcreatenode;
  108. { a node which is a reference to a certain temp }
  109. ttemprefnode = class(tnode)
  110. constructor create(const temp: ttempcreatenode); virtual;
  111. constructor create_offset(const temp: ttempcreatenode;aoffset:longint);
  112. function getcopy: tnode; override;
  113. function pass_1 : tnode; override;
  114. function det_resulttype : tnode; override;
  115. procedure mark_write;override;
  116. function docompare(p: tnode): boolean; override;
  117. { Changes the location of this temp to ref. Useful when assigning }
  118. { another temp to this one. The current location will be freed. }
  119. { Can only be called in pass 2 (since earlier, the temp location }
  120. { isn't known yet) }
  121. procedure changelocation(const ref: treference);
  122. protected
  123. tempinfo: ptempinfo;
  124. offset : longint;
  125. end;
  126. ttemprefnodeclass = class of ttemprefnode;
  127. { a node which removes a temp }
  128. ttempdeletenode = class(tnode)
  129. constructor create(const temp: ttempcreatenode);
  130. { this will convert the persistant temp to a normal temp
  131. for returning to the other nodes }
  132. constructor create_normal_temp(const temp: ttempcreatenode);
  133. function getcopy: tnode; override;
  134. function pass_1: tnode; override;
  135. function det_resulttype: tnode; override;
  136. function docompare(p: tnode): boolean; override;
  137. destructor destroy; override;
  138. protected
  139. tempinfo: ptempinfo;
  140. release_to_normal : boolean;
  141. end;
  142. ttempdeletenodeclass = class of ttempdeletenode;
  143. var
  144. cnothingnode : tnothingnodeclass;
  145. cerrornode : terrornodeclass;
  146. casmnode : tasmnodeclass;
  147. cstatementnode : tstatementnodeclass;
  148. cblocknode : tblocknodeclass;
  149. ctempcreatenode : ttempcreatenodeclass;
  150. ctemprefnode : ttemprefnodeclass;
  151. ctempdeletenode : ttempdeletenodeclass;
  152. { Create a blocknode and statement node for multiple statements
  153. generated internally by the parser }
  154. function internalstatements(var laststatement:tstatementnode;releasetemp : boolean):tblocknode;
  155. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  156. implementation
  157. uses
  158. cutils,
  159. verbose,globals,globtype,systems,
  160. symconst,symdef,symsym,symutil,defutil,defcmp,
  161. pass_1,
  162. nld,ncal,nflw,rgobj,cginfo,cgbase
  163. ;
  164. {*****************************************************************************
  165. Helpers
  166. *****************************************************************************}
  167. function internalstatements(var laststatement:tstatementnode;releasetemp : boolean):tblocknode;
  168. begin
  169. { create dummy initial statement }
  170. laststatement := cstatementnode.create(cnothingnode.create,nil);
  171. internalstatements := cblocknode.create(laststatement,releasetemp);
  172. end;
  173. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  174. begin
  175. if assigned(laststatement.right) then
  176. internalerror(200204201);
  177. laststatement.right:=cstatementnode.create(n,nil);
  178. laststatement:=tstatementnode(laststatement.right);
  179. end;
  180. {*****************************************************************************
  181. TFIRSTNOTHING
  182. *****************************************************************************}
  183. constructor tnothingnode.create;
  184. begin
  185. inherited create(nothingn);
  186. end;
  187. function tnothingnode.det_resulttype:tnode;
  188. begin
  189. result:=nil;
  190. resulttype:=voidtype;
  191. end;
  192. function tnothingnode.pass_1 : tnode;
  193. begin
  194. result:=nil;
  195. expectloc:=LOC_VOID;
  196. end;
  197. {*****************************************************************************
  198. TFIRSTERROR
  199. *****************************************************************************}
  200. constructor terrornode.create;
  201. begin
  202. inherited create(errorn);
  203. end;
  204. function terrornode.det_resulttype:tnode;
  205. begin
  206. result:=nil;
  207. include(flags,nf_error);
  208. codegenerror:=true;
  209. resulttype:=generrortype;
  210. end;
  211. function terrornode.pass_1 : tnode;
  212. begin
  213. result:=nil;
  214. expectloc:=LOC_VOID;
  215. codegenerror:=true;
  216. end;
  217. procedure terrornode.mark_write;
  218. begin
  219. end;
  220. {*****************************************************************************
  221. TSTATEMENTNODE
  222. *****************************************************************************}
  223. constructor tstatementnode.create(l,r : tnode);
  224. begin
  225. inherited create(statementn,l,r);
  226. end;
  227. function tstatementnode.det_resulttype:tnode;
  228. begin
  229. result:=nil;
  230. resulttype:=voidtype;
  231. { left is the statement itself calln assignn or a complex one }
  232. resulttypepass(left);
  233. if (not (cs_extsyntax in aktmoduleswitches)) and
  234. assigned(left.resulttype.def) and
  235. not((left.nodetype=calln) and
  236. { don't complain when funcretrefnode is set, because then the
  237. value is already used. And also not for constructors }
  238. (assigned(tcallnode(left).funcretnode) or
  239. (tcallnode(left).procdefinition.proctypeoption=potype_constructor))) and
  240. not(is_void(left.resulttype.def)) then
  241. CGMessage(cg_e_illegal_expression);
  242. if codegenerror then
  243. exit;
  244. { right is the next statement in the list }
  245. if assigned(right) then
  246. resulttypepass(right);
  247. if codegenerror then
  248. exit;
  249. end;
  250. function tstatementnode.pass_1 : tnode;
  251. begin
  252. result:=nil;
  253. { left is the statement itself calln assignn or a complex one }
  254. firstpass(left);
  255. if codegenerror then
  256. exit;
  257. expectloc:=left.expectloc;
  258. registers32:=left.registers32;
  259. registersfpu:=left.registersfpu;
  260. {$ifdef SUPPORT_MMX}
  261. registersmmx:=left.registersmmx;
  262. {$endif SUPPORT_MMX}
  263. { right is the next in the list }
  264. if assigned(right) then
  265. firstpass(right);
  266. if codegenerror then
  267. exit;
  268. end;
  269. procedure tstatementnode.printnodetree(var t:text);
  270. begin
  271. printnodelist(t);
  272. end;
  273. {*****************************************************************************
  274. TBLOCKNODE
  275. *****************************************************************************}
  276. constructor tblocknode.create(l : tnode;releasetemp : boolean);
  277. begin
  278. inherited create(blockn,l);
  279. {$ifndef newra}
  280. if releasetemp then
  281. include(flags,nf_releasetemps);
  282. {$endif newra}
  283. end;
  284. function tblocknode.det_resulttype:tnode;
  285. var
  286. hp : tstatementnode;
  287. begin
  288. result:=nil;
  289. resulttype:=voidtype;
  290. hp:=tstatementnode(left);
  291. while assigned(hp) do
  292. begin
  293. if assigned(hp.left) then
  294. begin
  295. codegenerror:=false;
  296. resulttypepass(hp.left);
  297. if (not (cs_extsyntax in aktmoduleswitches)) and
  298. assigned(hp.left.resulttype.def) and
  299. not((hp.left.nodetype=calln) and
  300. { don't complain when funcretnode is set, because then the
  301. value is already used. And also not for constructors }
  302. (assigned(tcallnode(hp.left).funcretnode) or
  303. (tcallnode(hp.left).procdefinition.proctypeoption=potype_constructor))) and
  304. not(is_void(hp.left.resulttype.def)) then
  305. CGMessagePos(hp.left.fileinfo,cg_e_illegal_expression);
  306. { the resulttype of the block is the last type that is
  307. returned. Normally this is a voidtype. But when the
  308. compiler inserts a block of multiple statements then the
  309. last entry can return a value }
  310. resulttype:=hp.left.resulttype;
  311. end;
  312. hp:=tstatementnode(hp.right);
  313. end;
  314. end;
  315. function tblocknode.pass_1 : tnode;
  316. var
  317. hp : tstatementnode;
  318. count : longint;
  319. begin
  320. result:=nil;
  321. expectloc:=LOC_VOID;
  322. count:=0;
  323. hp:=tstatementnode(left);
  324. while assigned(hp) do
  325. begin
  326. (*
  327. if cs_regalloc in aktglobalswitches then
  328. begin
  329. { node transformations }
  330. { concat function result to exit }
  331. { this is wrong for string or other complex
  332. result types !!! }
  333. if {ret_in_acc(current_procdef.rettype.def) and }
  334. (is_ordinal(current_procdef.rettype.def) or
  335. is_smallset(current_procdef.rettype.def)) and
  336. assigned(hp.right) and
  337. assigned(tstatementnode(hp.right).left) and
  338. (tstatementnode(hp.right).left.nodetype=exitn) and
  339. (hp.left.nodetype=assignn) and
  340. { !!!! this tbinarynode should be tassignmentnode }
  341. (tbinarynode(hp.left).left.nodetype=loadn) and
  342. (is_funcret_sym(tloadnode(tbinarynode(hp.left).left).symtableentry)) then
  343. begin
  344. if assigned(texitnode(tstatementnode(hp.right).left).left) then
  345. CGMessage(cg_n_inefficient_code)
  346. else
  347. begin
  348. texitnode(tstatementnode(hp.right).left).left:=tassignmentnode(hp.left).right;
  349. tassignmentnode(hp.left).right:=nil;
  350. hp.left.free;
  351. hp.left:=nil;
  352. end;
  353. end
  354. { warning if unreachable code occurs and elimate this }
  355. else if (hp.left.nodetype in
  356. [exitn,breakn,continuen,goton]) and
  357. { statement node (JM) }
  358. assigned(hp.right) and
  359. { kind of statement! (JM) }
  360. assigned(tstatementnode(hp.right).left) and
  361. (tstatementnode(hp.right).left.nodetype<>labeln) then
  362. begin
  363. { use correct line number }
  364. aktfilepos:=hp.right.fileinfo;
  365. hp.right.free;
  366. hp.right:=nil;
  367. CGMessage(cg_w_unreachable_code);
  368. { old lines }
  369. aktfilepos:=hp.left.fileinfo;
  370. end;
  371. end;
  372. *)
  373. if assigned(hp.left) then
  374. begin
  375. codegenerror:=false;
  376. firstpass(hp.left);
  377. hp.expectloc:=hp.left.expectloc;
  378. hp.registers32:=hp.left.registers32;
  379. hp.registersfpu:=hp.left.registersfpu;
  380. {$ifdef SUPPORT_MMX}
  381. hp.registersmmx:=hp.left.registersmmx;
  382. {$endif SUPPORT_MMX}
  383. end
  384. else
  385. hp.registers32:=0;
  386. if hp.registers32>registers32 then
  387. registers32:=hp.registers32;
  388. if hp.registersfpu>registersfpu then
  389. registersfpu:=hp.registersfpu;
  390. {$ifdef SUPPORT_MMX}
  391. if hp.registersmmx>registersmmx then
  392. registersmmx:=hp.registersmmx;
  393. {$endif}
  394. expectloc:=hp.expectloc;
  395. inc(count);
  396. hp:=tstatementnode(hp.right);
  397. end;
  398. end;
  399. {$ifdef state_tracking}
  400. function Tblocknode.track_state_pass(exec_known:boolean):boolean;
  401. var hp:Tstatementnode;
  402. begin
  403. track_state_pass:=false;
  404. hp:=Tstatementnode(left);
  405. while assigned(hp) do
  406. begin
  407. if hp.left.track_state_pass(exec_known) then
  408. track_state_pass:=true;
  409. hp:=Tstatementnode(hp.right);
  410. end;
  411. end;
  412. {$endif state_tracking}
  413. {*****************************************************************************
  414. TASMNODE
  415. *****************************************************************************}
  416. constructor tasmnode.create(p : taasmoutput);
  417. begin
  418. inherited create(asmn);
  419. p_asm:=p;
  420. getposition:=false;
  421. currenttai:=nil;
  422. end;
  423. constructor tasmnode.create_get_position;
  424. begin
  425. inherited create(asmn);
  426. p_asm:=nil;
  427. getposition:=true;
  428. currenttai:=nil;
  429. end;
  430. destructor tasmnode.destroy;
  431. begin
  432. if assigned(p_asm) then
  433. p_asm.free;
  434. inherited destroy;
  435. end;
  436. constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  437. var
  438. hp : tai;
  439. begin
  440. inherited ppuload(t,ppufile);
  441. getposition:=boolean(ppufile.getbyte);
  442. if not getposition then
  443. begin
  444. p_asm:=taasmoutput.create;
  445. repeat
  446. hp:=ppuloadai(ppufile);
  447. if hp=nil then
  448. break;
  449. p_asm.concat(hp);
  450. until false;
  451. end
  452. else
  453. p_asm:=nil;
  454. currenttai:=nil;
  455. end;
  456. procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
  457. var
  458. hp : tai;
  459. begin
  460. inherited ppuwrite(ppufile);
  461. ppufile.putbyte(byte(getposition));
  462. if not getposition then
  463. begin
  464. hp:=tai(p_asm.first);
  465. while assigned(hp) do
  466. begin
  467. ppuwriteai(ppufile,hp);
  468. hp:=tai(hp.next);
  469. end;
  470. { end is marked by a nil }
  471. ppuwriteai(ppufile,nil);
  472. end;
  473. end;
  474. procedure tasmnode.derefimpl;
  475. var
  476. hp : tai;
  477. begin
  478. inherited derefimpl;
  479. hp:=tai(p_asm.first);
  480. while assigned(hp) do
  481. begin
  482. hp.derefimpl;
  483. hp:=tai(hp.next);
  484. end;
  485. end;
  486. function tasmnode.getcopy: tnode;
  487. var
  488. n: tasmnode;
  489. begin
  490. n := tasmnode(inherited getcopy);
  491. if assigned(p_asm) then
  492. begin
  493. n.p_asm:=taasmoutput.create;
  494. n.p_asm.concatlistcopy(p_asm);
  495. end
  496. else n.p_asm := nil;
  497. n.getposition:=getposition;
  498. n.currenttai:=currenttai;
  499. getcopy := n;
  500. end;
  501. function tasmnode.det_resulttype:tnode;
  502. begin
  503. result:=nil;
  504. resulttype:=voidtype;
  505. if not getposition then
  506. include(current_procinfo.flags,pi_uses_asm);
  507. end;
  508. function tasmnode.pass_1 : tnode;
  509. begin
  510. result:=nil;
  511. expectloc:=LOC_VOID;
  512. end;
  513. function tasmnode.docompare(p: tnode): boolean;
  514. begin
  515. { comparing of asmlists is not implemented (JM) }
  516. docompare := false;
  517. end;
  518. {*****************************************************************************
  519. TEMPCREATENODE
  520. *****************************************************************************}
  521. constructor ttempcreatenode.create(const _restype: ttype; _size: longint; _temptype: ttemptype);
  522. begin
  523. inherited create(tempcreaten);
  524. size := _size;
  525. new(tempinfo);
  526. fillchar(tempinfo^,sizeof(tempinfo^),0);
  527. tempinfo^.restype := _restype;
  528. temptype := _temptype;
  529. end;
  530. function ttempcreatenode.getcopy: tnode;
  531. var
  532. n: ttempcreatenode;
  533. begin
  534. n := ttempcreatenode(inherited getcopy);
  535. n.size := size;
  536. n.temptype := temptype;
  537. new(n.tempinfo);
  538. fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
  539. n.tempinfo^.restype := tempinfo^.restype;
  540. { when the tempinfo has already a hookoncopy then it is not
  541. reset by a tempdeletenode }
  542. if assigned(tempinfo^.hookoncopy) then
  543. internalerror(200211262);
  544. { signal the temprefs that the temp they point to has been copied, }
  545. { so that if the refs get copied as well, they can hook themselves }
  546. { to the copy of the temp }
  547. tempinfo^.hookoncopy := n.tempinfo;
  548. tempinfo^.nextref_set_hookoncopy_nil := false;
  549. result := n;
  550. end;
  551. function ttempcreatenode.pass_1 : tnode;
  552. begin
  553. result := nil;
  554. expectloc:=LOC_VOID;
  555. end;
  556. function ttempcreatenode.det_resulttype: tnode;
  557. begin
  558. result := nil;
  559. { a tempcreatenode doesn't have a resulttype, only temprefnodes do }
  560. resulttype := voidtype;
  561. end;
  562. function ttempcreatenode.docompare(p: tnode): boolean;
  563. begin
  564. result :=
  565. inherited docompare(p) and
  566. (ttempcreatenode(p).size = size) and
  567. equal_defs(ttempcreatenode(p).tempinfo^.restype.def,tempinfo^.restype.def);
  568. end;
  569. procedure ttempcreatenode.printnodedata(var t:text);
  570. begin
  571. inherited printnodedata(t);
  572. writeln(t,printnodeindention,'size = ',size);
  573. end;
  574. {*****************************************************************************
  575. TEMPREFNODE
  576. *****************************************************************************}
  577. constructor ttemprefnode.create(const temp: ttempcreatenode);
  578. begin
  579. inherited create(temprefn);
  580. tempinfo := temp.tempinfo;
  581. offset:=0;
  582. end;
  583. constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
  584. begin
  585. self.create(temp);
  586. offset := aoffset;
  587. end;
  588. function ttemprefnode.getcopy: tnode;
  589. var
  590. n: ttemprefnode;
  591. begin
  592. n := ttemprefnode(inherited getcopy);
  593. n.offset := offset;
  594. if assigned(tempinfo^.hookoncopy) then
  595. { if the temp has been copied, assume it becomes a new }
  596. { temp which has to be hooked by the copied reference }
  597. begin
  598. { hook the ref to the copied temp }
  599. n.tempinfo := tempinfo^.hookoncopy;
  600. { if we passed a ttempdeletenode that changed the temp }
  601. { from a persistent one into a normal one, we must be }
  602. { the last reference (since our parent should free the }
  603. { temp (JM) }
  604. if (tempinfo^.nextref_set_hookoncopy_nil) then
  605. tempinfo^.hookoncopy := nil;
  606. end
  607. else
  608. { if the temp we refer to hasn't been copied, assume }
  609. { we're just a new reference to that temp }
  610. begin
  611. n.tempinfo := tempinfo;
  612. end;
  613. result := n;
  614. end;
  615. function ttemprefnode.pass_1 : tnode;
  616. begin
  617. expectloc:=LOC_REFERENCE;
  618. result := nil;
  619. end;
  620. function ttemprefnode.det_resulttype: tnode;
  621. begin
  622. { check if the temp is already resulttype passed }
  623. if not assigned(tempinfo^.restype.def) then
  624. internalerror(200108233);
  625. result := nil;
  626. resulttype := tempinfo^.restype;
  627. end;
  628. function ttemprefnode.docompare(p: tnode): boolean;
  629. begin
  630. result :=
  631. inherited docompare(p) and
  632. (ttemprefnode(p).tempinfo = tempinfo) and
  633. (ttemprefnode(p).offset = offset);
  634. end;
  635. procedure Ttemprefnode.mark_write;
  636. begin
  637. include(flags,nf_write);
  638. end;
  639. procedure ttemprefnode.changelocation(const ref: treference);
  640. begin
  641. { check if the temp is valid }
  642. if not tempinfo^.valid then
  643. internalerror(200306081);
  644. if (tempinfo^.temptype = tt_persistent) then
  645. tg.ChangeTempType(exprasmlist,tempinfo^.ref,tt_normal);
  646. tg.ungettemp(exprasmlist,tempinfo^.ref);
  647. tempinfo^.ref := ref;
  648. tg.ChangeTempType(exprasmlist,tempinfo^.ref,tempinfo^.temptype);
  649. { adapt location }
  650. location.reference := ref;
  651. inc(location.reference.offset,offset);
  652. end;
  653. {*****************************************************************************
  654. TEMPDELETENODE
  655. *****************************************************************************}
  656. constructor ttempdeletenode.create(const temp: ttempcreatenode);
  657. begin
  658. inherited create(tempdeleten);
  659. tempinfo := temp.tempinfo;
  660. release_to_normal := false;
  661. end;
  662. constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
  663. begin
  664. inherited create(tempdeleten);
  665. tempinfo := temp.tempinfo;
  666. release_to_normal := true;
  667. if temp.temptype <> tt_persistent then
  668. internalerror(200204211);
  669. end;
  670. function ttempdeletenode.getcopy: tnode;
  671. var
  672. n: ttempdeletenode;
  673. begin
  674. n := ttempdeletenode(inherited getcopy);
  675. n.release_to_normal := release_to_normal;
  676. if assigned(tempinfo^.hookoncopy) then
  677. { if the temp has been copied, assume it becomes a new }
  678. { temp which has to be hooked by the copied deletenode }
  679. begin
  680. { hook the tempdeletenode to the copied temp }
  681. n.tempinfo := tempinfo^.hookoncopy;
  682. { the temp shall not be used, reset hookoncopy }
  683. { Only if release_to_normal is false, otherwise }
  684. { the temp can still be referenced once more (JM) }
  685. if (not release_to_normal) then
  686. tempinfo^.hookoncopy:=nil
  687. else
  688. tempinfo^.nextref_set_hookoncopy_nil := true;
  689. end
  690. else
  691. { if the temp we refer to hasn't been copied, we have a }
  692. { problem since that means we now have two delete nodes }
  693. { for one temp }
  694. internalerror(200108234);
  695. result := n;
  696. end;
  697. function ttempdeletenode.pass_1 : tnode;
  698. begin
  699. expectloc:=LOC_VOID;
  700. result := nil;
  701. end;
  702. function ttempdeletenode.det_resulttype: tnode;
  703. begin
  704. result := nil;
  705. resulttype := voidtype;
  706. end;
  707. function ttempdeletenode.docompare(p: tnode): boolean;
  708. begin
  709. result :=
  710. inherited docompare(p) and
  711. (ttemprefnode(p).tempinfo = tempinfo);
  712. end;
  713. destructor ttempdeletenode.destroy;
  714. begin
  715. dispose(tempinfo);
  716. end;
  717. begin
  718. cnothingnode:=tnothingnode;
  719. cerrornode:=terrornode;
  720. casmnode:=tasmnode;
  721. cstatementnode:=tstatementnode;
  722. cblocknode:=tblocknode;
  723. ctempcreatenode:=ttempcreatenode;
  724. ctemprefnode:=ttemprefnode;
  725. ctempdeletenode:=ttempdeletenode;
  726. end.
  727. {
  728. $Log$
  729. Revision 1.55 2003-06-09 12:20:47 peter
  730. * getposition added to retrieve the the current tai item
  731. Revision 1.54 2003/06/08 18:27:15 jonas
  732. + ability to change the location of a ttempref node with changelocation()
  733. method. Useful to use instead of copying the contents from one temp to
  734. another
  735. + some shortstring optimizations in tassignmentnode that avoid some
  736. copying (required some shortstring optimizations to be moved from
  737. resulttype to firstpass, because they work on callnodes and string
  738. addnodes are only changed to callnodes in the firstpass)
  739. * allow setting/changing the funcretnode of callnodes after the
  740. resulttypepass has been done, funcretnode is now a property
  741. (all of the above should have a quite big effect on callparatemp)
  742. Revision 1.53 2003/05/30 21:01:44 jonas
  743. - disabled "result := value; exit;" -> exit(value) optimization because
  744. a) it was wrong
  745. b) exit(value) works now exactly the same as that
  746. (it was only activated with -Or)
  747. Revision 1.52 2003/05/23 14:27:35 peter
  748. * remove some unit dependencies
  749. * current_procinfo changes to store more info
  750. Revision 1.51 2003/05/17 13:30:08 jonas
  751. * changed tt_persistant to tt_persistent :)
  752. * tempcreatenode now doesn't accept a boolean anymore for persistent
  753. temps, but a ttemptype, so you can also create ansistring temps etc
  754. Revision 1.50 2003/05/13 19:14:41 peter
  755. * failn removed
  756. * inherited result code check moven to pexpr
  757. Revision 1.49 2003/05/11 14:45:12 peter
  758. * tloadnode does not support objectsymtable,withsymtable anymore
  759. * withnode cleanup
  760. * direct with rewritten to use temprefnode
  761. Revision 1.48 2003/04/27 11:21:33 peter
  762. * aktprocdef renamed to current_procdef
  763. * procinfo renamed to current_procinfo
  764. * procinfo will now be stored in current_module so it can be
  765. cleaned up properly
  766. * gen_main_procsym changed to create_main_proc and release_main_proc
  767. to also generate a tprocinfo structure
  768. * fixed unit implicit initfinal
  769. Revision 1.47 2003/04/25 20:59:33 peter
  770. * removed funcretn,funcretsym, function result is now in varsym
  771. and aliases for result and function name are added using absolutesym
  772. * vs_hidden parameter for funcret passed in parameter
  773. * vs_hidden fixes
  774. * writenode changed to printnode and released from extdebug
  775. * -vp option added to generate a tree.log with the nodetree
  776. * nicer printnode for statements, callnode
  777. Revision 1.46 2002/04/25 20:15:39 florian
  778. * block nodes within expressions shouldn't release the used registers,
  779. fixed using a flag till the new rg is ready
  780. Revision 1.45 2003/04/23 08:41:34 jonas
  781. * fixed ttemprefnode.compare and .getcopy to take offset field into
  782. account
  783. Revision 1.44 2003/04/22 23:50:22 peter
  784. * firstpass uses expectloc
  785. * checks if there are differences between the expectloc and
  786. location.loc from secondpass in EXTDEBUG
  787. Revision 1.43 2003/04/21 15:00:22 jonas
  788. * fixed tstatementnode.det_resulttype and tststatementnode.pass_1
  789. * fixed some getcopy issues with ttemp*nodes
  790. Revision 1.42 2003/04/17 07:50:24 daniel
  791. * Some work on interference graph construction
  792. Revision 1.41 2003/04/12 14:53:59 jonas
  793. * ttempdeletenode.create now sets the nodetype to tempdeleten instead of
  794. temprefn
  795. Revision 1.40 2003/03/17 20:30:46 peter
  796. * errornode.mark_write added
  797. Revision 1.39 2003/01/03 12:15:55 daniel
  798. * Removed ifdefs around notifications
  799. ifdefs around for loop optimizations remain
  800. Revision 1.38 2002/11/27 02:37:12 peter
  801. * case statement inlining added
  802. * fixed inlining of write()
  803. * switched statementnode left and right parts so the statements are
  804. processed in the correct order when getcopy is used. This is
  805. required for tempnodes
  806. Revision 1.37 2002/11/25 17:43:17 peter
  807. * splitted defbase in defutil,symutil,defcmp
  808. * merged isconvertable and is_equal into compare_defs(_ext)
  809. * made operator search faster by walking the list only once
  810. Revision 1.36 2002/10/05 15:15:19 peter
  811. * don't complain in X- mode for internal generated function calls
  812. with funcretrefnode set
  813. * give statement error at the correct line position instead of the
  814. block begin
  815. Revision 1.35 2002/09/01 08:01:16 daniel
  816. * Removed sets from Tcallnode.det_resulttype
  817. + Added read/write notifications of variables. These will be usefull
  818. for providing information for several optimizations. For example
  819. the value of the loop variable of a for loop does matter is the
  820. variable is read after the for loop, but if it's no longer used
  821. or written, it doesn't matter and this can be used to optimize
  822. the loop code generation.
  823. Revision 1.34 2002/08/18 20:06:23 peter
  824. * inlining is now also allowed in interface
  825. * renamed write/load to ppuwrite/ppuload
  826. * tnode storing in ppu
  827. * nld,ncon,nbas are already updated for storing in ppu
  828. Revision 1.33 2002/08/17 22:09:44 florian
  829. * result type handling in tcgcal.pass_2 overhauled
  830. * better tnode.printnodetree
  831. * some ppc stuff fixed
  832. Revision 1.32 2002/08/17 09:23:34 florian
  833. * first part of procinfo rewrite
  834. Revision 1.31 2002/08/15 19:10:35 peter
  835. * first things tai,tnode storing in ppu
  836. Revision 1.30 2002/07/20 11:57:53 florian
  837. * types.pas renamed to defbase.pas because D6 contains a types
  838. unit so this would conflicts if D6 programms are compiled
  839. + Willamette/SSE2 instructions to assembler added
  840. Revision 1.29 2002/07/19 11:41:35 daniel
  841. * State tracker work
  842. * The whilen and repeatn are now completely unified into whilerepeatn. This
  843. allows the state tracker to change while nodes automatically into
  844. repeat nodes.
  845. * Resulttypepass improvements to the notn. 'not not a' is optimized away and
  846. 'not(a>b)' is optimized into 'a<=b'.
  847. * Resulttypepass improvements to the whilerepeatn. 'while not a' is optimized
  848. by removing the notn and later switchting the true and falselabels. The
  849. same is done with 'repeat until not a'.
  850. Revision 1.28 2002/07/14 18:00:43 daniel
  851. + Added the beginning of a state tracker. This will track the values of
  852. variables through procedures and optimize things away.
  853. Revision 1.27 2002/07/01 18:46:22 peter
  854. * internal linker
  855. * reorganized aasm layer
  856. Revision 1.26 2002/06/24 12:43:00 jonas
  857. * fixed errors found with new -CR code from Peter when cycling with -O2p3r
  858. Revision 1.25 2002/05/18 13:34:09 peter
  859. * readded missing revisions
  860. Revision 1.24 2002/05/16 19:46:37 carl
  861. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  862. + try to fix temp allocation (still in ifdef)
  863. + generic constructor calls
  864. + start of tassembler / tmodulebase class cleanup
  865. Revision 1.22 2002/04/23 19:16:34 peter
  866. * add pinline unit that inserts compiler supported functions using
  867. one or more statements
  868. * moved finalize and setlength from ninl to pinline
  869. Revision 1.21 2002/04/21 19:02:03 peter
  870. * removed newn and disposen nodes, the code is now directly
  871. inlined from pexpr
  872. * -an option that will write the secondpass nodes to the .s file, this
  873. requires EXTDEBUG define to actually write the info
  874. * fixed various internal errors and crashes due recent code changes
  875. Revision 1.20 2002/04/04 19:05:57 peter
  876. * removed unused units
  877. * use tlocation.size in cg.a_*loc*() routines
  878. Revision 1.19 2002/03/31 20:26:33 jonas
  879. + a_loadfpu_* and a_loadmm_* methods in tcg
  880. * register allocation is now handled by a class and is mostly processor
  881. independent (+rgobj.pas and i386/rgcpu.pas)
  882. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  883. * some small improvements and fixes to the optimizer
  884. * some register allocation fixes
  885. * some fpuvaroffset fixes in the unary minus node
  886. * push/popusedregisters is now called rg.save/restoreusedregisters and
  887. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  888. also better optimizable)
  889. * fixed and optimized register saving/restoring for new/dispose nodes
  890. * LOC_FPU locations now also require their "register" field to be set to
  891. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  892. - list field removed of the tnode class because it's not used currently
  893. and can cause hard-to-find bugs
  894. }