nbas.pas 44 KB

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