nbas.pas 42 KB

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