nbas.pas 37 KB

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