nbas.pas 44 KB

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