nbas.pas 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  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. 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 tstatementnode.simplify : tnode;
  266. begin
  267. result:=nil;
  268. { these "optimizations" are only to make it more easy to recognise }
  269. { blocknodes which at the end of inlining only contain one single }
  270. { statement. Simplifying inside blocknode.simplify could be dangerous }
  271. { because if the main blocknode which makes up a procedure/function }
  272. { body were replaced with a statementn/nothingn, this could cause }
  273. { problems elsewhere in the compiler which expects a blocknode }
  274. { remove next statement if it's a nothing-statement (since if it's }
  275. { the last, it won't remove itself -- see next simplification) }
  276. while assigned(right) and
  277. (tstatementnode(right).left.nodetype = nothingn) do
  278. begin
  279. result:=tstatementnode(right).right;
  280. tstatementnode(right).right:=nil;
  281. right.free;
  282. right:=result;
  283. result:=nil;
  284. end;
  285. { Remove initial nothingn if there are other statements. If there }
  286. { are no other statements, returning nil doesn't help (will be }
  287. { interpreted as "can't be simplified") and replacing the }
  288. { statementnode with a nothingnode cannot be done (because it's }
  289. { possible this statementnode is a child of a blocknode, and }
  290. { blocknodes are expected to only contain statementnodes) }
  291. if (left.nodetype = nothingn) and
  292. assigned(right) then
  293. begin
  294. result:=right;
  295. right:=nil;
  296. exit;
  297. end;
  298. { if the current statement contains a block with one statement, }
  299. { replace the current statement with that block's statement }
  300. if (left.nodetype = blockn) and
  301. assigned(tblocknode(left).left) and
  302. not assigned(tstatementnode(tblocknode(left).left).right) then
  303. begin
  304. result:=tblocknode(left).left;
  305. tstatementnode(result).right:=right;
  306. right:=nil;
  307. tblocknode(left).left:=nil;
  308. exit;
  309. end;
  310. end;
  311. function tstatementnode.pass_typecheck:tnode;
  312. begin
  313. result:=nil;
  314. resultdef:=voidtype;
  315. { left is the statement itself calln assignn or a complex one }
  316. typecheckpass(left);
  317. if (not (cs_extsyntax in current_settings.moduleswitches)) and
  318. assigned(left.resultdef) and
  319. not((left.nodetype=calln) and
  320. { don't complain when funcretrefnode is set, because then the
  321. value is already used. And also not for constructors }
  322. (assigned(tcallnode(left).funcretnode) or
  323. (tcallnode(left).procdefinition.proctypeoption=potype_constructor))) and
  324. not(is_void(left.resultdef)) then
  325. CGMessage(parser_e_illegal_expression);
  326. if codegenerror then
  327. exit;
  328. { right is the next statement in the list }
  329. if assigned(right) then
  330. typecheckpass(right);
  331. if codegenerror then
  332. exit;
  333. end;
  334. function tstatementnode.pass_1 : tnode;
  335. begin
  336. result:=nil;
  337. { left is the statement itself calln assignn or a complex one }
  338. firstpass(left);
  339. if codegenerror then
  340. exit;
  341. expectloc:=left.expectloc;
  342. registersint:=left.registersint;
  343. registersfpu:=left.registersfpu;
  344. {$ifdef SUPPORT_MMX}
  345. registersmmx:=left.registersmmx;
  346. {$endif SUPPORT_MMX}
  347. { right is the next in the list }
  348. if assigned(right) then
  349. firstpass(right);
  350. if codegenerror then
  351. exit;
  352. end;
  353. procedure tstatementnode.printnodetree(var t:text);
  354. begin
  355. printnodelist(t);
  356. end;
  357. {*****************************************************************************
  358. TBLOCKNODE
  359. *****************************************************************************}
  360. constructor tblocknode.create(l : tnode);
  361. begin
  362. inherited create(blockn,l);
  363. end;
  364. destructor tblocknode.destroy;
  365. var
  366. hp, next: tstatementnode;
  367. begin
  368. hp := tstatementnode(left);
  369. left := nil;
  370. while assigned(hp) do
  371. begin
  372. next := tstatementnode(hp.right);
  373. hp.right := nil;
  374. hp.free;
  375. hp := next;
  376. end;
  377. inherited destroy;
  378. end;
  379. function tblocknode.simplify: tnode;
  380. begin
  381. result := nil;
  382. { Warning: never replace a blocknode with another node type, }
  383. { since the block may be the main block of a procedure/function/ }
  384. { main program body, and those nodes should always be blocknodes }
  385. { since that's what the compiler expects elsewhere. }
  386. { if the current block contains only one statement, and }
  387. { this one statement only contains another block, replace }
  388. { this block with that other block. }
  389. if assigned(left) and
  390. not assigned(tstatementnode(left).right) and
  391. (tstatementnode(left).left.nodetype = blockn) then
  392. begin
  393. result:=tstatementnode(left).left;
  394. tstatementnode(left).left:=nil;
  395. exit;
  396. end;
  397. end;
  398. function tblocknode.pass_typecheck:tnode;
  399. var
  400. hp : tstatementnode;
  401. begin
  402. result:=nil;
  403. resultdef:=voidtype;
  404. hp:=tstatementnode(left);
  405. while assigned(hp) do
  406. begin
  407. if assigned(hp.left) then
  408. begin
  409. codegenerror:=false;
  410. typecheckpass(hp.left);
  411. if not(codegenerror) and
  412. not(cs_extsyntax in current_settings.moduleswitches) and
  413. (hp.left.nodetype=calln) and
  414. not(is_void(hp.left.resultdef)) and
  415. not(cnf_return_value_used in tcallnode(hp.left).callnodeflags) and
  416. not((tcallnode(hp.left).procdefinition.proctypeoption=potype_constructor) and
  417. assigned(tprocdef(tcallnode(hp.left).procdefinition)._class) and
  418. is_object(tprocdef(tcallnode(hp.left).procdefinition)._class)) then
  419. CGMessagePos(hp.left.fileinfo,parser_e_illegal_expression);
  420. { the resultdef of the block is the last type that is
  421. returned. Normally this is a voidtype. But when the
  422. compiler inserts a block of multiple statements then the
  423. last entry can return a value }
  424. resultdef:=hp.left.resultdef;
  425. end;
  426. hp:=tstatementnode(hp.right);
  427. end;
  428. end;
  429. function tblocknode.pass_1 : tnode;
  430. var
  431. hp : tstatementnode;
  432. count : longint;
  433. begin
  434. result:=nil;
  435. expectloc:=LOC_VOID;
  436. count:=0;
  437. hp:=tstatementnode(left);
  438. while assigned(hp) do
  439. begin
  440. if assigned(hp.left) then
  441. begin
  442. codegenerror:=false;
  443. firstpass(hp.left);
  444. hp.expectloc:=hp.left.expectloc;
  445. hp.registersint:=hp.left.registersint;
  446. hp.registersfpu:=hp.left.registersfpu;
  447. {$ifdef SUPPORT_MMX}
  448. hp.registersmmx:=hp.left.registersmmx;
  449. {$endif SUPPORT_MMX}
  450. end
  451. else
  452. hp.registersint:=0;
  453. if hp.registersint>registersint then
  454. registersint:=hp.registersint;
  455. if hp.registersfpu>registersfpu then
  456. registersfpu:=hp.registersfpu;
  457. {$ifdef SUPPORT_MMX}
  458. if hp.registersmmx>registersmmx then
  459. registersmmx:=hp.registersmmx;
  460. {$endif}
  461. expectloc:=hp.expectloc;
  462. inc(count);
  463. hp:=tstatementnode(hp.right);
  464. end;
  465. end;
  466. {$ifdef state_tracking}
  467. function Tblocknode.track_state_pass(exec_known:boolean):boolean;
  468. var hp:Tstatementnode;
  469. begin
  470. track_state_pass:=false;
  471. hp:=Tstatementnode(left);
  472. while assigned(hp) do
  473. begin
  474. if hp.left.track_state_pass(exec_known) then
  475. track_state_pass:=true;
  476. hp:=Tstatementnode(hp.right);
  477. end;
  478. end;
  479. {$endif state_tracking}
  480. {*****************************************************************************
  481. TASMNODE
  482. *****************************************************************************}
  483. constructor tasmnode.create(p : TAsmList);
  484. begin
  485. inherited create(asmn);
  486. p_asm:=p;
  487. currenttai:=nil;
  488. used_regs_int:=[];
  489. used_regs_fpu:=[];
  490. end;
  491. constructor tasmnode.create_get_position;
  492. begin
  493. inherited create(asmn);
  494. p_asm:=nil;
  495. include(flags,nf_get_asm_position);
  496. currenttai:=nil;
  497. end;
  498. destructor tasmnode.destroy;
  499. begin
  500. if assigned(p_asm) then
  501. p_asm.free;
  502. inherited destroy;
  503. end;
  504. constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  505. var
  506. hp : tai;
  507. begin
  508. inherited ppuload(t,ppufile);
  509. if not(nf_get_asm_position in flags) then
  510. begin
  511. p_asm:=TAsmList.create;
  512. repeat
  513. hp:=ppuloadai(ppufile);
  514. if hp=nil then
  515. break;
  516. p_asm.concat(hp);
  517. until false;
  518. end
  519. else
  520. p_asm:=nil;
  521. currenttai:=nil;
  522. end;
  523. procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
  524. var
  525. hp : tai;
  526. begin
  527. inherited ppuwrite(ppufile);
  528. {$warning FIXME Add saving of register sets}
  529. if not(nf_get_asm_position in flags) then
  530. begin
  531. hp:=tai(p_asm.first);
  532. while assigned(hp) do
  533. begin
  534. ppuwriteai(ppufile,hp);
  535. hp:=tai(hp.next);
  536. end;
  537. { end is marked by a nil }
  538. ppuwriteai(ppufile,nil);
  539. end;
  540. end;
  541. procedure tasmnode.buildderefimpl;
  542. var
  543. hp : tai;
  544. begin
  545. inherited buildderefimpl;
  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. hp.buildderefimpl;
  552. hp:=tai(hp.next);
  553. end;
  554. end;
  555. end;
  556. procedure tasmnode.derefimpl;
  557. var
  558. hp : tai;
  559. begin
  560. inherited derefimpl;
  561. if not(nf_get_asm_position in flags) then
  562. begin
  563. hp:=tai(p_asm.first);
  564. while assigned(hp) do
  565. begin
  566. hp.derefimpl;
  567. hp:=tai(hp.next);
  568. end;
  569. end;
  570. end;
  571. function tasmnode.dogetcopy: tnode;
  572. var
  573. n: tasmnode;
  574. begin
  575. n := tasmnode(inherited dogetcopy);
  576. if assigned(p_asm) then
  577. begin
  578. n.p_asm:=TAsmList.create;
  579. n.p_asm.concatlistcopy(p_asm);
  580. end
  581. else n.p_asm := nil;
  582. n.currenttai:=currenttai;
  583. result:=n;
  584. end;
  585. function tasmnode.pass_typecheck:tnode;
  586. begin
  587. result:=nil;
  588. resultdef:=voidtype;
  589. if not(nf_get_asm_position in flags) then
  590. include(current_procinfo.flags,pi_has_assembler_block);
  591. end;
  592. function tasmnode.pass_1 : tnode;
  593. begin
  594. result:=nil;
  595. expectloc:=LOC_VOID;
  596. end;
  597. function tasmnode.docompare(p: tnode): boolean;
  598. begin
  599. { comparing of asmlists is not implemented (JM) }
  600. docompare := false;
  601. end;
  602. {*****************************************************************************
  603. TEMPCREATENODE
  604. *****************************************************************************}
  605. constructor ttempcreatenode.create(_typedef:tdef; _size: aint; _temptype: ttemptype;allowreg:boolean);
  606. begin
  607. inherited create(tempcreaten);
  608. size := _size;
  609. new(tempinfo);
  610. fillchar(tempinfo^,sizeof(tempinfo^),0);
  611. tempinfo^.typedef := _typedef;
  612. tempinfo^.temptype := _temptype;
  613. tempinfo^.owner := self;
  614. tempinfo^.withnode := nil;
  615. if allowreg and
  616. { temp must fit a single register }
  617. (tstoreddef(_typedef).is_fpuregable or
  618. (tstoreddef(_typedef).is_intregable and
  619. (_size<=TCGSize2Size[OS_64]))) and
  620. { size of register operations must be known }
  621. (def_cgsize(_typedef)<>OS_NO) and
  622. { no init/final needed }
  623. not (_typedef.needs_inittable) and
  624. ((_typedef.typ <> pointerdef) or
  625. (is_object(tpointerdef(_typedef).pointeddef) or
  626. not tpointerdef(_typedef).pointeddef.needs_inittable)) then
  627. include(tempinfo^.flags,ti_may_be_in_reg);
  628. end;
  629. constructor ttempcreatenode.create_withnode(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean; withnode: tnode);
  630. begin
  631. self.create(_typedef,_size,_temptype,allowreg);
  632. tempinfo^.withnode:=withnode.getcopy;
  633. end;
  634. constructor ttempcreatenode.create_inlined_result(_typedef: tdef; _size: aint; _temptype: ttemptype; allowreg:boolean);
  635. begin
  636. self.create(_typedef,_size,_temptype,allowreg);
  637. include(tempinfo^.flags,ti_is_inlined_result);
  638. end;
  639. function ttempcreatenode.dogetcopy: tnode;
  640. var
  641. n: ttempcreatenode;
  642. begin
  643. n := ttempcreatenode(inherited dogetcopy);
  644. n.size := size;
  645. new(n.tempinfo);
  646. fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
  647. n.tempinfo^.owner:=n;
  648. n.tempinfo^.typedef := tempinfo^.typedef;
  649. n.tempinfo^.temptype := tempinfo^.temptype;
  650. n.tempinfo^.flags := tempinfo^.flags * tempinfostoreflags;
  651. if assigned(tempinfo^.withnode) then
  652. n.tempinfo^.withnode := tempinfo^.withnode.getcopy
  653. else
  654. n.tempinfo^.withnode := nil;
  655. { when the tempinfo has already a hookoncopy then it is not
  656. reset by a tempdeletenode }
  657. if assigned(tempinfo^.hookoncopy) then
  658. internalerror(200211262);
  659. { signal the temprefs that the temp they point to has been copied, }
  660. { so that if the refs get copied as well, they can hook themselves }
  661. { to the copy of the temp }
  662. tempinfo^.hookoncopy := n.tempinfo;
  663. exclude(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
  664. result := n;
  665. end;
  666. constructor ttempcreatenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  667. begin
  668. inherited ppuload(t,ppufile);
  669. size:=ppufile.getlongint;
  670. new(tempinfo);
  671. fillchar(tempinfo^,sizeof(tempinfo^),0);
  672. ppufile.getsmallset(tempinfo^.flags);
  673. ppufile.getderef(tempinfo^.typedefderef);
  674. tempinfo^.temptype := ttemptype(ppufile.getbyte);
  675. tempinfo^.owner:=self;
  676. tempinfo^.withnode:=ppuloadnode(ppufile);
  677. end;
  678. procedure ttempcreatenode.ppuwrite(ppufile:tcompilerppufile);
  679. begin
  680. inherited ppuwrite(ppufile);
  681. ppufile.putlongint(size);
  682. ppufile.putsmallset(tempinfo^.flags);
  683. ppufile.putderef(tempinfo^.typedefderef);
  684. ppufile.putbyte(byte(tempinfo^.temptype));
  685. ppuwritenode(ppufile,tempinfo^.withnode);
  686. end;
  687. procedure ttempcreatenode.buildderefimpl;
  688. begin
  689. inherited buildderefimpl;
  690. tempinfo^.typedefderef.build(tempinfo^.typedef);
  691. if assigned(tempinfo^.withnode) then
  692. tempinfo^.withnode.buildderefimpl;
  693. end;
  694. procedure ttempcreatenode.derefimpl;
  695. begin
  696. inherited derefimpl;
  697. tempinfo^.typedef:=tdef(tempinfo^.typedefderef.resolve);
  698. if assigned(tempinfo^.withnode) then
  699. tempinfo^.withnode.derefimpl;
  700. end;
  701. procedure ttempcreatenode.derefnode;
  702. begin
  703. inherited derefnode;
  704. if assigned(tempinfo^.withnode) then
  705. tempinfo^.withnode.derefnode;
  706. end;
  707. function ttempcreatenode.pass_1 : tnode;
  708. begin
  709. result := nil;
  710. expectloc:=LOC_VOID;
  711. if (tempinfo^.typedef.needs_inittable) then
  712. include(current_procinfo.flags,pi_needs_implicit_finally);
  713. if assigned(tempinfo^.withnode) then
  714. firstpass(tempinfo^.withnode);
  715. end;
  716. function ttempcreatenode.pass_typecheck: tnode;
  717. begin
  718. result := nil;
  719. { a tempcreatenode doesn't have a resultdef, only temprefnodes do }
  720. resultdef := voidtype;
  721. if assigned(tempinfo^.withnode) then
  722. typecheckpass(tempinfo^.withnode);
  723. end;
  724. function ttempcreatenode.docompare(p: tnode): boolean;
  725. begin
  726. result :=
  727. inherited docompare(p) and
  728. (ttempcreatenode(p).size = size) and
  729. (ttempcreatenode(p).tempinfo^.flags*tempinfostoreflags=tempinfo^.flags*tempinfostoreflags) and
  730. (ttempcreatenode(p).tempinfo^.withnode.isequal(tempinfo^.withnode)) and
  731. equal_defs(ttempcreatenode(p).tempinfo^.typedef,tempinfo^.typedef);
  732. end;
  733. procedure ttempcreatenode.printnodedata(var t:text);
  734. begin
  735. inherited printnodedata(t);
  736. writeln(t,printnodeindention,'size = ',size,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  737. end;
  738. {*****************************************************************************
  739. TEMPREFNODE
  740. *****************************************************************************}
  741. constructor ttemprefnode.create(const temp: ttempcreatenode);
  742. begin
  743. inherited create(temprefn);
  744. tempinfo := temp.tempinfo;
  745. offset:=0;
  746. end;
  747. constructor ttemprefnode.create_offset(const temp: ttempcreatenode;aoffset:longint);
  748. begin
  749. self.create(temp);
  750. offset := aoffset;
  751. end;
  752. function ttemprefnode.dogetcopy: tnode;
  753. var
  754. n: ttemprefnode;
  755. begin
  756. n := ttemprefnode(inherited dogetcopy);
  757. n.offset := offset;
  758. if assigned(tempinfo^.hookoncopy) then
  759. { if the temp has been copied, assume it becomes a new }
  760. { temp which has to be hooked by the copied reference }
  761. begin
  762. { hook the ref to the copied temp }
  763. n.tempinfo := tempinfo^.hookoncopy;
  764. { if we passed a ttempdeletenode that changed the temp }
  765. { from a persistent one into a normal one, we must be }
  766. { the last reference (since our parent should free the }
  767. { temp (JM) }
  768. if (ti_nextref_set_hookoncopy_nil in tempinfo^.flags) then
  769. tempinfo^.hookoncopy := nil;
  770. end
  771. else
  772. { if the temp we refer to hasn't been copied, assume }
  773. { we're just a new reference to that temp }
  774. begin
  775. n.tempinfo := tempinfo;
  776. end;
  777. if not assigned(n.tempinfo) then
  778. internalerror(2005071901);
  779. result := n;
  780. end;
  781. constructor ttemprefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  782. begin
  783. inherited ppuload(t,ppufile);
  784. tempidx:=ppufile.getlongint;
  785. offset:=ppufile.getlongint;
  786. end;
  787. procedure ttemprefnode.ppuwrite(ppufile:tcompilerppufile);
  788. begin
  789. inherited ppuwrite(ppufile);
  790. ppufile.putlongint(tempinfo^.owner.ppuidx);
  791. ppufile.putlongint(offset);
  792. end;
  793. procedure ttemprefnode.derefnode;
  794. var
  795. temp : ttempcreatenode;
  796. begin
  797. inherited derefnode;
  798. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  799. if temp.nodetype<>tempcreaten then
  800. internalerror(200311075);
  801. tempinfo:=temp.tempinfo;
  802. end;
  803. function ttemprefnode.pass_1 : tnode;
  804. begin
  805. expectloc := LOC_REFERENCE;
  806. if not tempinfo^.typedef.needs_inittable and
  807. (ti_may_be_in_reg in tempinfo^.flags) then
  808. begin
  809. if tempinfo^.typedef.typ=floatdef then
  810. begin
  811. if (tempinfo^.temptype = tt_persistent) then
  812. expectloc := LOC_CFPUREGISTER
  813. else
  814. expectloc := LOC_FPUREGISTER;
  815. end
  816. else
  817. begin
  818. if (tempinfo^.temptype = tt_persistent) then
  819. expectloc := LOC_CREGISTER
  820. else
  821. expectloc := LOC_REGISTER;
  822. end;
  823. end;
  824. result := nil;
  825. end;
  826. function ttemprefnode.pass_typecheck: tnode;
  827. begin
  828. { check if the temp is already resultdef passed }
  829. if not assigned(tempinfo^.typedef) then
  830. internalerror(200108233);
  831. result := nil;
  832. resultdef := tempinfo^.typedef;
  833. end;
  834. function ttemprefnode.docompare(p: tnode): boolean;
  835. begin
  836. result :=
  837. inherited docompare(p) and
  838. (ttemprefnode(p).tempinfo = tempinfo) and
  839. (ttemprefnode(p).offset = offset);
  840. end;
  841. procedure Ttemprefnode.mark_write;
  842. begin
  843. include(flags,nf_write);
  844. end;
  845. procedure ttemprefnode.printnodedata(var t:text);
  846. begin
  847. inherited printnodedata(t);
  848. writeln(t,printnodeindention,'temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  849. end;
  850. {*****************************************************************************
  851. TEMPDELETENODE
  852. *****************************************************************************}
  853. constructor ttempdeletenode.create(const temp: ttempcreatenode);
  854. begin
  855. inherited create(tempdeleten);
  856. tempinfo := temp.tempinfo;
  857. release_to_normal := false;
  858. end;
  859. constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
  860. begin
  861. inherited create(tempdeleten);
  862. tempinfo := temp.tempinfo;
  863. release_to_normal := true;
  864. if tempinfo^.temptype <> tt_persistent then
  865. internalerror(200204211);
  866. end;
  867. function ttempdeletenode.dogetcopy: tnode;
  868. var
  869. n: ttempdeletenode;
  870. begin
  871. n:=ttempdeletenode(inherited dogetcopy);
  872. n.release_to_normal:=release_to_normal;
  873. if assigned(tempinfo^.hookoncopy) then
  874. { if the temp has been copied, assume it becomes a new }
  875. { temp which has to be hooked by the copied deletenode }
  876. begin
  877. { hook the tempdeletenode to the copied temp }
  878. n.tempinfo:=tempinfo^.hookoncopy;
  879. { the temp shall not be used, reset hookoncopy }
  880. { Only if release_to_normal is false, otherwise }
  881. { the temp can still be referenced once more (JM) }
  882. if (not release_to_normal) then
  883. tempinfo^.hookoncopy:=nil
  884. else
  885. include(tempinfo^.flags,ti_nextref_set_hookoncopy_nil);
  886. end
  887. else
  888. { if the temp we refer to hasn't been copied, we have a }
  889. { problem since that means we now have two delete nodes }
  890. { for one temp }
  891. internalerror(200108234);
  892. result:=n;
  893. end;
  894. constructor ttempdeletenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  895. begin
  896. inherited ppuload(t,ppufile);
  897. tempidx:=ppufile.getlongint;
  898. release_to_normal:=(ppufile.getbyte<>0);
  899. end;
  900. procedure ttempdeletenode.ppuwrite(ppufile:tcompilerppufile);
  901. begin
  902. inherited ppuwrite(ppufile);
  903. ppufile.putlongint(tempinfo^.owner.ppuidx);
  904. ppufile.putbyte(byte(release_to_normal));
  905. end;
  906. procedure ttempdeletenode.derefnode;
  907. var
  908. temp : ttempcreatenode;
  909. begin
  910. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  911. if temp.nodetype<>tempcreaten then
  912. internalerror(200311075);
  913. tempinfo:=temp.tempinfo;
  914. end;
  915. function ttempdeletenode.pass_1 : tnode;
  916. begin
  917. expectloc:=LOC_VOID;
  918. result := nil;
  919. end;
  920. function ttempdeletenode.pass_typecheck: tnode;
  921. begin
  922. result := nil;
  923. resultdef := voidtype;
  924. end;
  925. function ttempdeletenode.docompare(p: tnode): boolean;
  926. begin
  927. result :=
  928. inherited docompare(p) and
  929. (ttemprefnode(p).tempinfo = tempinfo);
  930. end;
  931. destructor ttempdeletenode.destroy;
  932. begin
  933. if assigned(tempinfo^.withnode) then
  934. begin
  935. tempinfo^.withnode.free;
  936. end;
  937. dispose(tempinfo);
  938. end;
  939. procedure ttempdeletenode.printnodedata(var t:text);
  940. begin
  941. inherited printnodedata(t);
  942. writeln(t,printnodeindention,'release_to_normal: ',release_to_normal,', temptypedef = "',tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  943. end;
  944. begin
  945. cnothingnode:=tnothingnode;
  946. cerrornode:=terrornode;
  947. casmnode:=tasmnode;
  948. cstatementnode:=tstatementnode;
  949. cblocknode:=tblocknode;
  950. ctempcreatenode:=ttempcreatenode;
  951. ctemprefnode:=ttemprefnode;
  952. ctempdeletenode:=ttempdeletenode;
  953. end.