nbas.pas 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707
  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. cgbase,cgutils,
  23. 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. {$ifdef DEBUG_NODE_XML}
  32. procedure XMLPrintNodeTree(var T: Text); override;
  33. {$endif DEBUG_NODE_XML}
  34. end;
  35. tnothingnodeclass = class of tnothingnode;
  36. terrornode = class(tnode)
  37. constructor create;virtual;
  38. function pass_1 : tnode;override;
  39. function pass_typecheck:tnode;override;
  40. procedure mark_write;override;
  41. end;
  42. terrornodeclass = class of terrornode;
  43. tspecializenode = class(tunarynode)
  44. sym:tsym;
  45. getaddr:boolean;
  46. inheriteddef:tdef;
  47. constructor create(l:tnode;g:boolean;s:tsym);virtual;
  48. constructor create_inherited(l:tnode;g:boolean;s:tsym;i:tdef);virtual;
  49. function pass_1:tnode;override;
  50. function pass_typecheck:tnode;override;
  51. end;
  52. tspecializenodeclass = class of tspecializenode;
  53. tfinalizetempsnode = class(tnode)
  54. constructor create;virtual;
  55. function pass_1 : tnode;override;
  56. function pass_typecheck:tnode;override;
  57. function docompare(p: tnode): boolean; override;
  58. end;
  59. tfinalizetempsnodeclass = class of tfinalizetempsnode;
  60. tasmnode = class(tnode)
  61. p_asm : TAsmList;
  62. currenttai : tai;
  63. { Used registers in assembler block }
  64. has_registerlist : boolean;
  65. constructor create(p : TAsmList);virtual;
  66. constructor create_get_position;
  67. destructor destroy;override;
  68. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  69. procedure ppuwrite(ppufile:tcompilerppufile);override;
  70. procedure buildderefimpl;override;
  71. procedure derefimpl;override;
  72. function dogetcopy : tnode;override;
  73. function pass_1 : tnode;override;
  74. function pass_typecheck:tnode;override;
  75. function docompare(p: tnode): boolean; override;
  76. {$ifdef DEBUG_NODE_XML}
  77. procedure XMLPrintNodeData(var T: Text); override;
  78. {$endif DEBUG_NODE_XML}
  79. end;
  80. tasmnodeclass = class of tasmnode;
  81. tstatementnode = class(tbinarynode)
  82. constructor create(l,r : tnode);virtual;
  83. function simplify(forinline : boolean) : tnode; override;
  84. function pass_1 : tnode;override;
  85. function pass_typecheck:tnode;override;
  86. procedure printnodetree(var t:text);override;
  87. property statement : tnode read left write left;
  88. property next : tnode read right write right;
  89. end;
  90. tstatementnodeclass = class of tstatementnode;
  91. tblocknode = class(tunarynode)
  92. constructor create(l : tnode);virtual;
  93. destructor destroy; override;
  94. function simplify(forinline : boolean) : tnode; override;
  95. function pass_1 : tnode;override;
  96. function pass_typecheck:tnode;override;
  97. {$ifdef state_tracking}
  98. function track_state_pass(exec_known:boolean):boolean;override;
  99. {$endif state_tracking}
  100. property statements : tnode read left write left;
  101. end;
  102. tblocknodeclass = class of tblocknode;
  103. ttempcreatenode = class;
  104. ttempinfoflag = (
  105. { temp can be kept in a register as far as the original creator is
  106. concerned }
  107. ti_may_be_in_reg,
  108. { the ttempcreatenode has been process and the temp's location is
  109. valid (-> the ttempdeletenode has not yet been processed, or
  110. in case it's a "create_to_normal()" one, the final ttemprefnode
  111. has not yet been processed) }
  112. ti_valid,
  113. { when performing a getcopy of a nodetree, we have to hook up the
  114. copies of ttemprefnodes and ttempdestroynode to the copied
  115. ttempinfo. this is done by setting hookoncopy in the original
  116. ttempinfo to point to the new one. if the temp is deleted via a
  117. regular ttempdeletenode, the hookoncopy is simply set to nil once
  118. it's processed. otherwise, it sets the ti_nextref_set_hookoncopy_nil
  119. and after processing the final ttemprefnode, hookoncopy is set to nil
  120. }
  121. ti_nextref_set_hookoncopy_nil,
  122. { the address of this temp is taken (-> cannot be kept in a register,
  123. even if the creator didn't mind)
  124. }
  125. ti_addr_taken,
  126. { in case an expression like "inc(x[func()],1)" is translated into
  127. a regular addition, you have to create a temp to hold the address
  128. representing x[func()], since otherwise func() will be called twice
  129. and that can spell trouble in case it has side effects. on platforms
  130. without pointers, we cannot just take the address though. This flag will,
  131. rather than loading the value at the calculated location and store
  132. it in the temp, keep a copy of the calculated location if possible
  133. and required (not possible for regvars, because SSA may change their
  134. register, but not required for them either since calculating their
  135. location has no side-effects)
  136. }
  137. ti_reference,
  138. { this temp only allows reading (makes it possible to safely use as
  139. reference under more circumstances)
  140. }
  141. ti_readonly,
  142. { if this is a managed temp, it doesn't have to be finalised before use
  143. }
  144. ti_nofini,
  145. { the value described by this temp. node is const/immutable, this is important for
  146. managed types like ansistrings where temp. refs are pointers to the actual value
  147. -- in this case, assignments to the temp do not increase the
  148. reference count, and if the assigned value was a temp itself then
  149. that temp is not deallocated until this temp is deleted (since
  150. otherwise the assigned value may be freed before the last use of
  151. the temp) }
  152. ti_const,
  153. { the temp. needs no final sync instruction if it is located in a register,
  154. so there are no loops involved in the usage of the temp.
  155. }
  156. ti_no_final_regsync,
  157. { this applied only to delete nodes: the single purpose of the temp. delete node is to clean up memory. In case
  158. of cse it might happen that the tempcreate node is optimized away so tempinfo is never initialized properly but
  159. the allocated memory must be disposed
  160. If a temp. node has this flag set, the life time of the temp. data must be determined by reg. life, the temp.
  161. location (in the sense of stack space/register) is never release }
  162. ti_cleanup_only
  163. );
  164. ttempinfoflags = set of ttempinfoflag;
  165. const
  166. tempinfostoreflags = [ti_may_be_in_reg,ti_addr_taken,ti_reference,ti_readonly,ti_no_final_regsync,ti_nofini,ti_const];
  167. type
  168. { to allow access to the location by temp references even after the temp has }
  169. { already been disposed and to make sure the coherency between temps and }
  170. { temp references is kept after a getcopy }
  171. ptempinfo = ^ttempinfo;
  172. ttempinfo = object
  173. private
  174. flags : ttempinfoflags;
  175. public
  176. { set to the copy of a tempcreate pnode (if it gets copied) so that the }
  177. { refs and deletenode can hook to this copy once they get copied too }
  178. hookoncopy : ptempinfo;
  179. typedef : tdef;
  180. typedefderef : tderef;
  181. temptype : ttemptype;
  182. owner : ttempcreatenode;
  183. withnode : tnode;
  184. location : tlocation;
  185. tempinitcode : tnode;
  186. end;
  187. ttempinfoaccessor = class
  188. class procedure settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags); virtual;
  189. class function gettempinfoflags(tempinfo: ptempinfo): ttempinfoflags; static; inline;
  190. end;
  191. ttempinfoaccessorclass = class of ttempinfoaccessor;
  192. ttempbasenode = class(tnode)
  193. protected
  194. class var tempinfoaccessor: ttempinfoaccessorclass;
  195. protected
  196. procedure settempinfoflags(const tempflags: ttempinfoflags); inline;
  197. function gettempinfoflags: ttempinfoflags; inline;
  198. public
  199. tempinfo: ptempinfo;
  200. procedure includetempflag(flag: ttempinfoflag); inline;
  201. procedure excludetempflag(flag: ttempinfoflag); inline;
  202. property tempflags: ttempinfoflags read gettempinfoflags write settempinfoflags;
  203. {$ifdef DEBUG_NODE_XML}
  204. procedure XMLPrintNodeInfo(var T: Text); override;
  205. procedure XMLPrintNodeData(var T: Text); override;
  206. {$endif DEBUG_NODE_XML}
  207. end;
  208. { a node which will create a (non)persistent temp of a given type with a given }
  209. { size (the size is separate to allow creating "void" temps with a custom size) }
  210. ttempcreatenode = class(ttempbasenode)
  211. size: tcgint;
  212. ftemplvalue : tnode;
  213. { * persistent temps are used in manually written code where the temp }
  214. { be usable among different statements and where you can manually say }
  215. { when the temp has to be freed (using a ttempdeletenode) }
  216. { * non-persistent temps are mostly used in typeconversion helpers, }
  217. { where the node that receives the temp becomes responsible for }
  218. { freeing it. In this last case, you must use only one reference }
  219. { to it and *not* generate a ttempdeletenode }
  220. constructor create(_typedef: tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean); virtual;
  221. constructor create_withnode(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg:boolean; withnode: tnode); virtual;
  222. constructor create_value(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode);
  223. constructor create_reference(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode; readonly: boolean);
  224. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  225. procedure ppuwrite(ppufile:tcompilerppufile);override;
  226. procedure buildderefimpl;override;
  227. procedure derefimpl;override;
  228. function dogetcopy: tnode; override;
  229. function pass_1 : tnode; override;
  230. function pass_typecheck: tnode; override;
  231. function docompare(p: tnode): boolean; override;
  232. procedure printnodedata(var t:text);override;
  233. {$ifdef DEBUG_NODE_XML}
  234. procedure XMLPrintNodeData(var T: Text); override;
  235. {$endif DEBUG_NODE_XML}
  236. end;
  237. ttempcreatenodeclass = class of ttempcreatenode;
  238. { a node which is a reference to a certain temp }
  239. ttemprefnode = class(ttempbasenode)
  240. constructor create(const temp: ttempcreatenode); virtual;
  241. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  242. procedure ppuwrite(ppufile:tcompilerppufile);override;
  243. procedure resolveppuidx;override;
  244. function dogetcopy: tnode; override;
  245. function pass_1 : tnode; override;
  246. function pass_typecheck : tnode; override;
  247. procedure mark_write;override;
  248. function docompare(p: tnode): boolean; override;
  249. procedure printnodedata(var t:text);override;
  250. private
  251. tempidx : longint;
  252. end;
  253. ttemprefnodeclass = class of ttemprefnode;
  254. { a node which removes a temp }
  255. ttempdeletenode = class(ttempbasenode)
  256. constructor create(const temp: ttempcreatenode); virtual;
  257. { this will convert the persistant temp to a normal temp
  258. for returning to the other nodes }
  259. constructor create_normal_temp(const temp: ttempcreatenode);
  260. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  261. procedure ppuwrite(ppufile:tcompilerppufile);override;
  262. procedure resolveppuidx;override;
  263. function dogetcopy: tnode; override;
  264. function pass_1: tnode; override;
  265. function pass_typecheck: tnode; override;
  266. function docompare(p: tnode): boolean; override;
  267. destructor destroy; override;
  268. procedure printnodedata(var t:text);override;
  269. {$ifdef DEBUG_NODE_XML}
  270. procedure XMLPrintNodeData(var T: Text); override;
  271. {$endif DEBUG_NODE_XML}
  272. protected
  273. release_to_normal : boolean;
  274. private
  275. tempidx : longint;
  276. end;
  277. ttempdeletenodeclass = class of ttempdeletenode;
  278. var
  279. cnothingnode : tnothingnodeclass = tnothingnode;
  280. cerrornode : terrornodeclass = terrornode;
  281. cspecializenode : tspecializenodeclass = tspecializenode;
  282. cfinalizetempsnode: tfinalizetempsnodeclass = tfinalizetempsnode;
  283. casmnode : tasmnodeclass = tasmnode;
  284. cstatementnode : tstatementnodeclass = tstatementnode;
  285. cblocknode : tblocknodeclass = tblocknode;
  286. ctempinfoaccessor : ttempinfoaccessorclass = ttempinfoaccessor;
  287. ctempcreatenode : ttempcreatenodeclass = ttempcreatenode;
  288. ctemprefnode : ttemprefnodeclass = ttemprefnode;
  289. ctempdeletenode : ttempdeletenodeclass = ttempdeletenode;
  290. { Create a blocknode and statement node for multiple statements
  291. generated internally by the parser }
  292. function internalstatements(out laststatement:tstatementnode):tblocknode;
  293. function laststatement(block:tblocknode):tstatementnode;
  294. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  295. { if the complexity of n is "high", creates a reference temp to n's
  296. location and replace n with a ttemprefnode referring to that location }
  297. function maybereplacewithtempref(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; readonly: boolean): ttempcreatenode;
  298. { same as above, but create a regular temp rather than reference temp }
  299. function maybereplacewithtemp(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; allowreg: boolean): ttempcreatenode;
  300. implementation
  301. uses
  302. verbose,globals,systems,
  303. ppu,
  304. symconst,symdef,defutil,defcmp,
  305. pass_1,
  306. nutils,nld,ncnv,
  307. procinfo
  308. {$ifdef DEBUG_NODE_XML}
  309. {$ifndef jvm}
  310. ,
  311. cpubase,
  312. cutils,
  313. itcpugas
  314. {$endif jvm}
  315. {$endif DEBUG_NODE_XML}
  316. ;
  317. {*****************************************************************************
  318. Helpers
  319. *****************************************************************************}
  320. function internalstatements(out laststatement:tstatementnode):tblocknode;
  321. begin
  322. { create dummy initial statement }
  323. laststatement := cstatementnode.create(cnothingnode.create,nil);
  324. internalstatements := cblocknode.create(laststatement);
  325. end;
  326. function laststatement(block:tblocknode):tstatementnode;
  327. begin
  328. result:=tstatementnode(block.left);
  329. while assigned(result) and assigned(result.right) do
  330. result:=tstatementnode(result.right);
  331. end;
  332. procedure addstatement(var laststatement:tstatementnode;n:tnode);
  333. begin
  334. if assigned(laststatement.right) then
  335. internalerror(200204201);
  336. laststatement.right:=cstatementnode.create(n,nil);
  337. laststatement:=tstatementnode(laststatement.right);
  338. end;
  339. function maybereplacewithtempref(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; readonly: boolean): ttempcreatenode;
  340. begin
  341. result:=nil;
  342. if (node_complexity(n)>4) or
  343. might_have_sideeffects(n) then
  344. begin
  345. result:=ctempcreatenode.create_reference(n.resultdef,size,tt_persistent,true,n,readonly);
  346. typecheckpass(tnode(result));
  347. n:=ctemprefnode.create(result);
  348. typecheckpass(n);
  349. if not assigned(stat) then
  350. block:=internalstatements(stat);
  351. addstatement(stat,result)
  352. end;
  353. end;
  354. function maybereplacewithtemp(var n: tnode; var block: tblocknode; var stat: tstatementnode; size: ASizeInt; allowreg: boolean): ttempcreatenode;
  355. begin
  356. result:=nil;
  357. if (node_complexity(n)>4) or
  358. might_have_sideeffects(n) then
  359. begin
  360. result:=ctempcreatenode.create_value(n.resultdef,size,tt_persistent,allowreg,n);
  361. typecheckpass(tnode(result));
  362. n:=ctemprefnode.create(result);
  363. typecheckpass(n);
  364. if not assigned(stat) then
  365. block:=internalstatements(stat);
  366. addstatement(stat,result)
  367. end;
  368. end;
  369. {*****************************************************************************
  370. TFIRSTNOTHING
  371. *****************************************************************************}
  372. constructor tnothingnode.create;
  373. begin
  374. inherited create(nothingn);
  375. end;
  376. function tnothingnode.pass_typecheck:tnode;
  377. begin
  378. result:=nil;
  379. resultdef:=voidtype;
  380. end;
  381. function tnothingnode.pass_1 : tnode;
  382. begin
  383. result:=nil;
  384. expectloc:=LOC_VOID;
  385. end;
  386. {$ifdef DEBUG_NODE_XML}
  387. procedure TNothingNode.XMLPrintNodeTree(var T: Text);
  388. begin
  389. Write(T, PrintNodeIndention, '<', nodetype2str[nodetype]);
  390. XMLPrintNodeInfo(T);
  391. { "Nothing nodes" contain no data, so just use "/>" to terminate it early }
  392. WriteLn(T, ' />');
  393. end;
  394. {$endif DEBUG_NODE_XML}
  395. {*****************************************************************************
  396. TFIRSTERROR
  397. *****************************************************************************}
  398. constructor terrornode.create;
  399. begin
  400. inherited create(errorn);
  401. end;
  402. function terrornode.pass_typecheck:tnode;
  403. begin
  404. result:=nil;
  405. include(flags,nf_error);
  406. codegenerror:=true;
  407. resultdef:=generrordef;
  408. end;
  409. function terrornode.pass_1 : tnode;
  410. begin
  411. result:=nil;
  412. expectloc:=LOC_VOID;
  413. codegenerror:=true;
  414. end;
  415. procedure terrornode.mark_write;
  416. begin
  417. end;
  418. {*****************************************************************************
  419. TSPECIALIZENODE
  420. *****************************************************************************}
  421. constructor tspecializenode.create(l:tnode;g:boolean;s:tsym);
  422. begin
  423. inherited create(specializen,l);
  424. sym:=s;
  425. getaddr:=g;
  426. end;
  427. constructor tspecializenode.create_inherited(l:tnode;g:boolean;s:tsym;i:tdef);
  428. begin
  429. create(l,g,s);
  430. inheriteddef:=i;
  431. end;
  432. function tspecializenode.pass_typecheck:tnode;
  433. begin
  434. result:=nil;
  435. resultdef:=cundefinedtype;
  436. end;
  437. function tspecializenode.pass_1:tnode;
  438. begin
  439. { such a node should not reach pass_1 }
  440. internalerror(2015071704);
  441. result:=nil;
  442. expectloc:=LOC_VOID;
  443. codegenerror:=true;
  444. end;
  445. {*****************************************************************************
  446. TFINALIZETEMPSNODE
  447. *****************************************************************************}
  448. constructor tfinalizetempsnode.create;
  449. begin
  450. inherited create(finalizetempsn);
  451. end;
  452. function tfinalizetempsnode.pass_1: tnode;
  453. begin
  454. result:=nil;
  455. expectloc:=LOC_VOID;
  456. end;
  457. function tfinalizetempsnode.pass_typecheck: tnode;
  458. begin
  459. resultdef:=voidtype;
  460. result:=nil;
  461. end;
  462. function tfinalizetempsnode.docompare(p: tnode): boolean;
  463. begin
  464. { these nodes should never be coalesced }
  465. result:=false;
  466. end;
  467. {*****************************************************************************
  468. TSTATEMENTNODE
  469. *****************************************************************************}
  470. constructor tstatementnode.create(l,r : tnode);
  471. begin
  472. inherited create(statementn,l,r);
  473. end;
  474. function is_exit_statement(var n: tnode; arg: pointer): foreachnoderesult;
  475. begin
  476. if (n.nodetype<>exitn) then
  477. result:=fen_false
  478. else
  479. result:=fen_norecurse_true;
  480. end;
  481. function no_exit_statement_in_block(n: tnode): boolean;
  482. begin
  483. result:=not foreachnodestatic(n,@is_exit_statement,nil);
  484. end;
  485. function tstatementnode.simplify(forinline: boolean) : tnode;
  486. begin
  487. result:=nil;
  488. { these "optimizations" are only to make it more easy to recognise }
  489. { blocknodes which at the end of inlining only contain one single }
  490. { statement. Simplifying inside blocknode.simplify could be dangerous }
  491. { because if the main blocknode which makes up a procedure/function }
  492. { body were replaced with a statementn/nothingn, this could cause }
  493. { problems elsewhere in the compiler which expects a blocknode }
  494. { remove next statement if it's a nothing-statement (since if it's }
  495. { the last, it won't remove itself -- see next simplification) }
  496. while assigned(right) and
  497. (tstatementnode(right).left.nodetype = nothingn) do
  498. begin
  499. result:=tstatementnode(right).right;
  500. tstatementnode(right).right:=nil;
  501. right.free;
  502. right:=result;
  503. result:=nil;
  504. end;
  505. { Remove initial nothingn if there are other statements. If there }
  506. { are no other statements, returning nil doesn't help (will be }
  507. { interpreted as "can't be simplified") and replacing the }
  508. { statementnode with a nothingnode cannot be done (because it's }
  509. { possible this statementnode is a child of a blocknode, and }
  510. { blocknodes are expected to only contain statementnodes) }
  511. if (left.nodetype = nothingn) and
  512. assigned(right) then
  513. begin
  514. result:=right;
  515. right:=nil;
  516. exit;
  517. end;
  518. { if the current statement contains a block with one statement,
  519. replace the current statement with that block's statement
  520. (but only if the block does not have nf_block_with_exit set
  521. or has no exit statement, because otherwise it needs an own
  522. exit label, see tests/test/tinline10)
  523. Further, it might not be the user code entry
  524. }
  525. if (left.nodetype = blockn) and
  526. ((left.flags*[nf_block_with_exit,nf_usercode_entry]=[]) or
  527. ((left.flags*[nf_block_with_exit,nf_usercode_entry]=[nf_block_with_exit]) and no_exit_statement_in_block(left))) and
  528. assigned(tblocknode(left).left) and
  529. not assigned(tstatementnode(tblocknode(left).left).right) then
  530. begin
  531. result:=tblocknode(left).left;
  532. tstatementnode(result).right:=right;
  533. right:=nil;
  534. tblocknode(left).left:=nil;
  535. exit;
  536. end;
  537. end;
  538. function tstatementnode.pass_typecheck:tnode;
  539. begin
  540. result:=nil;
  541. resultdef:=voidtype;
  542. { left is the statement itself calln assignn or a complex one }
  543. typecheckpass(left);
  544. if codegenerror then
  545. exit;
  546. { right is the next statement in the list }
  547. if assigned(right) then
  548. typecheckpass(right);
  549. if codegenerror then
  550. exit;
  551. end;
  552. function tstatementnode.pass_1 : tnode;
  553. begin
  554. result:=nil;
  555. { left is the statement itself calln assignn or a complex one }
  556. firstpass(left);
  557. if codegenerror then
  558. exit;
  559. expectloc:=left.expectloc;
  560. { right is the next in the list }
  561. if assigned(right) then
  562. firstpass(right);
  563. if codegenerror then
  564. exit;
  565. end;
  566. procedure tstatementnode.printnodetree(var t:text);
  567. begin
  568. printnodelist(t);
  569. end;
  570. {*****************************************************************************
  571. TBLOCKNODE
  572. *****************************************************************************}
  573. constructor tblocknode.create(l : tnode);
  574. begin
  575. inherited create(blockn,l);
  576. end;
  577. destructor tblocknode.destroy;
  578. var
  579. hp, next: tstatementnode;
  580. begin
  581. hp := tstatementnode(left);
  582. left := nil;
  583. while assigned(hp) do
  584. begin
  585. next := tstatementnode(hp.right);
  586. hp.right := nil;
  587. hp.free;
  588. hp := next;
  589. end;
  590. inherited destroy;
  591. end;
  592. function NodesEqual(var n: tnode; arg: pointer): foreachnoderesult;
  593. begin
  594. if n.IsEqual(tnode(arg)) then
  595. result:=fen_norecurse_true
  596. else
  597. result:=fen_false;
  598. end;
  599. function tblocknode.simplify(forinline : boolean): tnode;
  600. var
  601. a : array[0..3] of tstatementnode;
  602. begin
  603. result := nil;
  604. { Warning: never replace a blocknode with another node type,
  605. since the block may be the main block of a procedure/function/
  606. main program body, and those nodes should always be blocknodes
  607. since that's what the compiler expects elsewhere. }
  608. if assigned(left) and
  609. not assigned(tstatementnode(left).right) then
  610. begin
  611. case tstatementnode(left).left.nodetype of
  612. blockn:
  613. begin
  614. { if the current block contains only one statement, and
  615. this one statement only contains another block, replace
  616. this block with that other block. }
  617. result:=tstatementnode(left).left;
  618. tstatementnode(left).left:=nil;
  619. { make sure the nf_block_with_exit flag is safeguarded }
  620. result.flags:=result.flags+(flags*[nf_block_with_exit,nf_usercode_entry]);
  621. exit;
  622. end;
  623. nothingn:
  624. begin
  625. { if the block contains only a statement with a nothing node,
  626. get rid of the statement }
  627. left.Free;
  628. left:=nil;
  629. exit;
  630. end;
  631. else
  632. ;
  633. end;
  634. end;
  635. {$ifdef break_inlining}
  636. { simple sequence of tempcreate, assign and return temp.? }
  637. if GetStatements(left,a) and
  638. (a[0].left.nodetype=tempcreaten) and
  639. (a[1].left.nodetype=assignn) and
  640. (actualtargetnode(@tassignmentnode(a[1].left).left)^.nodetype=temprefn) and
  641. (a[2].left.nodetype=tempdeleten) and
  642. (a[3].left.nodetype=temprefn) and
  643. (ttempcreatenode(a[0].left).tempinfo=ttemprefnode(actualtargetnode(@tassignmentnode(a[1].left).left)^).tempinfo) and
  644. (ttempcreatenode(a[0].left).tempinfo=ttempdeletenode(a[2].left).tempinfo) and
  645. (ttempcreatenode(a[0].left).tempinfo=ttemprefnode(a[3].left).tempinfo) and
  646. { the temp. node might not be references inside the assigned expression }
  647. not(foreachnodestatic(tassignmentnode(a[1].left).right,@NodesEqual,actualtargetnode(@tassignmentnode(a[1].left).left)^)) then
  648. begin
  649. result:=tassignmentnode(a[1].left).right;
  650. tassignmentnode(a[1].left).right:=nil;
  651. { ensure the node is first passed, so the resultdef does not get changed if the
  652. the type conv. below is merged }
  653. firstpass(result);
  654. result:=ctypeconvnode.create_internal(result,ttemprefnode(a[3].left).resultdef);
  655. firstpass(result);
  656. exit;
  657. end;
  658. {$endif break_inlining}
  659. end;
  660. function tblocknode.pass_typecheck:tnode;
  661. var
  662. hp : tstatementnode;
  663. begin
  664. result:=nil;
  665. resultdef:=voidtype;
  666. hp:=tstatementnode(left);
  667. while assigned(hp) do
  668. begin
  669. if assigned(hp.left) then
  670. begin
  671. codegenerror:=false;
  672. typecheckpass(hp.left);
  673. { the resultdef of the block is the last type that is
  674. returned. Normally this is a voidtype. But when the
  675. compiler inserts a block of multiple statements then the
  676. last entry can return a value }
  677. resultdef:=hp.left.resultdef;
  678. end;
  679. hp:=tstatementnode(hp.right);
  680. end;
  681. end;
  682. function tblocknode.pass_1 : tnode;
  683. var
  684. hp : tstatementnode;
  685. //count : longint;
  686. begin
  687. result:=nil;
  688. expectloc:=LOC_VOID;
  689. //count:=0;
  690. hp:=tstatementnode(left);
  691. while assigned(hp) do
  692. begin
  693. if assigned(hp.left) then
  694. begin
  695. codegenerror:=false;
  696. firstpass(hp.left);
  697. hp.expectloc:=hp.left.expectloc;
  698. end;
  699. expectloc:=hp.expectloc;
  700. //inc(count);
  701. hp:=tstatementnode(hp.right);
  702. end;
  703. end;
  704. {$ifdef state_tracking}
  705. function Tblocknode.track_state_pass(exec_known:boolean):boolean;
  706. var hp:Tstatementnode;
  707. begin
  708. track_state_pass:=false;
  709. hp:=Tstatementnode(left);
  710. while assigned(hp) do
  711. begin
  712. if hp.left.track_state_pass(exec_known) then
  713. track_state_pass:=true;
  714. hp:=Tstatementnode(hp.right);
  715. end;
  716. end;
  717. {$endif state_tracking}
  718. {*****************************************************************************
  719. TASMNODE
  720. *****************************************************************************}
  721. constructor tasmnode.create(p : TAsmList);
  722. begin
  723. inherited create(asmn);
  724. p_asm:=p;
  725. currenttai:=nil;
  726. end;
  727. constructor tasmnode.create_get_position;
  728. begin
  729. inherited create(asmn);
  730. p_asm:=nil;
  731. include(flags,nf_get_asm_position);
  732. currenttai:=nil;
  733. end;
  734. destructor tasmnode.destroy;
  735. begin
  736. if assigned(p_asm) then
  737. p_asm.free;
  738. inherited destroy;
  739. end;
  740. constructor tasmnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  741. var
  742. hp : tai;
  743. begin
  744. inherited ppuload(t,ppufile);
  745. if not(nf_get_asm_position in flags) then
  746. begin
  747. p_asm:=TAsmList.create;
  748. repeat
  749. hp:=ppuloadai(ppufile);
  750. if hp=nil then
  751. break;
  752. p_asm.concat(hp);
  753. if hp.typ=ait_section then
  754. inc(p_asm.section_count);
  755. until false;
  756. end
  757. else
  758. p_asm:=nil;
  759. currenttai:=nil;
  760. end;
  761. procedure tasmnode.ppuwrite(ppufile:tcompilerppufile);
  762. var
  763. hp : tai;
  764. begin
  765. inherited ppuwrite(ppufile);
  766. { TODO: FIXME Add saving of register sets}
  767. if not(nf_get_asm_position in flags) then
  768. begin
  769. hp:=tai(p_asm.first);
  770. while assigned(hp) do
  771. begin
  772. ppuwriteai(ppufile,hp);
  773. hp:=tai(hp.next);
  774. end;
  775. { end is marked by a nil }
  776. ppuwriteai(ppufile,nil);
  777. end;
  778. end;
  779. procedure tasmnode.buildderefimpl;
  780. var
  781. hp : tai;
  782. begin
  783. inherited buildderefimpl;
  784. if not(nf_get_asm_position in flags) then
  785. begin
  786. hp:=tai(p_asm.first);
  787. while assigned(hp) do
  788. begin
  789. hp.buildderefimpl;
  790. hp:=tai(hp.next);
  791. end;
  792. end;
  793. end;
  794. procedure tasmnode.derefimpl;
  795. var
  796. hp : tai;
  797. begin
  798. inherited derefimpl;
  799. if not(nf_get_asm_position in flags) then
  800. begin
  801. hp:=tai(p_asm.first);
  802. while assigned(hp) do
  803. begin
  804. hp.derefimpl;
  805. hp:=tai(hp.next);
  806. end;
  807. end;
  808. end;
  809. function tasmnode.dogetcopy: tnode;
  810. var
  811. n: tasmnode;
  812. begin
  813. n := tasmnode(inherited dogetcopy);
  814. if assigned(p_asm) then
  815. begin
  816. n.p_asm:=TAsmList.create;
  817. n.p_asm.concatlistcopy(p_asm);
  818. end
  819. else n.p_asm := nil;
  820. n.currenttai:=currenttai;
  821. n.has_registerlist:=has_registerlist;
  822. result:=n;
  823. end;
  824. function tasmnode.pass_typecheck:tnode;
  825. begin
  826. result:=nil;
  827. resultdef:=voidtype;
  828. if not(nf_get_asm_position in flags) then
  829. include(current_procinfo.flags,pi_has_assembler_block);
  830. end;
  831. function tasmnode.pass_1 : tnode;
  832. begin
  833. result:=nil;
  834. expectloc:=LOC_VOID;
  835. end;
  836. function tasmnode.docompare(p: tnode): boolean;
  837. begin
  838. { comparing of asmlists is not implemented (JM) }
  839. docompare := false;
  840. end;
  841. {$ifdef DEBUG_NODE_XML}
  842. procedure TAsmNode.XMLPrintNodeData(var T: Text);
  843. procedure PadString(var S: string; Len: Integer);
  844. var
  845. X, C: Integer;
  846. begin
  847. C := Length(S);
  848. if C < Len then
  849. begin
  850. SetLength(S, 7);
  851. for X := C + 1 to Len do
  852. S[X] := ' '
  853. end;
  854. end;
  855. {$ifndef jvm}
  856. function FormatOp(const Oper: POper): string;
  857. begin
  858. case Oper^.typ of
  859. top_const:
  860. begin
  861. case Oper^.val of
  862. -15..15:
  863. Result := '$' + tostr(Oper^.val);
  864. $10..$FF:
  865. Result := '$0x' + hexstr(Oper^.val, 2);
  866. $100..$FFFF:
  867. Result := '$0x' + hexstr(Oper^.val, 4);
  868. $10000..$FFFFFFFF:
  869. Result := '$0x' + hexstr(Oper^.val, 8);
  870. else
  871. Result := '$0x' + hexstr(Oper^.val, 16);
  872. end;
  873. end;
  874. top_reg:
  875. Result := gas_regname(Oper^.reg);
  876. top_ref:
  877. with Oper^.ref^ do
  878. begin
  879. {$if defined(x86)}
  880. if segment <> NR_NO then
  881. Result := gas_regname(segment) + ':'
  882. else
  883. Result := '';
  884. {$endif defined(x86)}
  885. if Assigned(symbol) then
  886. begin
  887. Result := Result + symbol.Name;
  888. if offset > 0 then
  889. Result := Result + '+';
  890. end;
  891. if offset <> 0 then
  892. Result := Result + tostr(offset)
  893. else
  894. Result := Result;
  895. if (base <> NR_NO) or (index <> NR_NO) then
  896. begin
  897. Result := Result + '(';
  898. if base <> NR_NO then
  899. begin
  900. Result := Result + gas_regname(base);
  901. if index <> NR_NO then
  902. Result := Result + ',';
  903. end;
  904. if index <> NR_NO then
  905. Result := Result + gas_regname(index);
  906. if scalefactor <> 0 then
  907. Result := Result + ',' + tostr(scalefactor) + ')'
  908. else
  909. Result := Result + ')';
  910. end;
  911. end;
  912. top_bool:
  913. begin
  914. if Oper^.b then
  915. Result := 'TRUE'
  916. else
  917. Result := 'FALSE';
  918. end
  919. else
  920. Result := '';
  921. end;
  922. end;
  923. {$if defined(x86)}
  924. procedure ProcessInstruction(p: tai); inline;
  925. var
  926. ThisOp, ThisOper: string;
  927. X: Integer;
  928. begin
  929. case p.typ of
  930. ait_label:
  931. WriteLn(T, PrintNodeIndention, tai_label(p).labsym.name);
  932. ait_instruction:
  933. begin
  934. ThisOp := gas_op2str[taicpu(p).opcode]+cond2str[taicpu(p).condition];
  935. if gas_needsuffix[taicpu(p).opcode] <> AttSufNONE then
  936. ThisOp := ThisOp + gas_opsize2str[taicpu(p).opsize];
  937. { Pad the opcode with spaces so the succeeding operands are aligned }
  938. PadString(ThisOp, 7);
  939. Write(T, PrintNodeIndention, ' ', ThisOp); { Extra indentation to account for label formatting }
  940. for X := 0 to taicpu(p).ops - 1 do
  941. begin
  942. Write(T, ' ');
  943. ThisOper := FormatOp(taicpu(p).oper[X]);
  944. if X < taicpu(p).ops - 1 then
  945. begin
  946. ThisOper := ThisOper + ',';
  947. PadString(ThisOper, 7);
  948. end;
  949. Write(T, ThisOper);
  950. end;
  951. WriteLn(T);
  952. end;
  953. else
  954. { Do nothing };
  955. end;
  956. end;
  957. var
  958. hp: tai;
  959. begin
  960. if not Assigned(p_asm) then
  961. Exit;
  962. hp := tai(p_asm.First);
  963. while Assigned(hp) do
  964. begin
  965. ProcessInstruction(hp);
  966. hp := tai(hp.Next);
  967. end;
  968. {$else defined(x86)}
  969. begin
  970. WriteLn(T, PrintNodeIndention, '(Assembler output not currently supported on this platform)');
  971. {$endif defined(x86)}
  972. {$else jvm}
  973. begin
  974. WriteLn(T, PrintNodeIndention, '(Should assembly language even be possible under JVM?)');
  975. {$endif jvm}
  976. end;
  977. {$endif DEBUG_NODE_XML}
  978. {*****************************************************************************
  979. TEMPBASENODE
  980. *****************************************************************************}
  981. class procedure ttempinfoaccessor.settempinfoflags(tempinfo: ptempinfo; const flags: ttempinfoflags);
  982. begin
  983. tempinfo^.flags:=flags;
  984. end;
  985. class function ttempinfoaccessor.gettempinfoflags(tempinfo: ptempinfo): ttempinfoflags;
  986. begin
  987. result:=tempinfo^.flags;
  988. end;
  989. {*****************************************************************************
  990. TEMPBASENODE
  991. *****************************************************************************}
  992. procedure ttempbasenode.settempinfoflags(const tempflags: ttempinfoflags);
  993. begin
  994. ctempinfoaccessor.settempinfoflags(tempinfo,tempflags);
  995. end;
  996. function ttempbasenode.gettempinfoflags: ttempinfoflags;
  997. begin
  998. result:=ctempinfoaccessor.gettempinfoflags(tempinfo);
  999. end;
  1000. procedure ttempbasenode.includetempflag(flag: ttempinfoflag);
  1001. begin
  1002. { go through settempinfoflags() so it can filter out unsupported tempflags }
  1003. settempinfoflags(gettempinfoflags+[flag])
  1004. end;
  1005. procedure ttempbasenode.excludetempflag(flag: ttempinfoflag);
  1006. begin
  1007. { go through settempinfoflags() so it can prevent required tempflags from
  1008. being removed (if any) }
  1009. settempinfoflags(gettempinfoflags-[flag])
  1010. end;
  1011. {$ifdef DEBUG_NODE_XML}
  1012. procedure TTempBaseNode.XMLPrintNodeInfo(var T: Text);
  1013. begin
  1014. inherited XMLPrintNodeInfo(T);
  1015. { The raw pointer is the only way to uniquely identify the temp }
  1016. Write(T, ' id="', WritePointer(tempinfo), '"');
  1017. end;
  1018. procedure TTempBaseNode.XMLPrintNodeData(var T: Text);
  1019. var
  1020. Flag: TTempInfoFlag;
  1021. NotFirst: Boolean;
  1022. begin
  1023. inherited XMLPrintNodeData(t);
  1024. if not assigned(tempinfo) then
  1025. exit;
  1026. WriteLn(T, PrintNodeIndention, '<typedef>', SanitiseXMLString(tempinfo^.typedef.typesymbolprettyname), '</typedef>');
  1027. NotFirst := False;
  1028. for Flag := Low(TTempInfoFlag) to High(TTempInfoFlag) do
  1029. if (Flag in tempinfo^.flags) then
  1030. if not NotFirst then
  1031. begin
  1032. Write(T, PrintNodeIndention, '<tempflags>', Flag);
  1033. NotFirst := True;
  1034. end
  1035. else
  1036. Write(T, ',', Flag);
  1037. if NotFirst then
  1038. WriteLn(T, '</tempflags>')
  1039. else
  1040. WriteLn(T, PrintNodeIndention, '<tempflags />');
  1041. WriteLn(T, PrintNodeIndention, '<temptype>', tempinfo^.temptype, '</temptype>');
  1042. end;
  1043. {$endif DEBUG_NODE_XML}
  1044. {*****************************************************************************
  1045. TEMPCREATENODE
  1046. *****************************************************************************}
  1047. constructor ttempcreatenode.create(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean);
  1048. begin
  1049. inherited create(tempcreaten);
  1050. size := _size;
  1051. new(tempinfo);
  1052. fillchar(tempinfo^,sizeof(tempinfo^),0);
  1053. tempinfo^.typedef := _typedef;
  1054. tempinfo^.temptype := _temptype;
  1055. tempinfo^.owner := self;
  1056. tempinfo^.withnode := nil;
  1057. if allowreg and
  1058. { temp must fit a single register }
  1059. (tstoreddef(_typedef).is_fpuregable or
  1060. (tstoreddef(_typedef).is_intregable and
  1061. (_size<=TCGSize2Size[OS_64]))) and
  1062. { size of register operations must be known }
  1063. (def_cgsize(_typedef)<>OS_NO) and
  1064. { no init/final needed }
  1065. not is_managed_type(_typedef) then
  1066. includetempflag(ti_may_be_in_reg);
  1067. end;
  1068. constructor ttempcreatenode.create_withnode(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg:boolean; withnode: tnode);
  1069. begin
  1070. self.create(_typedef,_size,_temptype,allowreg);
  1071. tempinfo^.withnode:=withnode.getcopy;
  1072. end;
  1073. constructor ttempcreatenode.create_value(_typedef:tdef; _size: tcgint; _temptype: ttemptype;allowreg:boolean; templvalue: tnode);
  1074. begin
  1075. self.create(_typedef,_size,_temptype,allowreg);
  1076. // store in ppuwrite
  1077. ftemplvalue:=templvalue;
  1078. // create from stored ftemplvalue in ppuload
  1079. tempinfo^.tempinitcode:=cassignmentnode.create(ctemprefnode.create(self),ftemplvalue);
  1080. end;
  1081. constructor ttempcreatenode.create_reference(_typedef: tdef; _size: tcgint; _temptype: ttemptype; allowreg: boolean; templvalue: tnode; readonly: boolean);
  1082. begin
  1083. // store in ppuwrite
  1084. self.create(_typedef,_size,_temptype,allowreg);
  1085. ftemplvalue:=templvalue;
  1086. // no assignment node, just the tempvalue
  1087. tempinfo^.tempinitcode:=ftemplvalue;
  1088. includetempflag(ti_reference);
  1089. if readonly then
  1090. includetempflag(ti_readonly);
  1091. end;
  1092. function ttempcreatenode.dogetcopy: tnode;
  1093. var
  1094. n: ttempcreatenode;
  1095. begin
  1096. n := ttempcreatenode(inherited dogetcopy);
  1097. n.size := size;
  1098. new(n.tempinfo);
  1099. fillchar(n.tempinfo^,sizeof(n.tempinfo^),0);
  1100. n.tempinfo^.owner:=n;
  1101. n.tempinfo^.typedef := tempinfo^.typedef;
  1102. n.tempinfo^.temptype := tempinfo^.temptype;
  1103. n.tempflags := tempflags * tempinfostoreflags;
  1104. { when the tempinfo has already a hookoncopy then it is not
  1105. reset by a tempdeletenode }
  1106. if assigned(tempinfo^.hookoncopy) then
  1107. internalerror(200211262);
  1108. { signal the temprefs that the temp they point to has been copied, }
  1109. { so that if the refs get copied as well, they can hook themselves }
  1110. { to the copy of the temp }
  1111. tempinfo^.hookoncopy := n.tempinfo;
  1112. excludetempflag(ti_nextref_set_hookoncopy_nil);
  1113. if assigned(tempinfo^.withnode) then
  1114. n.tempinfo^.withnode := tempinfo^.withnode.getcopy
  1115. else
  1116. n.tempinfo^.withnode := nil;
  1117. if assigned(tempinfo^.tempinitcode) then
  1118. n.tempinfo^.tempinitcode := tempinfo^.tempinitcode.getcopy
  1119. else
  1120. n.tempinfo^.tempinitcode := nil;
  1121. result := n;
  1122. end;
  1123. constructor ttempcreatenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  1124. begin
  1125. inherited ppuload(t,ppufile);
  1126. size:=ppufile.getlongint;
  1127. new(tempinfo);
  1128. fillchar(tempinfo^,sizeof(tempinfo^),0);
  1129. ppufile.getset(tppuset2(tempinfo^.flags));
  1130. ppufile.getderef(tempinfo^.typedefderef);
  1131. tempinfo^.temptype := ttemptype(ppufile.getbyte);
  1132. tempinfo^.owner:=self;
  1133. tempinfo^.withnode:=ppuloadnode(ppufile);
  1134. ftemplvalue:=ppuloadnode(ppufile);
  1135. end;
  1136. procedure ttempcreatenode.ppuwrite(ppufile:tcompilerppufile);
  1137. begin
  1138. inherited ppuwrite(ppufile);
  1139. ppufile.putlongint(size);
  1140. ppufile.putset(tppuset2(tempinfo^.flags));
  1141. ppufile.putderef(tempinfo^.typedefderef);
  1142. ppufile.putbyte(byte(tempinfo^.temptype));
  1143. ppuwritenode(ppufile,tempinfo^.withnode);
  1144. ppuwritenode(ppufile,ftemplvalue);
  1145. end;
  1146. procedure ttempcreatenode.buildderefimpl;
  1147. begin
  1148. inherited buildderefimpl;
  1149. tempinfo^.typedefderef.build(tempinfo^.typedef);
  1150. if assigned(tempinfo^.withnode) then
  1151. tempinfo^.withnode.buildderefimpl;
  1152. if assigned(ftemplvalue) then
  1153. ftemplvalue.buildderefimpl;
  1154. end;
  1155. procedure ttempcreatenode.derefimpl;
  1156. begin
  1157. inherited derefimpl;
  1158. tempinfo^.typedef:=tdef(tempinfo^.typedefderef.resolve);
  1159. if assigned(tempinfo^.withnode) then
  1160. tempinfo^.withnode.derefimpl;
  1161. if assigned(ftemplvalue) then
  1162. begin
  1163. ftemplvalue.derefimpl;
  1164. tempinfo^.tempinitcode:=cassignmentnode.create(ctemprefnode.create(self),ftemplvalue);
  1165. end;
  1166. end;
  1167. function ttempcreatenode.pass_1 : tnode;
  1168. begin
  1169. result := nil;
  1170. expectloc:=LOC_VOID;
  1171. { temps which are immutable do not need to be initialized/finalized }
  1172. if (tempinfo^.typedef.needs_inittable) and not(ti_const in tempflags) then
  1173. include(current_procinfo.flags,pi_needs_implicit_finally);
  1174. if assigned(tempinfo^.withnode) then
  1175. firstpass(tempinfo^.withnode);
  1176. if assigned(tempinfo^.tempinitcode) then
  1177. firstpass(tempinfo^.tempinitcode);
  1178. inc(current_procinfo.estimatedtempsize,size);
  1179. end;
  1180. function ttempcreatenode.pass_typecheck: tnode;
  1181. begin
  1182. result := nil;
  1183. { a tempcreatenode doesn't have a resultdef, only temprefnodes do }
  1184. resultdef := voidtype;
  1185. if assigned(tempinfo^.withnode) then
  1186. typecheckpass(tempinfo^.withnode);
  1187. if assigned(tempinfo^.tempinitcode) then
  1188. typecheckpass(tempinfo^.tempinitcode);
  1189. end;
  1190. function ttempcreatenode.docompare(p: tnode): boolean;
  1191. begin
  1192. result :=
  1193. inherited docompare(p) and
  1194. (ttempcreatenode(p).size = size) and
  1195. (ttempcreatenode(p).tempflags*tempinfostoreflags=tempflags*tempinfostoreflags) and
  1196. equal_defs(ttempcreatenode(p).tempinfo^.typedef,tempinfo^.typedef) and
  1197. (ttempcreatenode(p).tempinfo^.withnode.isequal(tempinfo^.withnode)) and
  1198. (ttempcreatenode(p).tempinfo^.tempinitcode.isequal(tempinfo^.tempinitcode));
  1199. end;
  1200. procedure ttempcreatenode.printnodedata(var t:text);
  1201. var
  1202. f: ttempinfoflag;
  1203. first: Boolean;
  1204. begin
  1205. inherited printnodedata(t);
  1206. writeln(t,printnodeindention,'size = ',size,', temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
  1207. tempinfo^.typedef.GetTypeName,'", tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  1208. write(t,printnodeindention,'[');
  1209. first:=true;
  1210. for f in tempflags do
  1211. begin
  1212. if not(first) then
  1213. write(t,',');
  1214. write(t,f);
  1215. first:=false;
  1216. end;
  1217. writeln(t,']');
  1218. writeln(t,printnodeindention,'tempinit =');
  1219. printnode(t,tempinfo^.tempinitcode);
  1220. end;
  1221. {$ifdef DEBUG_NODE_XML}
  1222. procedure TTempCreateNode.XMLPrintNodeData(var T: Text);
  1223. begin
  1224. inherited XMLPrintNodeData(T);
  1225. WriteLn(T, PrintNodeIndention, '<size>', size, '</size>');
  1226. if Assigned(TempInfo^.TempInitCode) then
  1227. begin
  1228. WriteLn(T, PrintNodeIndention, '<tempinit>');
  1229. PrintNodeIndent;
  1230. XMLPrintNode(T, TempInfo^.TempInitCode);
  1231. PrintNodeUnindent;
  1232. WriteLn(T, PrintNodeIndention, '</tempinit>');
  1233. end
  1234. else
  1235. WriteLn(T, PrintNodeIndention, '<tempinit />');
  1236. end;
  1237. {$endif DEBUG_NODE_XML}
  1238. {*****************************************************************************
  1239. TEMPREFNODE
  1240. *****************************************************************************}
  1241. constructor ttemprefnode.create(const temp: ttempcreatenode);
  1242. begin
  1243. inherited create(temprefn);
  1244. tempinfo := temp.tempinfo;
  1245. end;
  1246. function ttemprefnode.dogetcopy: tnode;
  1247. var
  1248. n: ttemprefnode;
  1249. begin
  1250. n := ttemprefnode(inherited dogetcopy);
  1251. if assigned(tempinfo^.hookoncopy) then
  1252. { if the temp has been copied, assume it becomes a new }
  1253. { temp which has to be hooked by the copied reference }
  1254. begin
  1255. { hook the ref to the copied temp }
  1256. n.tempinfo := tempinfo^.hookoncopy;
  1257. { if we passed a ttempdeletenode that changed the temp }
  1258. { from a persistent one into a normal one, we must be }
  1259. { the last reference (since our parent should free the }
  1260. { temp (JM) }
  1261. if (ti_nextref_set_hookoncopy_nil in tempflags) then
  1262. tempinfo^.hookoncopy := nil;
  1263. end
  1264. else
  1265. { if the temp we refer to hasn't been copied, assume }
  1266. { we're just a new reference to that temp }
  1267. begin
  1268. n.tempinfo := tempinfo;
  1269. end;
  1270. if not assigned(n.tempinfo) then
  1271. internalerror(2005071901);
  1272. result := n;
  1273. end;
  1274. constructor ttemprefnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  1275. begin
  1276. inherited ppuload(t,ppufile);
  1277. tempidx:=ppufile.getlongint;
  1278. end;
  1279. procedure ttemprefnode.ppuwrite(ppufile:tcompilerppufile);
  1280. begin
  1281. inherited ppuwrite(ppufile);
  1282. ppufile.putlongint(tempinfo^.owner.ppuidx);
  1283. end;
  1284. procedure ttemprefnode.resolveppuidx;
  1285. var
  1286. temp : ttempcreatenode;
  1287. begin
  1288. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  1289. if temp.nodetype<>tempcreaten then
  1290. internalerror(200311075);
  1291. tempinfo:=temp.tempinfo;
  1292. end;
  1293. function ttemprefnode.pass_1 : tnode;
  1294. begin
  1295. expectloc := LOC_REFERENCE;
  1296. if not tempinfo^.typedef.needs_inittable and
  1297. (ti_may_be_in_reg in tempflags) then
  1298. begin
  1299. if tempinfo^.typedef.typ=floatdef then
  1300. begin
  1301. if not use_vectorfpu(tempinfo^.typedef) then
  1302. if (tempinfo^.temptype = tt_persistent) then
  1303. expectloc := LOC_CFPUREGISTER
  1304. else
  1305. expectloc := LOC_FPUREGISTER
  1306. else
  1307. if (tempinfo^.temptype = tt_persistent) then
  1308. expectloc := LOC_CMMREGISTER
  1309. else
  1310. expectloc := LOC_MMREGISTER
  1311. end
  1312. else
  1313. begin
  1314. if (tempinfo^.temptype = tt_persistent) then
  1315. expectloc := LOC_CREGISTER
  1316. else
  1317. expectloc := LOC_REGISTER;
  1318. end;
  1319. end;
  1320. result := nil;
  1321. end;
  1322. function ttemprefnode.pass_typecheck: tnode;
  1323. begin
  1324. { check if the temp is already resultdef passed }
  1325. if not assigned(tempinfo^.typedef) then
  1326. internalerror(200108233);
  1327. result := nil;
  1328. resultdef := tempinfo^.typedef;
  1329. end;
  1330. function ttemprefnode.docompare(p: tnode): boolean;
  1331. begin
  1332. result :=
  1333. inherited docompare(p) and
  1334. (ttemprefnode(p).tempinfo = tempinfo);
  1335. end;
  1336. procedure ttemprefnode.mark_write;
  1337. begin
  1338. include(flags,nf_write);
  1339. end;
  1340. procedure ttemprefnode.printnodedata(var t:text);
  1341. var
  1342. f : ttempinfoflag;
  1343. notfirst : Boolean;
  1344. begin
  1345. inherited printnodedata(t);
  1346. write(t,printnodeindention,'temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
  1347. tempinfo^.typedef.GetTypeName,'", (tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2),' flags = [');
  1348. notfirst:=false;
  1349. for f in tempinfo^.flags do
  1350. begin
  1351. if notfirst then
  1352. write(t,',');
  1353. write(t,f);
  1354. notfirst:=true;
  1355. end;
  1356. writeln(t,'])');
  1357. end;
  1358. {*****************************************************************************
  1359. TEMPDELETENODE
  1360. *****************************************************************************}
  1361. constructor ttempdeletenode.create(const temp: ttempcreatenode);
  1362. begin
  1363. inherited create(tempdeleten);
  1364. tempinfo := temp.tempinfo;
  1365. release_to_normal := false;
  1366. end;
  1367. constructor ttempdeletenode.create_normal_temp(const temp: ttempcreatenode);
  1368. begin
  1369. inherited create(tempdeleten);
  1370. tempinfo := temp.tempinfo;
  1371. release_to_normal := true;
  1372. if tempinfo^.temptype <> tt_persistent then
  1373. internalerror(200204211);
  1374. end;
  1375. function ttempdeletenode.dogetcopy: tnode;
  1376. var
  1377. n: ttempdeletenode;
  1378. begin
  1379. n:=ttempdeletenode(inherited dogetcopy);
  1380. n.release_to_normal:=release_to_normal;
  1381. if assigned(tempinfo^.hookoncopy) then
  1382. { if the temp has been copied, assume it becomes a new }
  1383. { temp which has to be hooked by the copied deletenode }
  1384. begin
  1385. { hook the tempdeletenode to the copied temp }
  1386. n.tempinfo:=tempinfo^.hookoncopy;
  1387. { the temp shall not be used, reset hookoncopy }
  1388. { Only if release_to_normal is false, otherwise }
  1389. { the temp can still be referenced once more (JM) }
  1390. if (not release_to_normal) then
  1391. tempinfo^.hookoncopy:=nil
  1392. else
  1393. includetempflag(ti_nextref_set_hookoncopy_nil);
  1394. end
  1395. else
  1396. { if the temp we refer to hasn't been copied, we have a }
  1397. { problem since that means we now have two delete nodes }
  1398. { for one temp }
  1399. internalerror(200108234);
  1400. result:=n;
  1401. end;
  1402. constructor ttempdeletenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  1403. begin
  1404. inherited ppuload(t,ppufile);
  1405. tempidx:=ppufile.getlongint;
  1406. release_to_normal:=(ppufile.getbyte<>0);
  1407. end;
  1408. procedure ttempdeletenode.ppuwrite(ppufile:tcompilerppufile);
  1409. begin
  1410. inherited ppuwrite(ppufile);
  1411. ppufile.putlongint(tempinfo^.owner.ppuidx);
  1412. ppufile.putbyte(byte(release_to_normal));
  1413. end;
  1414. procedure ttempdeletenode.resolveppuidx;
  1415. var
  1416. temp : ttempcreatenode;
  1417. begin
  1418. temp:=ttempcreatenode(nodeppuidxget(tempidx));
  1419. if temp.nodetype<>tempcreaten then
  1420. internalerror(200311075);
  1421. tempinfo:=temp.tempinfo;
  1422. end;
  1423. function ttempdeletenode.pass_1 : tnode;
  1424. begin
  1425. expectloc:=LOC_VOID;
  1426. result := nil;
  1427. end;
  1428. function ttempdeletenode.pass_typecheck: tnode;
  1429. begin
  1430. result := nil;
  1431. resultdef := voidtype;
  1432. end;
  1433. function ttempdeletenode.docompare(p: tnode): boolean;
  1434. begin
  1435. result :=
  1436. inherited docompare(p) and
  1437. (ttemprefnode(p).tempinfo = tempinfo);
  1438. end;
  1439. destructor ttempdeletenode.destroy;
  1440. begin
  1441. tempinfo^.withnode.free;
  1442. tempinfo^.tempinitcode.free;
  1443. dispose(tempinfo);
  1444. inherited destroy;
  1445. end;
  1446. procedure ttempdeletenode.printnodedata(var t:text);
  1447. begin
  1448. inherited printnodedata(t);
  1449. writeln(t,printnodeindention,'release_to_normal: ',release_to_normal,', temptypedef = ',tempinfo^.typedef.typesymbolprettyname,' = "',
  1450. tempinfo^.typedef.GetTypeName,'", temptype = ',tempinfo^.temptype,', tempinfo = $',hexstr(ptrint(tempinfo),sizeof(ptrint)*2));
  1451. end;
  1452. {$ifdef DEBUG_NODE_XML}
  1453. procedure TTempDeleteNode.XMLPrintNodeData(var T: Text);
  1454. begin
  1455. inherited XMLPrintNodeData(T);
  1456. WriteLn(T, PrintNodeIndention, '<release_to_normal>', release_to_normal, '</release_to_normal>');
  1457. end;
  1458. {$endif DEBUG_NODE_XML}
  1459. end.