nbas.pas 56 KB

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