nbas.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. This unit implements some basic nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nbas;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cpuinfo,cpubase,cgbase,cgutils,
  23. aasmbase,aasmtai,aasmdata,aasmcpu,
  24. node,
  25. symtype;
  26. type
  27. tnothingnode = class(tnode)
  28. constructor create;virtual;
  29. function pass_1 : tnode;override;
  30. function pass_typecheck: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 pass_typecheck:tnode;override;
  37. procedure mark_write;override;
  38. end;
  39. terrornodeclass = class of terrornode;
  40. tasmnode = class(tnode)
  41. p_asm : TAsmList;
  42. currenttai : tai;
  43. { Used registers in assembler block }
  44. used_regs_int,
  45. used_regs_fpu : tcpuregisterset;
  46. constructor create(p : TAsmList);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 dogetcopy : tnode;override;
  54. function pass_1 : tnode;override;
  55. function pass_typecheck: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 simplify : tnode; override;
  62. function pass_1 : tnode;override;
  63. function pass_typecheck:tnode;override;
  64. procedure printnodetree(var t:text);override;
  65. property statement : tnode read left write left;
  66. property next : tnode read right write right;
  67. end;
  68. tstatementnodeclass = class of tstatementnode;
  69. tblocknode = class(tunarynode)
  70. constructor create(l : tnode);virtual;
  71. destructor destroy; override;
  72. function simplify : tnode; override;
  73. function pass_1 : tnode;override;
  74. function pass_typecheck:tnode;override;
  75. {$ifdef state_tracking}
  76. function track_state_pass(exec_known:boolean):boolean;override;
  77. {$endif state_tracking}
  78. property statements : tnode read left write left;
  79. end;
  80. tblocknodeclass = class of tblocknode;
  81. ttempcreatenode = class;
  82. ttempinfoflag = (ti_may_be_in_reg,ti_valid,ti_nextref_set_hookoncopy_nil,ti_is_inlined_result,
  83. ti_addr_taken);
  84. ttempinfoflags = set of ttempinfoflag;
  85. const
  86. tempinfostoreflags = [ti_may_be_in_reg,ti_is_inlined_result,ti_addr_taken];
  87. type
  88. { to allow access to the location by temp references even after the temp has }
  89. { already been disposed and to make sure the coherency between temps and }
  90. { temp references is kept after a getcopy }
  91. ptempinfo = ^ttempinfo;
  92. ttempinfo = record
  93. { set to the copy of a tempcreate pnode (if it gets copied) so that the }
  94. { refs and deletenode can hook to this copy once they get copied too }
  95. hookoncopy : ptempinfo;
  96. typedef : tdef;
  97. typedefderef : tderef;
  98. temptype : ttemptype;
  99. owner : ttempcreatenode;
  100. withnode : tnode;
  101. location : tlocation;
  102. flags : ttempinfoflags;
  103. end;
  104. { a node which will create a (non)persistent temp of a given type with a given }
  105. { size (the size is separate to allow creating "void" temps with a custom size) }
  106. ttempcreatenode = class(tnode)
  107. size: aint;
  108. tempinfo: ptempinfo;
  109. { * persistent temps are used in manually written code where the temp }
  110. { be usable among different statements and where you can manually say }
  111. { when the temp has to be freed (using a ttempdeletenode) }
  112. { * non-persistent temps are mostly used in typeconversion helpers, }
  113. { where the node that receives the temp becomes responsible for }
  114. { freeing it. In this last case, you must use only one reference }
  115. { to it and *not* generate a ttempdeletenode }
  116. constructor create(_typedef: tdef; _size: aint; _temptype: ttemptype;allowreg:boolean); virtual;
  117. constructor create_withnode(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean; withnode: tnode); virtual;
  118. constructor create_inlined_result(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean); virtual;
  119. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  120. procedure ppuwrite(ppufile:tcompilerppufile);override;
  121. procedure buildderefimpl;override;
  122. procedure derefimpl;override;
  123. procedure derefnode;override;
  124. function dogetcopy: tnode; override;
  125. function pass_1 : tnode; override;
  126. function pass_typecheck: tnode; override;
  127. function docompare(p: tnode): boolean; override;
  128. procedure printnodedata(var t:text);override;
  129. end;
  130. ttempcreatenodeclass = class of ttempcreatenode;
  131. { a node which is a reference to a certain temp }
  132. ttemprefnode = class(tnode)
  133. tempinfo: ptempinfo;
  134. constructor create(const temp: ttempcreatenode); virtual;
  135. constructor create_offset(const temp: ttempcreatenode;aoffset:longint);
  136. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  137. procedure ppuwrite(ppufile:tcompilerppufile);override;
  138. function dogetcopy: tnode; override;
  139. procedure derefnode;override;
  140. function pass_1 : tnode; override;
  141. function pass_typecheck : tnode; override;
  142. procedure mark_write;override;
  143. function docompare(p: tnode): boolean; override;
  144. procedure printnodedata(var t:text);override;
  145. protected
  146. offset : longint;
  147. private
  148. tempidx : longint;
  149. end;
  150. ttemprefnodeclass = class of ttemprefnode;
  151. { a node which removes a temp }
  152. ttempdeletenode = class(tnode)
  153. tempinfo: ptempinfo;
  154. constructor create(const temp: ttempcreatenode); virtual;
  155. { this will convert the persistant temp to a normal temp
  156. for returning to the other nodes }
  157. constructor create_normal_temp(const temp: ttempcreatenode);
  158. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  159. procedure ppuwrite(ppufile:tcompilerppufile);override;
  160. function dogetcopy: tnode; override;
  161. procedure derefnode;override;
  162. function pass_1: tnode; override;
  163. function pass_typecheck: tnode; override;
  164. function docompare(p: tnode): boolean; override;
  165. destructor destroy; override;
  166. procedure printnodedata(var t:text);override;
  167. protected
  168. release_to_normal : boolean;
  169. private
  170. tempidx : longint;
  171. end;
  172. ttempdeletenodeclass = class of ttempdeletenode;
  173. var
  174. cnothingnode : tnothingnodeclass;
  175. cerrornode : terrornodeclass;
  176. casmnode : tasmnodeclass;
  177. cstatementnode : tstatementnodeclass;
  178. cblocknode : tblocknodeclass;
  179. ctempcreatenode : ttempcreatenodeclass;
  180. ctemprefnode : ttemprefnodeclass;
  181. ctempdeletenode : ttempdeletenodeclass;
  182. { Create a blocknode and statement node for multiple statements
  183. generated internally by the parser }
  184. function internalstatements(var laststatement:tstatementnode):tblocknode;
  185. function laststatement(block:tblocknode):tstatementnode;
  186. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  187. implementation
  188. uses
  189. cutils,
  190. verbose,globals,systems,
  191. symconst,symdef,defutil,defcmp,
  192. pass_1,
  193. nutils,nld,ncal,nflw,
  194. procinfo
  195. ;
  196. {*****************************************************************************
  197. Helpers
  198. *****************************************************************************}
  199. function internalstatements(var laststatement:tstatementnode):tblocknode;
  200. begin
  201. { create dummy initial statement }
  202. laststatement := cstatementnode.create(cnothingnode.create,nil);
  203. internalstatements := cblocknode.create(laststatement);
  204. end;
  205. function laststatement(block:tblocknode):tstatementnode;
  206. begin
  207. result:=tstatementnode(block.left);
  208. while assigned(result) and assigned(result.right) do
  209. result:=tstatementnode(result.right);
  210. end;
  211. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  212. begin
  213. if assigned(laststatement.right) then
  214. internalerror(200204201);
  215. laststatement.right:=cstatementnode.create(n,nil);
  216. laststatement:=tstatementnode(laststatement.right);
  217. end;
  218. {*****************************************************************************
  219. TFIRSTNOTHING
  220. *****************************************************************************}
  221. constructor tnothingnode.create;
  222. begin
  223. inherited create(nothingn);
  224. end;
  225. function tnothingnode.pass_typecheck:tnode;
  226. begin
  227. result:=nil;
  228. resultdef:=voidtype;
  229. end;
  230. function tnothingnode.pass_1 : tnode;
  231. begin
  232. result:=nil;
  233. expectloc:=LOC_VOID;
  234. end;
  235. {*****************************************************************************
  236. TFIRSTERROR
  237. *****************************************************************************}
  238. constructor terrornode.create;
  239. begin
  240. inherited create(errorn);
  241. end;
  242. function terrornode.pass_typecheck:tnode;
  243. begin
  244. result:=nil;
  245. include(flags,nf_error);
  246. codegenerror:=true;
  247. resultdef:=generrordef;
  248. end;
  249. function terrornode.pass_1 : tnode;
  250. begin
  251. result:=nil;
  252. expectloc:=LOC_VOID;
  253. codegenerror:=true;
  254. end;
  255. procedure terrornode.mark_write;
  256. begin
  257. end;
  258. {*****************************************************************************
  259. TSTATEMENTNODE
  260. *****************************************************************************}
  261. constructor tstatementnode.create(l,r : tnode);
  262. begin
  263. inherited create(statementn,l,r);
  264. end;
  265. function is_exit_statement(var n: tnode; arg: pointer): foreachnoderesult;
  266. begin
  267. if (n.nodetype<>exitn) then
  268. result:=fen_false
  269. else
  270. result:=fen_norecurse_true;
  271. end;
  272. function no_exit_statement_in_block(n: tnode): boolean;
  273. begin
  274. result:=not foreachnodestatic(n,@is_exit_statement,nil);
  275. end;
  276. function tstatementnode.simplify : tnode;
  277. begin
  278. result:=nil;
  279. { these "optimizations" are only to make it more easy to recognise }
  280. { blocknodes which at the end of inlining only contain one single }
  281. { statement. Simplifying inside blocknode.simplify could be dangerous }
  282. { because if the main blocknode which makes up a procedure/function }
  283. { body were replaced with a statementn/nothingn, this could cause }
  284. { problems elsewhere in the compiler which expects a blocknode }
  285. { remove next statement if it's a nothing-statement (since if it's }
  286. { the last, it won't remove itself -- see next simplification) }
  287. while assigned(right) and
  288. (tstatementnode(right).left.nodetype = nothingn) do
  289. begin
  290. result:=tstatementnode(right).right;
  291. tstatementnode(right).right:=nil;
  292. right.free;
  293. right:=result;
  294. result:=nil;
  295. end;
  296. { Remove initial nothingn if there are other statements. If there }
  297. { are no other statements, returning nil doesn't help (will be }
  298. { interpreted as "can't be simplified") and replacing the }
  299. { statementnode with a nothingnode cannot be done (because it's }
  300. { possible this statementnode is a child of a blocknode, and }
  301. { blocknodes are expected to only contain statementnodes) }
  302. if (left.nodetype = nothingn) and
  303. assigned(right) then
  304. begin
  305. result:=right;
  306. right:=nil;
  307. exit;
  308. end;
  309. { if the current statement contains a block with one statement, }
  310. { replace the current statement with that block's statement }
  311. { (but only if the block does not have nf_block_with_exit set }
  312. { or has no exit statement, because otherwise it needs an own }
  313. { exit label, see tests/test/tinline10) }
  314. if (left.nodetype = blockn) and
  315. (not(nf_block_with_exit in left.flags) or
  316. no_exit_statement_in_block(left)) and
  317. assigned(tblocknode(left).left) and
  318. not assigned(tstatementnode(tblocknode(left).left).right) then
  319. begin
  320. result:=tblocknode(left).left;
  321. tstatementnode(result).right:=right;
  322. right:=nil;
  323. tblocknode(left).left:=nil;
  324. exit;
  325. end;
  326. end;
  327. function tstatementnode.pass_typecheck:tnode;
  328. begin
  329. result:=nil;
  330. resultdef:=voidtype;
  331. { left is the statement itself calln assignn or a complex one }
  332. typecheckpass(left);
  333. if (not (cs_extsyntax in current_settings.moduleswitches)) and
  334. assigned(left.resultdef) and
  335. not((left.nodetype=calln) and
  336. { don't complain when the value is used. And also not for constructors }
  337. ((cnf_return_value_used in tcallnode(left).callnodeflags) or
  338. (tcallnode(left).procdefinition.proctypeoption=potype_constructor))) and
  339. not(is_void(left.resultdef)) then
  340. CGMessage(parser_e_illegal_expression);
  341. if codegenerror then
  342. exit;
  343. { right is the next statement in the list }
  344. if assigned(right) then
  345. typecheckpass(right);
  346. if codegenerror then
  347. exit;
  348. end;
  349. function tstatementnode.pass_1 : tnode;
  350. begin
  351. result:=nil;
  352. { left is the statement itself calln assignn or a complex one }
  353. firstpass(left);
  354. if codegenerror then
  355. exit;
  356. expectloc:=left.expectloc;
  357. registersint:=left.registersint;
  358. registersfpu:=left.registersfpu;
  359. {$ifdef SUPPORT_MMX}
  360. registersmmx:=left.registersmmx;
  361. {$endif SUPPORT_MMX}
  362. { right is the next in the list }
  363. if assigned(right) then
  364. firstpass(right);
  365. if codegenerror then
  366. exit;
  367. end;
  368. procedure tstatementnode.printnodetree(var t:text);
  369. begin
  370. printnodelist(t);
  371. end;
  372. {*****************************************************************************
  373. TBLOCKNODE
  374. *****************************************************************************}
  375. constructor tblocknode.create(l : tnode);
  376. begin
  377. inherited create(blockn,l);
  378. end;
  379. destructor tblocknode.destroy;
  380. var
  381. hp, next: tstatementnode;
  382. begin
  383. hp := tstatementnode(left);
  384. left := nil;
  385. while assigned(hp) do
  386. begin
  387. next := tstatementnode(hp.right);
  388. hp.right := nil;
  389. hp.free;
  390. hp := next;
  391. end;
  392. inherited destroy;
  393. end;
  394. function tblocknode.simplify: tnode;
  395. begin
  396. result := nil;
  397. { Warning: never replace a blocknode with another node type, }
  398. { since the block may be the main block of a procedure/function/ }
  399. { main program body, and those nodes should always be blocknodes }
  400. { since that's what the compiler expects elsewhere. }
  401. { if the current block contains only one statement, and }
  402. { this one statement only contains another block, replace }
  403. { this block with that other block. }
  404. if assigned(left) and
  405. not assigned(tstatementnode(left).right) and
  406. (tstatementnode(left).left.nodetype = blockn) then
  407. begin
  408. result:=tstatementnode(left).left;
  409. tstatementnode(left).left:=nil;
  410. { make sure the nf_block_with_exit flag is safeguarded }
  411. result.flags:=result.flags+(flags * [nf_block_with_exit]);
  412. exit;
  413. end;
  414. end;
  415. function tblocknode.pass_typecheck:tnode;
  416. var
  417. hp : tstatementnode;
  418. begin
  419. result:=nil;
  420. resultdef:=voidtype;
  421. hp:=tstatementnode(left);
  422. while assigned(hp) do
  423. begin
  424. if assigned(hp.left) then
  425. begin
  426. codegenerror:=false;
  427. typecheckpass(hp.left);
  428. if not(codegenerror) and
  429. not(cs_extsyntax in current_settings.moduleswitches) and
  430. (hp.left.nodetype=calln) and
  431. not(is_void(hp.left.resultdef)) and
  432. not(cnf_return_value_used in tcallnode(hp.left).callnodeflags) and
  433. not((tcallnode(hp.left).procdefinition.proctypeoption=potype_constructor) and
  434. assigned(tprocdef(tcallnode(hp.left).procdefinition)._class) and
  435. is_object(tprocdef(tcallnode(hp.left).procdefinition)._class)) then
  436. CGMessagePos(hp.left.fileinfo,parser_e_illegal_expression);
  437. { the resultdef of the block is the last type that is
  438. returned. Normally this is a voidtype. But when the
  439. compiler inserts a block of multiple statements then the
  440. last entry can return a value }
  441. resultdef:=hp.left.resultdef;
  442. end;
  443. hp:=tstatementnode(hp.right);
  444. end;
  445. end;
  446. function tblocknode.pass_1 : tnode;
  447. var
  448. hp : tstatementnode;
  449. count : longint;
  450. begin
  451. result:=nil;
  452. expectloc:=LOC_VOID;
  453. count:=0;
  454. hp:=tstatementnode(left);
  455. while assigned(hp) do
  456. begin
  457. if assigned(hp.left) then
  458. begin
  459. codegenerror:=false;
  460. firstpass(hp.left);
  461. hp.expectloc:=hp.left.expectloc;
  462. hp.registersint:=hp.left.registersint;
  463. hp.registersfpu:=hp.left.registersfpu;
  464. {$ifdef SUPPORT_MMX}
  465. hp.registersmmx:=hp.left.registersmmx;
  466. {$endif SUPPORT_MMX}
  467. end
  468. else
  469. hp.registersint:=0;
  470. if hp.registersint>registersint then
  471. registersint:=hp.registersint;
  472. if hp.registersfpu>registersfpu then
  473. registersfpu:=hp.registersfpu;
  474. {$ifdef SUPPORT_MMX}
  475. if hp.registersmmx>registersmmx then
  476. registersmmx:=hp.registersmmx;
  477. {$endif}
  478. expectloc:=hp.expectloc;
  479. inc(count);
  480. hp:=tstatementnode(hp.right);
  481. end;
  482. end;
  483. {$ifdef state_tracking}
  484. function Tblocknode.track_state_pass(exec_known:boolean):boolean;
  485. var hp:Tstatementnode;
  486. begin
  487. track_state_pass:=false;
  488. hp:=Tstatementnode(left);
  489. while assigned(hp) do
  490. begin
  491. if hp.left.track_state_pass(exec_known) then
  492. track_state_pass:=true;
  493. hp:=Tstatementnode(hp.right);
  494. end;
  495. end;
  496. {$endif state_tracking}
  497. {*****************************************************************************
  498. TASMNODE
  499. *****************************************************************************}
  500. constructor tasmnode.create(p : TAsmList);
  501. begin
  502. inherited create(asmn);
  503. p_asm:=p;
  504. currenttai:=nil;
  505. used_regs_int:=[];
  506. used_regs_fpu:=[];
  507. end;
  508. constructor tasmnode.create_get_position;
  509. begin
  510. inherited create(asmn);
  511. p_asm:=nil;
  512. include(flags,nf_get_asm_position);
  513. currenttai:=nil;
  514. end;
  515. destructor tasmnode.destroy;
  516. begin
  517. if assigned(p_asm) then
  518. p_asm.free;
  519. inherited destroy;
  520. end;
  521. constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  522. var
  523. hp : tai;
  524. begin
  525. inherited ppuload(t,ppufile);
  526. if not(nf_get_asm_position in flags) then
  527. begin
  528. p_asm:=TAsmList.create;
  529. repeat
  530. hp:=ppuloadai(ppufile);
  531. if hp=nil then
  532. break;
  533. p_asm.concat(hp);
  534. until false;
  535. end
  536. else
  537. p_asm:=nil;
  538. currenttai:=nil;
  539. end;
  540. procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
  541. var
  542. hp : tai;
  543. begin
  544. inherited ppuwrite(ppufile);
  545. {$warning FIXME Add saving of register sets}
  546. if not(nf_get_asm_position in flags) then
  547. begin
  548. hp:=tai(p_asm.first);
  549. while assigned(hp) do
  550. begin
  551. ppuwriteai(ppufile,hp);
  552. hp:=tai(hp.next);
  553. end;
  554. { end is marked by a nil }
  555. ppuwriteai(ppufile,nil);
  556. end;
  557. end;
  558. procedure tasmnode.buildderefimpl;
  559. var
  560. hp : tai;
  561. begin
  562. inherited buildderefimpl;
  563. if not(nf_get_asm_position in flags) then
  564. begin
  565. hp:=tai(p_asm.first);
  566. while assigned(hp) do
  567. begin
  568. hp.buildderefimpl;
  569. hp:=tai(hp.next);
  570. end;
  571. end;
  572. end;
  573. procedure tasmnode.derefimpl;
  574. var
  575. hp : tai;
  576. begin
  577. inherited derefimpl;
  578. if not(nf_get_asm_position in flags) then
  579. begin
  580. hp:=tai(p_asm.first);
  581. while assigned(hp) do
  582. begin
  583. hp.derefimpl;
  584. hp:=tai(hp.next);
  585. end;
  586. end;
  587. end;
  588. function tasmnode.dogetcopy: tnode;
  589. var
  590. n: tasmnode;
  591. begin
  592. n := tasmnode(inherited dogetcopy);
  593. if assigned(p_asm) then
  594. begin
  595. n.p_asm:=TAsmList.create;
  596. n.p_asm.concatlistcopy(p_asm);
  597. end
  598. else n.p_asm := nil;
  599. n.currenttai:=currenttai;
  600. result:=n;
  601. end;
  602. function tasmnode.pass_typecheck:tnode;
  603. begin
  604. result:=nil;
  605. resultdef:=voidtype;
  606. if not(nf_get_asm_position in flags) then
  607. include(current_procinfo.flags,pi_has_assembler_block);
  608. end;
  609. function tasmnode.pass_1 : tnode;
  610. begin
  611. result:=nil;
  612. expectloc:=LOC_VOID;
  613. end;
  614. function tasmnode.docompare(p: tnode): boolean;
  615. begin
  616. { comparing of asmlists is not implemented (JM) }
  617. docompare := false;
  618. end;
  619. {*****************************************************************************
  620. TEMPCREATENODE
  621. *****************************************************************************}
  622. constructor ttempcreatenode.create(_typedef:tdef; _size: aint; _temptype: ttemptype;allowreg:boolean);
  623. begin
  624. inherited create(tempcreaten);
  625. size := _size;
  626. new(tempinfo);
  627. fillchar(tempinfo^,sizeof(tempinfo^),0);
  628. tempinfo^.typedef := _typedef;
  629. tempinfo^.temptype := _temptype;
  630. tempinfo^.owner := self;
  631. tempinfo^.withnode := nil;
  632. if allowreg and
  633. { temp must fit a single register }
  634. (tstoreddef(_typedef).is_fpuregable or
  635. (tstoreddef(_typedef).is_intregable and
  636. (_size<=TCGSize2Size[OS_64]))) and
  637. { size of register operations must be known }
  638. (def_cgsize(_typedef)<>OS_NO) and
  639. { no init/final needed }
  640. not (_typedef.needs_inittable) and
  641. ((_typedef.typ <> pointerdef) or
  642. (is_object(tpointerdef(_typedef).pointeddef) or
  643. not tpointerdef(_typedef).pointeddef.needs_inittable)) then
  644. include(tempinfo^.flags,ti_may_be_in_reg);
  645. end;
  646. constructor ttempcreatenode.create_withnode(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean; withnode: tnode);
  647. begin
  648. self.create(_typedef,_size,_temptype,allowreg);
  649. tempinfo^.withnode:=withnode.getcopy;
  650. end;
  651. constructor ttempcreatenode.create_inlined_result(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean);
  652. begin
  653. self.create(_typedef,_size,_temptype,allowreg);
  654. include(tempinfo^.flags,ti_is_inlined_result);
  655. end;
  656. function ttempcreatenode.dogetcopy: tnode;
  657. var
  658. n: ttempcreatenode;
  659. begin
  660. n := ttempcreatenode(inherited dogetcopy);
  661. n.size := size;
  662. new(n.tempinfo);
  663. fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
  664. n.tempinfo^.owner:=n;
  665. n.tempinfo^.typedef := tempinfo^.typedef;
  666. n.tempinfo^.temptype := tempinfo^.temptype;
  667. n.tempinfo^.flags := tempinfo^.flags * tempinfostoreflags;
  668. if assigned(tempinfo^.withnode) then
  669. n.tempinfo^.withnode := tempinfo^.withnode.getcopy
  670. else
  671. n.tempinfo^.withnode := nil;
  672. { when the tempinfo has already a hookoncopy then it is not
  673. reset by a tempdeletenode }
  674. if assigned(tempinfo^.hookoncopy) then
  675. internalerror(200211262);
  676. { signal the temprefs that the temp they point to has been copied, }
  677. { so that if the refs get copied as well, they can hook themselves }
  678. { to the copy of the temp }
  679. tempinfo^.hookoncopy := n.tempinfo;
  680. exclude(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
  681. result := n;
  682. end;
  683. constructor ttempcreatenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  684. begin
  685. inherited ppuload(t,ppufile);
  686. size:=ppufile.getlongint;
  687. new(tempinfo);
  688. fillchar(tempinfo^,sizeof(tempinfo^),0);
  689. ppufile.getsmallset(tempinfo^.flags);
  690. ppufile.getderef(tempinfo^.typedefderef);
  691. tempinfo^.temptype := ttemptype(ppufile.getbyte);
  692. tempinfo^.owner:=self;
  693. tempinfo^.withnode:=ppuloadnode(ppufile);
  694. end;
  695. procedure ttempcreatenode.ppuwrite(ppufile:tcompilerppufile);
  696. begin
  697. inherited ppuwrite(ppufile);
  698. ppufile.putlongint(size);
  699. ppufile.putsmallset(tempinfo^.flags);
  700. ppufile.putderef(tempinfo^.typedefderef);
  701. ppufile.putbyte(byte(tempinfo^.temptype));
  702. ppuwritenode(ppufile,tempinfo^.withnode);
  703. end;
  704. procedure ttempcreatenode.buildderefimpl;
  705. begin
  706. inherited buildderefimpl;
  707. tempinfo^.typedefderef.build(tempinfo^.typedef);
  708. if assigned(tempinfo^.withnode) then
  709. tempinfo^.withnode.buildderefimpl;
  710. end;
  711. procedure ttempcreatenode.derefimpl;
  712. begin
  713. inherited derefimpl;
  714. tempinfo^.typedef:=tdef(tempinfo^.typedefderef.resolve);
  715. if assigned(tempinfo^.withnode) then
  716. tempinfo^.withnode.derefimpl;
  717. end;
  718. procedure ttempcreatenode.derefnode;
  719. begin
  720. inherited derefnode;
  721. if assigned(tempinfo^.withnode) then
  722. tempinfo^.withnode.derefnode;
  723. end;
  724. function ttempcreatenode.pass_1 : tnode;
  725. begin
  726. result := nil;
  727. expectloc:=LOC_VOID;
  728. if (tempinfo^.typedef.needs_inittable) then
  729. include(current_procinfo.flags,pi_needs_implicit_finally);
  730. if assigned(tempinfo^.withnode) then
  731. firstpass(tempinfo^.withnode);
  732. end;
  733. function ttempcreatenode.pass_typecheck: tnode;
  734. begin
  735. result := nil;
  736. { a tempcreatenode doesn't have a resultdef, only temprefnodes do }
  737. resultdef := voidtype;
  738. if assigned(tempinfo^.withnode) then
  739. typecheckpass(tempinfo^.withnode);
  740. end;
  741. function ttempcreatenode.docompare(p: tnode): boolean;
  742. begin
  743. result :=
  744. inherited docompare(p) and
  745. (ttempcreatenode(p).size = size) and
  746. (ttempcreatenode(p).tempinfo^.flags*tempinfostoreflags=tempinfo^.flags*tempinfostoreflags) and
  747. (ttempcreatenode(p).tempinfo^.withnode.isequal(tempinfo^.withnode)) and
  748. equal_defs(ttempcreatenode(p).tempinfo^.typedef,tempinfo^.typedef);
  749. end;
  750. procedure ttempcreatenode.printnodedata(var t:text);
  751. begin
  752. inherited printnodedata(t);
  753. writeln(t,printnodeindention,'size = ',size,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  754. end;
  755. {*****************************************************************************
  756. TEMPREFNODE
  757. *****************************************************************************}
  758. constructor ttemprefnode.create(const temp: ttempcreatenode);
  759. begin
  760. inherited create(temprefn);
  761. tempinfo := temp.tempinfo;
  762. offset:=0;
  763. end;
  764. constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
  765. begin
  766. self.create(temp);
  767. offset := aoffset;
  768. end;
  769. function ttemprefnode.dogetcopy: tnode;
  770. var
  771. n: ttemprefnode;
  772. begin
  773. n := ttemprefnode(inherited dogetcopy);
  774. n.offset := offset;
  775. if assigned(tempinfo^.hookoncopy) then
  776. { if the temp has been copied, assume it becomes a new }
  777. { temp which has to be hooked by the copied reference }
  778. begin
  779. { hook the ref to the copied temp }
  780. n.tempinfo := tempinfo^.hookoncopy;
  781. { if we passed a ttempdeletenode that changed the temp }
  782. { from a persistent one into a normal one, we must be }
  783. { the last reference (since our parent should free the }
  784. { temp (JM) }
  785. if (ti_nextref_set_hookoncopy_nil in tempinfo^.flags) then
  786. tempinfo^.hookoncopy := nil;
  787. end
  788. else
  789. { if the temp we refer to hasn't been copied, assume }
  790. { we're just a new reference to that temp }
  791. begin
  792. n.tempinfo := tempinfo;
  793. end;
  794. if not assigned(n.tempinfo) then
  795. internalerror(2005071901);
  796. result := n;
  797. end;
  798. constructor ttemprefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  799. begin
  800. inherited ppuload(t,ppufile);
  801. tempidx:=ppufile.getlongint;
  802. offset:=ppufile.getlongint;
  803. end;
  804. procedure ttemprefnode.ppuwrite(ppufile:tcompilerppufile);
  805. begin
  806. inherited ppuwrite(ppufile);
  807. ppufile.putlongint(tempinfo^.owner.ppuidx);
  808. ppufile.putlongint(offset);
  809. end;
  810. procedure ttemprefnode.derefnode;
  811. var
  812. temp : ttempcreatenode;
  813. begin
  814. inherited derefnode;
  815. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  816. if temp.nodetype<>tempcreaten then
  817. internalerror(200311075);
  818. tempinfo:=temp.tempinfo;
  819. end;
  820. function ttemprefnode.pass_1 : tnode;
  821. begin
  822. expectloc := LOC_REFERENCE;
  823. if not tempinfo^.typedef.needs_inittable and
  824. (ti_may_be_in_reg in tempinfo^.flags) then
  825. begin
  826. if tempinfo^.typedef.typ=floatdef then
  827. begin
  828. if (tempinfo^.temptype = tt_persistent) then
  829. expectloc := LOC_CFPUREGISTER
  830. else
  831. expectloc := LOC_FPUREGISTER;
  832. end
  833. else
  834. begin
  835. if (tempinfo^.temptype = tt_persistent) then
  836. expectloc := LOC_CREGISTER
  837. else
  838. expectloc := LOC_REGISTER;
  839. end;
  840. end;
  841. result := nil;
  842. end;
  843. function ttemprefnode.pass_typecheck: tnode;
  844. begin
  845. { check if the temp is already resultdef passed }
  846. if not assigned(tempinfo^.typedef) then
  847. internalerror(200108233);
  848. result := nil;
  849. resultdef := tempinfo^.typedef;
  850. end;
  851. function ttemprefnode.docompare(p: tnode): boolean;
  852. begin
  853. result :=
  854. inherited docompare(p) and
  855. (ttemprefnode(p).tempinfo = tempinfo) and
  856. (ttemprefnode(p).offset = offset);
  857. end;
  858. procedure Ttemprefnode.mark_write;
  859. begin
  860. include(flags,nf_write);
  861. end;
  862. procedure ttemprefnode.printnodedata(var t:text);
  863. begin
  864. inherited printnodedata(t);
  865. writeln(t,printnodeindention,'temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  866. end;
  867. {*****************************************************************************
  868. TEMPDELETENODE
  869. *****************************************************************************}
  870. constructor ttempdeletenode.create(const temp: ttempcreatenode);
  871. begin
  872. inherited create(tempdeleten);
  873. tempinfo := temp.tempinfo;
  874. release_to_normal := false;
  875. end;
  876. constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
  877. begin
  878. inherited create(tempdeleten);
  879. tempinfo := temp.tempinfo;
  880. release_to_normal := true;
  881. if tempinfo^.temptype <> tt_persistent then
  882. internalerror(200204211);
  883. end;
  884. function ttempdeletenode.dogetcopy: tnode;
  885. var
  886. n: ttempdeletenode;
  887. begin
  888. n:=ttempdeletenode(inherited dogetcopy);
  889. n.release_to_normal:=release_to_normal;
  890. if assigned(tempinfo^.hookoncopy) then
  891. { if the temp has been copied, assume it becomes a new }
  892. { temp which has to be hooked by the copied deletenode }
  893. begin
  894. { hook the tempdeletenode to the copied temp }
  895. n.tempinfo:=tempinfo^.hookoncopy;
  896. { the temp shall not be used, reset hookoncopy }
  897. { Only if release_to_normal is false, otherwise }
  898. { the temp can still be referenced once more (JM) }
  899. if (not release_to_normal) then
  900. tempinfo^.hookoncopy:=nil
  901. else
  902. include(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
  903. end
  904. else
  905. { if the temp we refer to hasn't been copied, we have a }
  906. { problem since that means we now have two delete nodes }
  907. { for one temp }
  908. internalerror(200108234);
  909. result:=n;
  910. end;
  911. constructor ttempdeletenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  912. begin
  913. inherited ppuload(t,ppufile);
  914. tempidx:=ppufile.getlongint;
  915. release_to_normal:=(ppufile.getbyte<>0);
  916. end;
  917. procedure ttempdeletenode.ppuwrite(ppufile:tcompilerppufile);
  918. begin
  919. inherited ppuwrite(ppufile);
  920. ppufile.putlongint(tempinfo^.owner.ppuidx);
  921. ppufile.putbyte(byte(release_to_normal));
  922. end;
  923. procedure ttempdeletenode.derefnode;
  924. var
  925. temp : ttempcreatenode;
  926. begin
  927. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  928. if temp.nodetype<>tempcreaten then
  929. internalerror(200311075);
  930. tempinfo:=temp.tempinfo;
  931. end;
  932. function ttempdeletenode.pass_1 : tnode;
  933. begin
  934. expectloc:=LOC_VOID;
  935. result := nil;
  936. end;
  937. function ttempdeletenode.pass_typecheck: tnode;
  938. begin
  939. result := nil;
  940. resultdef := voidtype;
  941. end;
  942. function ttempdeletenode.docompare(p: tnode): boolean;
  943. begin
  944. result :=
  945. inherited docompare(p) and
  946. (ttemprefnode(p).tempinfo = tempinfo);
  947. end;
  948. destructor ttempdeletenode.destroy;
  949. begin
  950. if assigned(tempinfo^.withnode) then
  951. begin
  952. tempinfo^.withnode.free;
  953. end;
  954. dispose(tempinfo);
  955. end;
  956. procedure ttempdeletenode.printnodedata(var t:text);
  957. begin
  958. inherited printnodedata(t);
  959. writeln(t,printnodeindention,'release_to_normal: ',release_to_normal,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  960. end;
  961. begin
  962. cnothingnode:=tnothingnode;
  963. cerrornode:=terrornode;
  964. casmnode:=tasmnode;
  965. cstatementnode:=tstatementnode;
  966. cblocknode:=tblocknode;
  967. ctempcreatenode:=ttempcreatenode;
  968. ctemprefnode:=ttemprefnode;
  969. ctempdeletenode:=ttempdeletenode;
  970. end.