nbas.pas 41 KB

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