rgobj.pas 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the base class for the register allocator
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$i fpcdefs.inc}
  19. { Allow duplicate allocations, can be used to get the .s file written }
  20. { $define ALLOWDUPREG}
  21. {#******************************************************************************
  22. @abstract(Abstract register allocator unit)
  23. Register allocator introduction.
  24. Free Pascal uses a Chaitin style register allocator. We use a variant similair
  25. to the one described in the book "Modern compiler implementation in C" by
  26. Andrew W. Appel., published by Cambridge University Press.
  27. The register allocator that is described by Appel uses a much improved way
  28. of register coalescing, called "iterated register coalescing". Instead
  29. of doing coalescing as a prepass to the register allocation, the coalescing
  30. is done inside the register allocator. This has the advantage that the
  31. register allocator can coalesce very aggresively without introducing spills.
  32. Reading this book is recommended for a complete understanding. Here is a small
  33. introduction.
  34. The code generator thinks it has an infinite amount of registers. Our processor
  35. has a limited amount of registers. Therefore we must reduce the amount of
  36. registers until there are less enough to fit into the processors registers.
  37. Registers can interfere or not interfere. If two imaginary registers interfere
  38. they cannot be placed into the same psysical register. Reduction of registers
  39. is done by:
  40. - "coalescing" Two registers that do not interfere are combined
  41. into one register.
  42. - "spilling" A register is changed into a memory location and the generated
  43. code is modified to use the memory location instead of the register.
  44. Register allocation is a graph colouring problem. Each register is a colour, and
  45. if two registers interfere there is a connection between them in the graph.
  46. In addition to the imaginary registers in the code generator, the psysical
  47. CPU registers are also present in this graph. This allows us to make
  48. interferences between imaginary registers and cpu registers. This is very
  49. usefull for describing archtectural constraints, like for example that
  50. the div instruction modifies edx, so variables that are in use at that time
  51. cannot be stored into edx. This can be modelled by making edx interfere
  52. with those variables.
  53. Graph colouring is an NP complete problem. Therefore we use an approximation
  54. that pushes registers to colour on to a stack. This is done in the "simplify"
  55. procedure.
  56. The register allocator first checks which registers are a candidate for
  57. coalescing.
  58. *******************************************************************************}
  59. unit rgobj;
  60. interface
  61. uses
  62. cutils, cpubase,
  63. aasmbase,aasmtai,aasmcpu,
  64. cclasses,globtype,cgbase,node,
  65. {$ifdef delphi}
  66. dmisc,
  67. {$endif}
  68. cpuinfo
  69. ;
  70. const
  71. ALL_OTHERREGISTERS=[low(tregisterindex)..high(tregisterindex)];
  72. type
  73. regvarother_longintarray = array[tregisterindex] of longint;
  74. regvarother_booleanarray = array[tregisterindex] of boolean;
  75. regvarint_longintarray = array[first_int_supreg..last_int_supreg] of longint;
  76. regvarint_ptreearray = array[first_int_supreg..last_int_supreg] of tnode;
  77. tpushedsavedloc = record
  78. case byte of
  79. 0: (pushed: boolean);
  80. 1: (ofs: longint);
  81. end;
  82. tpushedsavedother = array[tregisterindex] of tpushedsavedloc;
  83. Tinterferencebitmap=array[Tsuperregister] of set of Tsuperregister;
  84. Tinterferenceadjlist=array[Tsuperregister] of Pstring;
  85. Tinterferencegraph=record
  86. bitmap:Tinterferencebitmap;
  87. adjlist:Tinterferenceadjlist;
  88. end;
  89. Pinterferencegraph=^Tinterferencegraph;
  90. Tmovelist=record
  91. count:cardinal;
  92. data:array[0..$ffff] of Tlinkedlistitem;
  93. end;
  94. Pmovelist=^Tmovelist;
  95. {In the register allocator we keep track of move instructions.
  96. These instructions are moved between five linked lists. There
  97. is also a linked list per register to keep track about the moves
  98. it is associated with. Because we need to determine quickly in
  99. which of the five lists it is we add anu enumeradtion to each
  100. move instruction.}
  101. Tmoveset=(ms_coalesced_moves,ms_constrained_moves,ms_frozen_moves,
  102. ms_worklist_moves,ms_active_moves);
  103. Tmoveins=class(Tlinkedlistitem)
  104. moveset:Tmoveset;
  105. { $ifdef ra_debug}
  106. x,y:Tsuperregister;
  107. { $endif}
  108. instruction:Taicpu;
  109. end;
  110. {#------------------------------------------------------------------
  111. This class implements the abstract register allocator. It is used by the
  112. code generator to allocate and free registers which might be valid across
  113. nodes. It also contains utility routines related to registers.
  114. Some of the methods in this class should be overriden
  115. by cpu-specific implementations.
  116. --------------------------------------------------------------------}
  117. trgobj=class
  118. preserved_by_proc,used_in_proc:Tsuperregisterset;
  119. is_reg_var:Tsuperregisterset; {old regvars}
  120. reg_var_loaded:Tsuperregisterset; {old regvars}
  121. {# The register allocator assigns each register a colour.}
  122. colour:array[Tsuperregister] of Tsuperregister;
  123. spillednodes:string;
  124. constructor create(Acpu_registers:byte;
  125. Aregtype:Tregistertype;
  126. Adefaultsub:Tsubregister;
  127. const Ausable:string;
  128. Afirst_imaginary:Tsuperregister;
  129. Apreserved_by_proc:Tsuperregisterset);
  130. destructor destroy;override;
  131. {# Allocate a register. An internalerror will be generated if there is
  132. no more free registers which can be allocated.}
  133. function getregister(list:Taasmoutput;subreg:Tsubregister):Tregister;
  134. procedure add_constraints(reg:Tregister);virtual;
  135. {# Allocate an ABT register. An internalerror will be generated if there
  136. are no more free registers that can be allocated. An explanantion of
  137. abt registers can be found near the implementation.}
  138. function getabtregister(list:Taasmoutput;subreg:Tsubregister):Tregister;
  139. {# Get the register specified.}
  140. procedure getexplicitregister(list:Taasmoutput;r:Tregister);
  141. {# Get multiple registers specified.}
  142. procedure allocexplicitregisters(list:Taasmoutput;r:Tsuperregisterset);
  143. {# Free multiple registers specified.}
  144. procedure deallocexplicitregisters(list:Taasmoutput;r:Tsuperregisterset);
  145. {# Deallocate any kind of register }
  146. procedure ungetregister(list:Taasmoutput;r:Tregister);virtual;
  147. {# Do the register allocation.}
  148. procedure do_register_allocation(list:Taasmoutput;headertai:tai);
  149. { procedure resetusableregisters;virtual;}
  150. { procedure makeregvar(reg:Tsuperregister);}
  151. {$ifdef EXTDEBUG}
  152. procedure writegraph(loopidx:longint);
  153. {$endif EXTDEBUG}
  154. procedure add_move_instruction(instr:Taicpu);
  155. {# Prepare the register colouring.}
  156. procedure prepare_colouring;
  157. {# Clean up after register colouring.}
  158. procedure epilogue_colouring;
  159. {# Colour the registers; that is do the register allocation.}
  160. procedure colour_registers;
  161. {# Spills certain registers in the specified assembler list.}
  162. function spill_registers(list:Taasmoutput;headertai:tai;const regs_to_spill:string):boolean;
  163. {# Adds an interference edge.}
  164. procedure add_edge(u,v:Tsuperregister);
  165. unusedregs,usableregs:Tsuperregisterset;
  166. protected
  167. regtype:Tregistertype;
  168. { default subregister used }
  169. defaultsub:tsubregister;
  170. {# First imaginary register.}
  171. first_imaginary,
  172. {# Last register allocated.}
  173. lastused,
  174. {# Highest register allocated until now.}
  175. maxreg:Tsuperregister;
  176. usable_registers:string[32];
  177. countusableregs:byte; {old regvars}
  178. cpu_registers:byte;
  179. igraph:Tinterferencegraph;
  180. degree:array[0..255] of byte;
  181. alias:array[Tsuperregister] of Tsuperregister;
  182. simplifyworklist,freezeworklist,spillworklist:string;
  183. coalescednodes:string;
  184. selectstack:string;
  185. abtlist:string;
  186. movelist:array[Tsuperregister] of Pmovelist;
  187. worklist_moves,active_moves,frozen_moves,
  188. coalesced_moves,constrained_moves:Tlinkedlist;
  189. procedure getregisterinline(list:Taasmoutput;position:Tai;subreg:Tsubregister;var result:Tregister);
  190. procedure ungetregisterinline(list:Taasmoutput;position:Tai;r:Tregister);
  191. procedure add_edges_used(u:Tsuperregister);
  192. procedure add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  193. function move_related(n:Tsuperregister):boolean;
  194. procedure make_work_list;
  195. procedure enable_moves(n:Tsuperregister);
  196. procedure decrement_degree(m:Tsuperregister);
  197. procedure simplify;
  198. function get_alias(n:Tsuperregister):Tsuperregister;
  199. procedure add_worklist(u:Tsuperregister);
  200. function adjacent_ok(u,v:Tsuperregister):boolean;
  201. function conservative(u,v:Tsuperregister):boolean;
  202. procedure combine(u,v:Tsuperregister);
  203. procedure coalesce;
  204. procedure freeze_moves(u:Tsuperregister);
  205. procedure freeze;
  206. procedure select_spill;
  207. procedure assign_colours;
  208. procedure clear_interferences(u:Tsuperregister);
  209. end;
  210. const {# This value is used in tsaved. If the array value is equal
  211. to this, then this means that this register is not used.}
  212. reg_not_saved = $7fffffff;
  213. first_reg = 0;
  214. last_reg = 254;
  215. maxspillingcounter = 20;
  216. implementation
  217. uses
  218. systems,
  219. globals,verbose,tgobj,procinfo;
  220. {******************************************************************************
  221. trgobj
  222. ******************************************************************************}
  223. constructor trgobj.create(Acpu_registers:byte;
  224. Aregtype:Tregistertype;
  225. Adefaultsub:Tsubregister;
  226. const Ausable:string;
  227. Afirst_imaginary:Tsuperregister;
  228. Apreserved_by_proc:Tsuperregisterset);
  229. var i:Tsuperregister;
  230. begin
  231. used_in_proc:=[];
  232. { resetusableregisters;}
  233. lastused:=0;
  234. maxreg:=Afirst_imaginary;
  235. first_imaginary:=Afirst_imaginary;
  236. cpu_registers:=Acpu_registers;
  237. regtype:=Aregtype;
  238. defaultsub:=Adefaultsub;
  239. unusedregs:=[first_reg..last_reg]; { 255 (RS_INVALID) can't be used }
  240. {$ifdef powerpc}
  241. preserved_by_proc:=[RS_R13..RS_R31];
  242. {$else powerpc}
  243. preserved_by_proc:=[];
  244. {$endif powerpc}
  245. fillchar(igraph,sizeof(igraph),0);
  246. fillchar(degree,sizeof(degree),0);
  247. {Precoloured nodes should have an infinite degree, which we can approach
  248. by 255.}
  249. for i:=0 to first_imaginary-1 do
  250. degree[i]:=255;
  251. fillchar(movelist,sizeof(movelist),0);
  252. worklist_moves:=Tlinkedlist.create;
  253. usable_registers:=Ausable;
  254. abtlist:='';
  255. fillchar(colour,sizeof(colour),RS_INVALID);
  256. end;
  257. destructor trgobj.destroy;
  258. var i:Tsuperregister;
  259. begin
  260. for i:=low(Tsuperregister) to high(Tsuperregister) do
  261. begin
  262. if igraph.adjlist[i]<>nil then
  263. dispose(igraph.adjlist[i]);
  264. if movelist[i]<>nil then
  265. dispose(movelist[i]);
  266. end;
  267. worklist_moves.free;
  268. end;
  269. function trgobj.getregister(list:Taasmoutput;subreg:Tsubregister):Tregister;
  270. var i,p:Tsuperregister;
  271. r:Tregister;
  272. min : byte;
  273. adj : pstring;
  274. begin
  275. if maxreg<last_reg then
  276. begin
  277. inc(maxreg);
  278. p:=maxreg;
  279. min:=0;
  280. end
  281. else
  282. begin
  283. min:=$ff;
  284. p:=first_imaginary;
  285. for i:=first_imaginary to maxreg do
  286. if (i in unusedregs) and
  287. (pos(char(i),abtlist)=0) then
  288. begin
  289. adj:=igraph.adjlist[Tsuperregister(i)];
  290. if adj=nil then
  291. begin
  292. p:=i;
  293. min:=0;
  294. break; {We won't find smaller ones.}
  295. end
  296. else
  297. if length(adj^)<min then
  298. begin
  299. p:=i;
  300. min:=length(adj^);
  301. if min=0 then
  302. break; {We won't find smaller ones.}
  303. end;
  304. end;
  305. if min=$ff then
  306. begin
  307. {$ifdef ALLOWDUPREG}
  308. result:=newreg(regtype,RS_INVALID,subreg);
  309. exit;
  310. {$else}
  311. internalerror(10);
  312. {$endif}
  313. end;
  314. end;
  315. exclude(unusedregs,p);
  316. include(used_in_proc,p);
  317. r:=newreg(regtype,p,subreg);
  318. list.concat(Tai_regalloc.alloc(r));
  319. add_edges_used(p);
  320. add_constraints(r);
  321. result:=r;
  322. end;
  323. procedure trgobj.ungetregister(list:Taasmoutput;r:Tregister);
  324. var supreg:Tsuperregister;
  325. begin
  326. supreg:=getsupreg(r);
  327. if not (supreg in unusedregs) then
  328. begin
  329. include(unusedregs,supreg);
  330. list.concat(Tai_regalloc.dealloc(r));
  331. add_edges_used(supreg);
  332. add_constraints(r);
  333. end;
  334. end;
  335. procedure trgobj.getexplicitregister(list:Taasmoutput;r:Tregister);
  336. var supreg:Tsuperregister;
  337. begin
  338. supreg:=getsupreg(r);
  339. if supreg in unusedregs then
  340. begin
  341. exclude(unusedregs,supreg);
  342. include(used_in_proc,supreg);
  343. list.concat(Tai_regalloc.alloc(r));
  344. add_edges_used(supreg);
  345. add_constraints(r);
  346. end
  347. else
  348. {$ifndef ALLOWDUPREG}
  349. internalerror(200301103)
  350. {$endif ALLOWDUPREG}
  351. ;
  352. end;
  353. procedure trgobj.allocexplicitregisters(list:Taasmoutput;r:Tsuperregisterset);
  354. var reg:Tregister;
  355. i:Tsuperregister;
  356. begin
  357. if unusedregs*r=r then
  358. begin
  359. unusedregs:=unusedregs-r;
  360. used_in_proc:=used_in_proc+r;
  361. for i:=0 to first_imaginary-1 do
  362. if i in r then
  363. begin
  364. add_edges_used(i);
  365. reg:=newreg(regtype,i,R_SUBWHOLE);
  366. list.concat(Tai_regalloc.alloc(reg));
  367. end;
  368. end
  369. else
  370. {$ifndef ALLOWDUPREG}
  371. internalerror(200305061)
  372. {$endif ALLOWDUPREG}
  373. ;
  374. end;
  375. procedure trgobj.deallocexplicitregisters(list:Taasmoutput;r:Tsuperregisterset);
  376. var reg:Tregister;
  377. i:Tsuperregister;
  378. begin
  379. if unusedregs*r=[] then
  380. begin
  381. unusedregs:=unusedregs+r;
  382. for i:=first_imaginary-1 downto 0 do
  383. if i in r then
  384. begin
  385. reg:=newreg(regtype,i,R_SUBWHOLE);
  386. list.concat(Tai_regalloc.dealloc(reg));
  387. end;
  388. end
  389. else
  390. internalerror(200305061);
  391. end;
  392. procedure trgobj.do_register_allocation(list:Taasmoutput;headertai:tai);
  393. var spillingcounter:byte;
  394. fastspill:boolean;
  395. begin
  396. {Do register allocation.}
  397. spillingcounter:=0;
  398. repeat
  399. prepare_colouring;
  400. colour_registers;
  401. epilogue_colouring;
  402. fastspill:=true;
  403. if spillednodes<>'' then
  404. begin
  405. inc(spillingcounter);
  406. if spillingcounter>maxspillingcounter then
  407. internalerror(200309041);
  408. fastspill:=spill_registers(list,headertai,spillednodes);
  409. end;
  410. until (spillednodes='') or not fastspill;
  411. end;
  412. procedure trgobj.add_constraints(reg:Tregister);
  413. begin
  414. end;
  415. procedure trgobj.add_edge(u,v:Tsuperregister);
  416. {This procedure will add an edge to the virtual interference graph.}
  417. procedure addadj(u,v:Tsuperregister);
  418. begin
  419. if igraph.adjlist[u]=nil then
  420. begin
  421. getmem(igraph.adjlist[u],16);
  422. igraph.adjlist[u]^:='';
  423. end
  424. else if (length(igraph.adjlist[u]^) and 15)=15 then
  425. reallocmem(igraph.adjlist[u],length(igraph.adjlist[u]^)+16);
  426. igraph.adjlist[u]^:=igraph.adjlist[u]^+char(v);
  427. end;
  428. begin
  429. if (u<>v) and not(v in igraph.bitmap[u]) then
  430. begin
  431. include(igraph.bitmap[u],v);
  432. include(igraph.bitmap[v],u);
  433. {Precoloured nodes are not stored in the interference graph.}
  434. if not(u in [first_int_supreg..last_int_supreg]) then
  435. begin
  436. addadj(u,v);
  437. inc(degree[u]);
  438. end;
  439. if not(v in [first_int_supreg..last_int_supreg]) then
  440. begin
  441. addadj(v,u);
  442. inc(degree[v]);
  443. end;
  444. end;
  445. end;
  446. procedure trgobj.add_edges_used(u:Tsuperregister);
  447. var i:Tsuperregister;
  448. begin
  449. for i:=0 to maxreg do
  450. if not(i in unusedregs) then
  451. add_edge(u,i);
  452. end;
  453. {$ifdef EXTDEBUG}
  454. procedure trgobj.writegraph(loopidx:longint);
  455. {This procedure writes out the current interference graph in the
  456. register allocator.}
  457. var f:text;
  458. i,j:Tsuperregister;
  459. begin
  460. assign(f,'igraph'+tostr(loopidx));
  461. rewrite(f);
  462. writeln(f,'Interference graph');
  463. writeln(f);
  464. write(f,' ');
  465. for i:=0 to 15 do
  466. for j:=0 to 15 do
  467. write(f,hexstr(i,1));
  468. writeln(f);
  469. write(f,' ');
  470. for i:=0 to 15 do
  471. write(f,'0123456789ABCDEF');
  472. writeln(f);
  473. for i:=0 to 255 do
  474. begin
  475. write(f,hexstr(i,2):4);
  476. for j:=0 to 255 do
  477. if j in igraph.bitmap[i] then
  478. write(f,'*')
  479. else
  480. write(f,'-');
  481. writeln(f);
  482. end;
  483. close(f);
  484. end;
  485. {$endif EXTDEBUG}
  486. procedure trgobj.add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  487. begin
  488. if movelist[u]=nil then
  489. begin
  490. getmem(movelist[u],64);
  491. movelist[u]^.count:=0;
  492. end
  493. else if (movelist[u]^.count and 15)=15 then
  494. reallocmem(movelist[u],(movelist[u]^.count+1)*4+64);
  495. movelist[u]^.data[movelist[u]^.count]:=data;
  496. inc(movelist[u]^.count);
  497. end;
  498. procedure trgobj.add_move_instruction(instr:Taicpu);
  499. {This procedure notifies a certain as a move instruction so the
  500. register allocator can try to eliminate it.}
  501. var i:Tmoveins;
  502. ssupreg,dsupreg:Tsuperregister;
  503. begin
  504. i:=Tmoveins.create;
  505. i.moveset:=ms_worklist_moves;
  506. i.instruction:=instr;
  507. worklist_moves.insert(i);
  508. ssupreg:=getsupreg(instr.oper[O_MOV_SOURCE].reg);
  509. add_to_movelist(ssupreg,i);
  510. dsupreg:=getsupreg(instr.oper[O_MOV_DEST].reg);
  511. if ssupreg<>dsupreg then
  512. {Avoid adding the same move instruction twice to a single register.}
  513. add_to_movelist(dsupreg,i);
  514. i.x:=ssupreg;
  515. i.y:=dsupreg;
  516. end;
  517. function trgobj.move_related(n:Tsuperregister):boolean;
  518. var i:cardinal;
  519. begin
  520. move_related:=false;
  521. if movelist[n]<>nil then
  522. begin
  523. for i:=0 to movelist[n]^.count-1 do
  524. if Tmoveins(movelist[n]^.data[i]).moveset in
  525. [ms_worklist_moves,ms_active_moves] then
  526. begin
  527. move_related:=true;
  528. break;
  529. end;
  530. end;
  531. end;
  532. procedure trgobj.make_work_list;
  533. var n:Tsuperregister;
  534. begin
  535. {If we have 7 cpu registers, and the degree of a node is 7, we cannot
  536. assign it to any of the registers, thus it is significant.}
  537. for n:=first_imaginary to maxreg do
  538. if degree[n]>=cpu_registers then
  539. spillworklist:=spillworklist+char(n)
  540. else if move_related(n) then
  541. freezeworklist:=freezeworklist+char(n)
  542. else
  543. simplifyworklist:=simplifyworklist+char(n);
  544. end;
  545. procedure trgobj.prepare_colouring;
  546. begin
  547. make_work_list;
  548. active_moves:=Tlinkedlist.create;
  549. frozen_moves:=Tlinkedlist.create;
  550. coalesced_moves:=Tlinkedlist.create;
  551. constrained_moves:=Tlinkedlist.create;
  552. fillchar(alias,sizeof(alias),0);
  553. coalescednodes:='';
  554. selectstack:='';
  555. end;
  556. procedure trgobj.enable_moves(n:Tsuperregister);
  557. var m:Tlinkedlistitem;
  558. i:cardinal;
  559. begin
  560. if movelist[n]<>nil then
  561. for i:=0 to movelist[n]^.count-1 do
  562. begin
  563. m:=movelist[n]^.data[i];
  564. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  565. begin
  566. if Tmoveins(m).moveset=ms_active_moves then
  567. begin
  568. {Move m from the set active_moves to the set worklist_moves.}
  569. active_moves.remove(m);
  570. Tmoveins(m).moveset:=ms_worklist_moves;
  571. worklist_moves.concat(m);
  572. end;
  573. end;
  574. end;
  575. end;
  576. procedure trgobj.decrement_degree(m:Tsuperregister);
  577. var adj:Pstring;
  578. d:byte;
  579. i,p:byte;
  580. n:char;
  581. begin
  582. d:=degree[m];
  583. if degree[m]>0 then
  584. dec(degree[m]);
  585. if d=cpu_registers then
  586. begin
  587. {Enable moves for m.}
  588. enable_moves(m);
  589. {Enable moves for adjacent.}
  590. adj:=igraph.adjlist[m];
  591. if adj<>nil then
  592. for i:=1 to length(adj^) do
  593. begin
  594. n:=adj^[i];
  595. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  596. enable_moves(Tsuperregister(n));
  597. end;
  598. {Remove the node from the spillworklist.}
  599. p:=pos(char(m),spillworklist);
  600. if p=0 then
  601. internalerror(200305301); {must be found}
  602. if length(spillworklist)>1 then
  603. spillworklist[p]:=spillworklist[length(spillworklist)];
  604. dec(spillworklist[0]);
  605. if move_related(m) then
  606. freezeworklist:=freezeworklist+char(m)
  607. else
  608. simplifyworklist:=simplifyworklist+char(m);
  609. end;
  610. end;
  611. procedure trgobj.simplify;
  612. var adj:Pstring;
  613. i,min,p:byte;
  614. m:char;
  615. n:Tsuperregister;
  616. begin
  617. {We the element with the least interferences out of the
  618. simplifyworklist.}
  619. min:=$ff;
  620. p:=1;
  621. for i:=1 to length(simplifyworklist) do
  622. begin
  623. adj:=igraph.adjlist[Tsuperregister(simplifyworklist[i])];
  624. if adj=nil then
  625. begin
  626. min:=0;
  627. break; {We won't find smaller ones.}
  628. end
  629. else
  630. if length(adj^)<min then
  631. begin
  632. min:=length(adj^);
  633. if min=0 then
  634. break; {We won't find smaller ones.}
  635. p:=i;
  636. end;
  637. end;
  638. n:=Tsuperregister(simplifyworklist[p]);
  639. if length(simplifyworklist)>1 then
  640. simplifyworklist[p]:=simplifyworklist[length(simplifyworklist)];
  641. dec(simplifyworklist[0]);
  642. {Push it on the selectstack.}
  643. selectstack:=selectstack+char(n);
  644. adj:=igraph.adjlist[n];
  645. if adj<>nil then
  646. for i:=1 to length(adj^) do
  647. begin
  648. m:=adj^[i];
  649. if ((pos(m,selectstack) or pos(m,coalescednodes))=0) and
  650. not (Tsuperregister(m) in [first_int_supreg..last_int_supreg]) then
  651. decrement_degree(Tsuperregister(m));
  652. end;
  653. end;
  654. function trgobj.get_alias(n:Tsuperregister):Tsuperregister;
  655. begin
  656. while pos(char(n),coalescednodes)<>0 do
  657. n:=alias[n];
  658. get_alias:=n;
  659. end;
  660. procedure trgobj.add_worklist(u:Tsuperregister);
  661. var p:byte;
  662. begin
  663. if not(u in [first_int_supreg..last_int_supreg]) and
  664. not move_related(u) and
  665. (degree[u]<cpu_registers) then
  666. begin
  667. p:=pos(char(u),freezeworklist);
  668. if p=0 then
  669. internalerror(200308161); {must be found}
  670. if length(freezeworklist)>1 then
  671. freezeworklist[p]:=freezeworklist[length(freezeworklist)];
  672. dec(freezeworklist[0]);
  673. simplifyworklist:=simplifyworklist+char(u);
  674. end;
  675. end;
  676. function trgobj.adjacent_ok(u,v:Tsuperregister):boolean;
  677. {Check wether u and v should be coalesced. u is precoloured.}
  678. function ok(t,r:Tsuperregister):boolean;
  679. begin
  680. ok:=(degree[t]<cpu_registers) or
  681. (t in [first_int_supreg..last_int_supreg]) or
  682. (r in igraph.bitmap[t]);
  683. end;
  684. var adj:Pstring;
  685. i:byte;
  686. t:char;
  687. begin
  688. adjacent_ok:=true;
  689. adj:=igraph.adjlist[v];
  690. if adj<>nil then
  691. for i:=1 to length(adj^) do
  692. begin
  693. t:=adj^[i];
  694. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  695. if not ok(Tsuperregister(t),u) then
  696. begin
  697. adjacent_ok:=false;
  698. break;
  699. end;
  700. end;
  701. end;
  702. function trgobj.conservative(u,v:Tsuperregister):boolean;
  703. var adj:Pstring;
  704. done:set of char; {To prevent that we count nodes twice.}
  705. i,k:byte;
  706. n:char;
  707. begin
  708. k:=0;
  709. done:=[];
  710. adj:=igraph.adjlist[u];
  711. if adj<>nil then
  712. for i:=1 to length(adj^) do
  713. begin
  714. n:=adj^[i];
  715. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  716. begin
  717. include(done,n);
  718. if degree[Tsuperregister(n)]>=cpu_registers then
  719. inc(k);
  720. end;
  721. end;
  722. adj:=igraph.adjlist[v];
  723. if adj<>nil then
  724. for i:=1 to length(adj^) do
  725. begin
  726. n:=adj^[i];
  727. if ((pos(n,selectstack) or pos(n,coalescednodes))=0) and
  728. not (n in done) and
  729. (degree[Tsuperregister(n)]>=cpu_registers) then
  730. inc(k);
  731. end;
  732. conservative:=(k<cpu_registers);
  733. end;
  734. procedure trgobj.combine(u,v:Tsuperregister);
  735. var add:boolean;
  736. adj:Pstring;
  737. i,p:byte;
  738. n,o:cardinal;
  739. t:char;
  740. decrement:boolean;
  741. begin
  742. p:=pos(char(v),freezeworklist);
  743. if p<>0 then
  744. delete(freezeworklist,p,1)
  745. else
  746. delete(spillworklist,pos(char(v),spillworklist),1);
  747. coalescednodes:=coalescednodes+char(v);
  748. alias[v]:=u;
  749. {Combine both movelists. Since the movelists are sets, only add
  750. elements that are not already present.}
  751. if assigned(movelist[v]) then
  752. begin
  753. for n:=0 to movelist[v]^.count-1 do
  754. begin
  755. add:=true;
  756. for o:=0 to movelist[u]^.count-1 do
  757. if movelist[u]^.data[o]=movelist[v]^.data[n] then
  758. begin
  759. add:=false;
  760. break;
  761. end;
  762. if add then
  763. add_to_movelist(u,movelist[v]^.data[n]);
  764. end;
  765. enable_moves(v);
  766. end;
  767. adj:=igraph.adjlist[v];
  768. if adj<>nil then
  769. for i:=1 to length(adj^) do
  770. begin
  771. t:=adj^[i];
  772. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  773. begin
  774. decrement:=(Tsuperregister(t)<>u) and not(u in igraph.bitmap[Tsuperregister(t)]);
  775. add_edge(Tsuperregister(t),u);
  776. {Do not call decrement_degree because it might move nodes between
  777. lists while the degree does not change (add_edge will increase it).
  778. Instead, we will decrement manually. (Only if the degree has been
  779. increased.)}
  780. if decrement and not (Tsuperregister(t) in [first_int_supreg..last_int_supreg])
  781. and (degree[Tsuperregister(t)]>0) then
  782. dec(degree[Tsuperregister(t)]);
  783. end;
  784. end;
  785. p:=pos(char(u),freezeworklist);
  786. if (degree[u]>=cpu_registers) and (p<>0) then
  787. begin
  788. delete(freezeworklist,p,1);
  789. spillworklist:=spillworklist+char(u);
  790. end;
  791. end;
  792. procedure trgobj.coalesce;
  793. var m:Tmoveins;
  794. x,y,u,v:Tsuperregister;
  795. begin
  796. m:=Tmoveins(worklist_moves.getfirst);
  797. x:=get_alias(getsupreg(m.instruction.oper[0].reg));
  798. y:=get_alias(getsupreg(m.instruction.oper[1].reg));
  799. if y in [first_int_supreg..last_int_supreg] then
  800. begin
  801. u:=y;
  802. v:=x;
  803. end
  804. else
  805. begin
  806. u:=x;
  807. v:=y;
  808. end;
  809. if (u=v) then
  810. begin
  811. m.moveset:=ms_coalesced_moves; {Already coalesced.}
  812. coalesced_moves.insert(m);
  813. add_worklist(u);
  814. end
  815. {Do u and v interfere? In that case the move is constrained. Two
  816. precoloured nodes interfere allways. If v is precoloured, by the above
  817. code u is precoloured, thus interference...}
  818. else if (v in [first_int_supreg..last_int_supreg]) or (u in igraph.bitmap[v]) then
  819. begin
  820. m.moveset:=ms_constrained_moves; {Cannot coalesce yet...}
  821. constrained_moves.insert(m);
  822. add_worklist(u);
  823. add_worklist(v);
  824. end
  825. {Next test: is it possible and a good idea to coalesce??}
  826. else if ((u in [first_int_supreg..last_int_supreg]) and adjacent_ok(u,v)) or
  827. (not(u in [first_int_supreg..last_int_supreg]) and conservative(u,v)) then
  828. begin
  829. m.moveset:=ms_coalesced_moves; {Move coalesced!}
  830. coalesced_moves.insert(m);
  831. combine(u,v);
  832. add_worklist(u);
  833. end
  834. else
  835. begin
  836. m.moveset:=ms_active_moves;
  837. active_moves.insert(m);
  838. end;
  839. end;
  840. procedure trgobj.freeze_moves(u:Tsuperregister);
  841. var i:cardinal;
  842. m:Tlinkedlistitem;
  843. v,x,y:Tsuperregister;
  844. begin
  845. if movelist[u]<>nil then
  846. for i:=0 to movelist[u]^.count-1 do
  847. begin
  848. m:=movelist[u]^.data[i];
  849. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  850. begin
  851. x:=getsupreg(Tmoveins(m).instruction.oper[0].reg);
  852. y:=getsupreg(Tmoveins(m).instruction.oper[1].reg);
  853. if get_alias(y)=get_alias(u) then
  854. v:=get_alias(x)
  855. else
  856. v:=get_alias(y);
  857. {Move m from active_moves/worklist_moves to frozen_moves.}
  858. if Tmoveins(m).moveset=ms_active_moves then
  859. active_moves.remove(m)
  860. else
  861. worklist_moves.remove(m);
  862. Tmoveins(m).moveset:=ms_frozen_moves;
  863. frozen_moves.insert(m);
  864. if not(v in [first_int_supreg..last_int_supreg]) and
  865. not(move_related(v)) and
  866. (degree[v]<cpu_registers) then
  867. begin
  868. delete(freezeworklist,pos(char(v),freezeworklist),1);
  869. simplifyworklist:=simplifyworklist+char(v);
  870. end;
  871. end;
  872. end;
  873. end;
  874. procedure trgobj.freeze;
  875. var n:Tsuperregister;
  876. begin
  877. {We need to take a random element out of the freezeworklist. We take
  878. the last element. Dirty code!}
  879. n:=Tsuperregister(freezeworklist[byte(freezeworklist[0])]);
  880. dec(freezeworklist[0]);
  881. {Add it to the simplifyworklist.}
  882. simplifyworklist:=simplifyworklist+char(n);
  883. freeze_moves(n);
  884. end;
  885. procedure trgobj.select_spill;
  886. var n:char;
  887. begin
  888. {This code is WAY too naive. We need not to select just a register, but
  889. the register that is used the least...}
  890. n:=spillworklist[byte(spillworklist[0])];
  891. dec(spillworklist[0]);
  892. simplifyworklist:=simplifyworklist+n;
  893. freeze_moves(Tsuperregister(n));
  894. end;
  895. procedure trgobj.assign_colours;
  896. {Assign_colours assigns the actual colours to the registers.}
  897. var adj:Pstring;
  898. i,j,k:byte;
  899. n,a,c:Tsuperregister;
  900. adj_colours,colourednodes:set of Tsuperregister;
  901. w:char;
  902. begin
  903. spillednodes:='';
  904. {Reset colours}
  905. for i:=0 to maxreg do
  906. colour[i]:=i;
  907. {Colour the cpu registers...}
  908. colourednodes:=[first_int_supreg..last_int_supreg];
  909. {Now colour the imaginary registers on the select-stack.}
  910. for i:=length(selectstack) downto 1 do
  911. begin
  912. n:=Tsuperregister(selectstack[i]);
  913. {Create a list of colours that we cannot assign to n.}
  914. adj_colours:=[];
  915. adj:=igraph.adjlist[n];
  916. if adj<>nil then
  917. for j:=1 to length(adj^) do
  918. begin
  919. w:=adj^[j];
  920. a:=get_alias(Tsuperregister(w));
  921. if a in colourednodes then
  922. include(adj_colours,colour[a]);
  923. end;
  924. include(adj_colours,RS_STACK_POINTER_REG);
  925. {Assume a spill by default...}
  926. spillednodes:=spillednodes+char(n);
  927. {Search for a colour not in this list.}
  928. for k:=1 to length(usable_registers) do
  929. begin
  930. c:=Tsuperregister(usable_registers[k]);
  931. if not(c in adj_colours) then
  932. begin
  933. colour[n]:=c;
  934. dec(spillednodes[0]); {Colour found: no spill.}
  935. include(colourednodes,n);
  936. if n in used_in_proc then
  937. include(used_in_proc,c);
  938. break;
  939. end;
  940. end;
  941. end;
  942. {Finally colour the nodes that were coalesced.}
  943. for i:=1 to length(coalescednodes) do
  944. begin
  945. n:=Tsuperregister(coalescednodes[i]);
  946. k:=get_alias(n);
  947. colour[n]:=colour[k];
  948. if n in used_in_proc then
  949. include(used_in_proc,colour[k]);
  950. end;
  951. {$ifdef ra_debug}
  952. if aktfilepos.line=2502 then
  953. begin
  954. writeln('colourlist ',length(freezeworklist));
  955. for i:=0 to maxintreg do
  956. writeln(i:4,' ',colour[i]:4)
  957. end;
  958. {$endif ra_debug}
  959. end;
  960. procedure trgobj.colour_registers;
  961. begin
  962. repeat
  963. if length(simplifyworklist)<>0 then
  964. simplify
  965. else if not(worklist_moves.empty) then
  966. coalesce
  967. else if length(freezeworklist)<>0 then
  968. freeze
  969. else if length(spillworklist)<>0 then
  970. select_spill;
  971. until (length(simplifyworklist)=0) and
  972. worklist_moves.empty and
  973. (length(freezeworklist)=0) and
  974. (length(spillworklist)=0);
  975. assign_colours;
  976. end;
  977. procedure trgobj.epilogue_colouring;
  978. {
  979. procedure move_to_worklist_moves(list:Tlinkedlist);
  980. var p:Tlinkedlistitem;
  981. begin
  982. p:=list.first;
  983. while p<>nil do
  984. begin
  985. Tmoveins(p).moveset:=ms_worklist_moves;
  986. p:=p.next;
  987. end;
  988. worklist_moves.concatlist(list);
  989. end;
  990. }
  991. var i:Tsuperregister;
  992. begin
  993. worklist_moves.clear;
  994. {$ifdef Principle_wrong_by_definition}
  995. {Move everything back to worklist_moves.}
  996. move_to_worklist_moves(active_moves);
  997. move_to_worklist_moves(frozen_moves);
  998. move_to_worklist_moves(coalesced_moves);
  999. move_to_worklist_moves(constrained_moves);
  1000. {$endif Principle_wrong_by_definition}
  1001. active_moves.destroy;
  1002. active_moves:=nil;
  1003. frozen_moves.destroy;
  1004. frozen_moves:=nil;
  1005. coalesced_moves.destroy;
  1006. coalesced_moves:=nil;
  1007. constrained_moves.destroy;
  1008. constrained_moves:=nil;
  1009. for i:=0 to 255 do
  1010. if movelist[i]<>nil then
  1011. begin
  1012. dispose(movelist[i]);
  1013. movelist[i]:=0;
  1014. end;
  1015. end;
  1016. procedure trgobj.clear_interferences(u:Tsuperregister);
  1017. {Remove node u from the interference graph and remove all collected
  1018. move instructions it is associated with.}
  1019. var i:byte;
  1020. j,k,count:cardinal;
  1021. v:Tsuperregister;
  1022. m,n:Tmoveins;
  1023. begin
  1024. if igraph.adjlist[u]<>nil then
  1025. begin
  1026. for i:=1 to length(igraph.adjlist[u]^) do
  1027. begin
  1028. v:=Tsuperregister(igraph.adjlist[u]^[i]);
  1029. {Remove (u,v) and (v,u) from bitmap.}
  1030. exclude(igraph.bitmap[u],v);
  1031. exclude(igraph.bitmap[v],u);
  1032. {Remove (v,u) from adjacency list.}
  1033. if igraph.adjlist[v]<>nil then
  1034. begin
  1035. delete(igraph.adjlist[v]^,pos(char(v),igraph.adjlist[v]^),1);
  1036. if length(igraph.adjlist[v]^)=0 then
  1037. begin
  1038. dispose(igraph.adjlist[v]);
  1039. igraph.adjlist[v]:=nil;
  1040. end;
  1041. end;
  1042. end;
  1043. {Remove ( u,* ) from adjacency list.}
  1044. dispose(igraph.adjlist[u]);
  1045. igraph.adjlist[u]:=nil;
  1046. end;
  1047. {$ifdef Principle_wrong_by_definition}
  1048. {Now remove the moves.}
  1049. if movelist[u]<>nil then
  1050. begin
  1051. for j:=0 to movelist[u]^.count-1 do
  1052. begin
  1053. m:=Tmoveins(movelist[u]^.data[j]);
  1054. {Get the other register of the move instruction.}
  1055. v:=m.instruction.oper[0].reg.number shr 8;
  1056. if v=u then
  1057. v:=m.instruction.oper[1].reg.number shr 8;
  1058. repeat
  1059. repeat
  1060. if (u<>v) and (movelist[v]<>nil) then
  1061. begin
  1062. {Remove the move from it's movelist.}
  1063. count:=movelist[v]^.count-1;
  1064. for k:=0 to count do
  1065. if m=movelist[v]^.data[k] then
  1066. begin
  1067. if k<>count then
  1068. movelist[v]^.data[k]:=movelist[v]^.data[count];
  1069. dec(movelist[v]^.count);
  1070. if count=0 then
  1071. begin
  1072. dispose(movelist[v]);
  1073. movelist[v]:=nil;
  1074. end;
  1075. break;
  1076. end;
  1077. end;
  1078. {The complexity is enourmous: the register might have been
  1079. coalesced. In that case it's movelists have been added to
  1080. it's coalescing alias. (DM)}
  1081. v:=alias[v];
  1082. until v=0;
  1083. {And also register u might have been coalesced.}
  1084. u:=alias[u];
  1085. until u=0;
  1086. case m.moveset of
  1087. ms_coalesced_moves:
  1088. coalesced_moves.remove(m);
  1089. ms_constrained_moves:
  1090. constrained_moves.remove(m);
  1091. ms_frozen_moves:
  1092. frozen_moves.remove(m);
  1093. ms_worklist_moves:
  1094. worklist_moves.remove(m);
  1095. ms_active_moves:
  1096. active_moves.remove(m);
  1097. end;
  1098. end;
  1099. dispose(movelist[u]);
  1100. movelist[u]:=nil;
  1101. end;
  1102. {$endif Principle_wrong_by_definition}
  1103. end;
  1104. procedure trgobj.getregisterinline(list:Taasmoutput;
  1105. position:Tai;subreg:Tsubregister;var result:Tregister);
  1106. var min,p,i:Tsuperregister;
  1107. r:Tregister;
  1108. adj:Pstring;
  1109. begin
  1110. if maxreg<last_reg then
  1111. begin
  1112. inc(maxreg);
  1113. p:=maxreg;
  1114. min:=0;
  1115. end
  1116. else
  1117. begin
  1118. min:=$ff;
  1119. p:=first_imaginary;
  1120. for i:=first_imaginary to maxreg do
  1121. if (i in unusedregs) and
  1122. (pos(char(i),abtlist)=0) and
  1123. (pos(char(i),spillednodes)=0) then
  1124. begin
  1125. adj:=igraph.adjlist[Tsuperregister(i)];
  1126. if adj=nil then
  1127. begin
  1128. p:=i;
  1129. min:=0;
  1130. break; {We won't find smaller ones.}
  1131. end
  1132. else
  1133. if length(adj^)<min then
  1134. begin
  1135. p:=i;
  1136. min:=length(adj^);
  1137. if min=0 then
  1138. break; {We won't find smaller ones.}
  1139. end;
  1140. end;
  1141. if min=$ff then
  1142. begin
  1143. {$ifdef ALLOWDUPREG}
  1144. result:=newreg(regtype,RS_INVALID,subreg);
  1145. exit;
  1146. {$else}
  1147. internalerror(10);
  1148. {$endif}
  1149. end;
  1150. end;
  1151. {$ifdef ra_debug}
  1152. writeln('Spilling temp: ',p,' min ',min);
  1153. {$endif ra_debug}
  1154. exclude(unusedregs,p);
  1155. include(used_in_proc,p);
  1156. r:=newreg(regtype,p,subreg);
  1157. if position=nil then
  1158. list.insert(Tai_regalloc.alloc(r))
  1159. else
  1160. list.insertafter(Tai_regalloc.alloc(r),position);
  1161. add_edges_used(p);
  1162. add_constraints(r);
  1163. result:=r;
  1164. end;
  1165. {In some cases we can get in big trouble. See this example:
  1166. ; register reg23d released
  1167. ; register eax allocated
  1168. ; register ebx allocated
  1169. ; register ecx allocated
  1170. ; register edx allocated
  1171. ; register esi allocated
  1172. ; register edi allocated
  1173. call [reg23d]
  1174. This code is ok, *except* when reg23d is spilled. In that case the
  1175. spilled would introduce a help register which can never get
  1176. allocated to a real register because it interferes with all of them.
  1177. To solve this we introduce the ABT ("avoid big trouble :)" ) registers.
  1178. If you allocate an ABT register you get a register that has less
  1179. than cpu_register interferences and will not be allocated ever again
  1180. by the normal register get procedures. In other words it is for sure it
  1181. will never get spilled.}
  1182. function trgobj.getabtregister(list:Taasmoutput;subreg:tsubregister):Tregister;
  1183. var p,i:Tsuperregister;
  1184. r:Tregister;
  1185. found:boolean;
  1186. min : byte;
  1187. adj:Pstring;
  1188. begin
  1189. min:=$ff;
  1190. for i:=1 to length(abtlist) do
  1191. if Tsuperregister(abtlist[i]) in unusedregs then
  1192. begin
  1193. p:=tsuperregister(abtlist[i]);
  1194. min:=0;
  1195. break;
  1196. end;
  1197. if min>0 then
  1198. begin
  1199. if maxreg<last_reg then
  1200. begin
  1201. inc(maxreg);
  1202. p:=maxreg;
  1203. min:=0;
  1204. end
  1205. else
  1206. begin
  1207. p:=first_imaginary;
  1208. for i:=first_imaginary to maxreg do
  1209. if (i in unusedregs) and
  1210. ((igraph.adjlist[i]=nil) or
  1211. (length(igraph.adjlist[i]^)<cpu_registers)) then
  1212. begin
  1213. adj:=igraph.adjlist[i];
  1214. if adj=nil then
  1215. begin
  1216. p:=i;
  1217. min:=0;
  1218. break; {We won't find smaller ones.}
  1219. end
  1220. else
  1221. if length(adj^)<min then
  1222. begin
  1223. p:=i;
  1224. min:=length(adj^);
  1225. if min=0 then
  1226. break; {We won't find smaller ones.}
  1227. end;
  1228. end;
  1229. end;
  1230. if min=$ff then
  1231. begin
  1232. {$ifdef ALLOWDUPREG}
  1233. result:=newreg(regtype,RS_INVALID,cgsize2subreg(size));
  1234. exit;
  1235. {$else}
  1236. internalerror(10);
  1237. {$endif}
  1238. end;
  1239. end;
  1240. exclude(unusedregs,p);
  1241. include(used_in_proc,p);
  1242. r:=newreg(regtype,p,subreg);
  1243. list.concat(Tai_regalloc.alloc(r));
  1244. result:=r;
  1245. add_edges_used(p);
  1246. add_constraints(r);
  1247. if pos(char(p),abtlist)=0 then
  1248. abtlist:=abtlist+char(p);
  1249. end;
  1250. procedure trgobj.ungetregisterinline(list:Taasmoutput;
  1251. position:Tai;r:Tregister);
  1252. var supreg:Tsuperregister;
  1253. begin
  1254. supreg:=getsupreg(r);
  1255. include(unusedregs,supreg);
  1256. if position=nil then
  1257. list.insert(Tai_regalloc.dealloc(r))
  1258. else
  1259. list.insertafter(Tai_regalloc.dealloc(r),position);
  1260. add_edges_used(supreg);
  1261. add_constraints(r);
  1262. end;
  1263. function trgobj.spill_registers(list:Taasmoutput;headertai:tai;const regs_to_spill:string):boolean;
  1264. {Returns true if any help registers have been used.}
  1265. var i:byte;
  1266. p,q:Tai;
  1267. regs_to_spill_set:Tsuperregisterset;
  1268. spill_temps:^Tspill_temp_list;
  1269. supreg : tsuperregister;
  1270. templist : taasmoutput;
  1271. begin
  1272. spill_registers:=false;
  1273. unusedregs:=[first_reg..last_reg];
  1274. fillchar(degree,sizeof(degree),0);
  1275. {Precoloured nodes should have an infinite degree, which we can approach
  1276. by 255.}
  1277. for i:=first_int_supreg to last_int_supreg do
  1278. degree[i]:=255;
  1279. { exclude(unusedregs,RS_STACK_POINTER_REG);}
  1280. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1281. {Make sure the register allocator won't allocate registers into ebp.}
  1282. exclude(unusedregs,RS_FRAME_POINTER_REG);
  1283. new(spill_temps);
  1284. fillchar(spill_temps^,sizeof(spill_temps^),0);
  1285. regs_to_spill_set:=[];
  1286. { Allocate temps and insert in front of the list }
  1287. templist:=taasmoutput.create;
  1288. for i:=1 to length(regs_to_spill) do
  1289. begin
  1290. {Alternative representation.}
  1291. include(regs_to_spill_set,Tsuperregister(regs_to_spill[i]));
  1292. {Clear all interferences of the spilled register.}
  1293. clear_interferences(Tsuperregister(regs_to_spill[i]));
  1294. {Get a temp for the spilled register}
  1295. tg.gettemp(templist,4,tt_noreuse,spill_temps^[Tsuperregister(regs_to_spill[i])]);
  1296. end;
  1297. list.insertlistafter(headertai,templist);
  1298. templist.free;
  1299. { Walk through all instructions, we can start with the headertai,
  1300. because before the header tai is only symbols }
  1301. p:=headertai;
  1302. while assigned(p) do
  1303. begin
  1304. case p.typ of
  1305. ait_regalloc:
  1306. begin
  1307. {A register allocation of a spilled register can be removed.}
  1308. supreg:=getsupreg(Tai_regalloc(p).reg);
  1309. if supreg in regs_to_spill_set then
  1310. begin
  1311. q:=p;
  1312. p:=Tai(p.next);
  1313. list.remove(q);
  1314. continue;
  1315. end
  1316. else
  1317. if Tai_regalloc(p).allocation then
  1318. exclude(unusedregs,supreg)
  1319. else
  1320. include(unusedregs,supreg);
  1321. end;
  1322. ait_instruction:
  1323. begin
  1324. aktfilepos:=Taicpu_abstract(p).fileinfo;
  1325. if Taicpu_abstract(p).spill_registers(list,@getregisterinline,
  1326. @ungetregisterinline,
  1327. regs_to_spill_set,
  1328. unusedregs,
  1329. spill_temps^) then
  1330. spill_registers:=true;
  1331. if Taicpu_abstract(p).is_move then
  1332. add_move_instruction(Taicpu(p));
  1333. end;
  1334. end;
  1335. p:=Tai(p.next);
  1336. end;
  1337. aktfilepos:=current_procinfo.exitpos;
  1338. for i:=1 to length(regs_to_spill) do
  1339. tg.ungettemp(list,spill_temps^[Tsuperregister(regs_to_spill[i])]);
  1340. dispose(spill_temps);
  1341. end;
  1342. end.
  1343. {
  1344. $Log$
  1345. Revision 1.84 2003-10-11 16:06:42 florian
  1346. * fixed some MMX<->SSE
  1347. * started to fix ppc, needs an overhaul
  1348. + stabs info improve for spilling, not sure if it works correctly/completly
  1349. - MMX_SUPPORT removed from Makefile.fpc
  1350. Revision 1.83 2003/10/10 17:48:14 peter
  1351. * old trgobj moved to x86/rgcpu and renamed to trgx86fpu
  1352. * tregisteralloctor renamed to trgobj
  1353. * removed rgobj from a lot of units
  1354. * moved location_* and reference_* to cgobj
  1355. * first things for mmx register allocation
  1356. Revision 1.82 2003/10/09 21:31:37 daniel
  1357. * Register allocator splitted, ans abstract now
  1358. Revision 1.81 2003/10/01 20:34:49 peter
  1359. * procinfo unit contains tprocinfo
  1360. * cginfo renamed to cgbase
  1361. * moved cgmessage to verbose
  1362. * fixed ppc and sparc compiles
  1363. Revision 1.80 2003/09/30 19:54:42 peter
  1364. * reuse registers with the least conflicts
  1365. Revision 1.79 2003/09/29 20:58:56 peter
  1366. * optimized releasing of registers
  1367. Revision 1.78 2003/09/28 13:41:12 peter
  1368. * return reg 255 when allowdupreg is defined
  1369. Revision 1.77 2003/09/25 16:19:32 peter
  1370. * fix filepositions
  1371. * insert spill temp allocations at the start of the proc
  1372. Revision 1.76 2003/09/16 16:17:01 peter
  1373. * varspez in calls to push_addr_param
  1374. Revision 1.75 2003/09/12 19:07:42 daniel
  1375. * Fixed fast spilling functionality by re-adding the code that initializes
  1376. precoloured nodes to degree 255. I would like to play hangman on the one
  1377. who removed that code.
  1378. Revision 1.74 2003/09/11 11:54:59 florian
  1379. * improved arm code generation
  1380. * move some protected and private field around
  1381. * the temp. register for register parameters/arguments are now released
  1382. before the move to the parameter register is done. This improves
  1383. the code in a lot of cases.
  1384. Revision 1.73 2003/09/09 20:59:27 daniel
  1385. * Adding register allocation order
  1386. Revision 1.72 2003/09/09 15:55:44 peter
  1387. * use register with least interferences in spillregister
  1388. Revision 1.71 2003/09/07 22:09:35 peter
  1389. * preparations for different default calling conventions
  1390. * various RA fixes
  1391. Revision 1.70 2003/09/03 21:06:45 peter
  1392. * fixes for FPU register allocation
  1393. Revision 1.69 2003/09/03 15:55:01 peter
  1394. * NEWRA branch merged
  1395. Revision 1.68 2003/09/03 11:18:37 florian
  1396. * fixed arm concatcopy
  1397. + arm support in the common compiler sources added
  1398. * moved some generic cg code around
  1399. + tfputype added
  1400. * ...
  1401. Revision 1.67.2.5 2003/08/31 20:44:07 peter
  1402. * fixed getexplicitregisterint tregister value
  1403. Revision 1.67.2.4 2003/08/31 20:40:50 daniel
  1404. * Fixed add_edges_used
  1405. Revision 1.67.2.3 2003/08/29 17:28:59 peter
  1406. * next batch of updates
  1407. Revision 1.67.2.2 2003/08/28 18:35:08 peter
  1408. * tregister changed to cardinal
  1409. Revision 1.67.2.1 2003/08/27 19:55:54 peter
  1410. * first tregister patch
  1411. Revision 1.67 2003/08/23 10:46:21 daniel
  1412. * Register allocator bugfix for h2pas
  1413. Revision 1.66 2003/08/17 16:59:20 jonas
  1414. * fixed regvars so they work with newra (at least for ppc)
  1415. * fixed some volatile register bugs
  1416. + -dnotranslation option for -dnewra, which causes the registers not to
  1417. be translated from virtual to normal registers. Requires support in
  1418. the assembler writer as well, which is only implemented in aggas/
  1419. agppcgas currently
  1420. Revision 1.65 2003/08/17 14:32:48 daniel
  1421. * Precoloured nodes now have an infinite degree approached with 255,
  1422. like they should.
  1423. Revision 1.64 2003/08/17 08:48:02 daniel
  1424. * Another register allocator bug fixed.
  1425. * cpu_registers set to 6 for i386
  1426. Revision 1.63 2003/08/09 18:56:54 daniel
  1427. * cs_regalloc renamed to cs_regvars to avoid confusion with register
  1428. allocator
  1429. * Some preventive changes to i386 spillinh code
  1430. Revision 1.62 2003/08/03 14:09:50 daniel
  1431. * Fixed a register allocator bug
  1432. * Figured out why -dnewra generates superfluous "mov reg1,reg2"
  1433. statements: changes in location_force. These moves are now no longer
  1434. constrained so they are optimized away.
  1435. Revision 1.61 2003/07/21 13:32:39 jonas
  1436. * add_edges_used() is now also called for registers allocated with
  1437. getexplicitregisterint()
  1438. * writing the intereference graph is now only done with -dradebug2 and
  1439. the created files are now called "igraph.<module_name>"
  1440. Revision 1.60 2003/07/06 15:31:21 daniel
  1441. * Fixed register allocator. *Lots* of fixes.
  1442. Revision 1.59 2003/07/06 15:00:47 jonas
  1443. * fixed my previous completely broken commit. It's not perfect though,
  1444. registers > last_int_supreg and < max_intreg may still be "translated"
  1445. Revision 1.58 2003/07/06 14:45:05 jonas
  1446. * support integer registers that are not managed by newra (ie. don't
  1447. translate register numbers that fall outside the range
  1448. first_int_supreg..last_int_supreg)
  1449. Revision 1.57 2003/07/02 22:18:04 peter
  1450. * paraloc splitted in callerparaloc,calleeparaloc
  1451. * sparc calling convention updates
  1452. Revision 1.56 2003/06/17 16:34:44 jonas
  1453. * lots of newra fixes (need getfuncretparaloc implementation for i386)!
  1454. * renamed all_intregisters to volatile_intregisters and made it
  1455. processor dependent
  1456. Revision 1.55 2003/06/14 14:53:50 jonas
  1457. * fixed newra cycle for x86
  1458. * added constants for indicating source and destination operands of the
  1459. "move reg,reg" instruction to aasmcpu (and use those in rgobj)
  1460. Revision 1.54 2003/06/13 21:19:31 peter
  1461. * current_procdef removed, use current_procinfo.procdef instead
  1462. Revision 1.53 2003/06/12 21:11:10 peter
  1463. * ungetregisterfpu gets size parameter
  1464. Revision 1.52 2003/06/12 16:43:07 peter
  1465. * newra compiles for sparc
  1466. Revision 1.51 2003/06/09 14:54:26 jonas
  1467. * (de)allocation of registers for parameters is now performed properly
  1468. (and checked on the ppc)
  1469. - removed obsolete allocation of all parameter registers at the start
  1470. of a procedure (and deallocation at the end)
  1471. Revision 1.50 2003/06/03 21:11:09 peter
  1472. * cg.a_load_* get a from and to size specifier
  1473. * makeregsize only accepts newregister
  1474. * i386 uses generic tcgnotnode,tcgunaryminus
  1475. Revision 1.49 2003/06/03 13:01:59 daniel
  1476. * Register allocator finished
  1477. Revision 1.48 2003/06/01 21:38:06 peter
  1478. * getregisterfpu size parameter added
  1479. * op_const_reg size parameter added
  1480. * sparc updates
  1481. Revision 1.47 2003/05/31 20:31:11 jonas
  1482. * set inital costs of assigning a variable to a register to 120 for
  1483. non-i386, because the used register must be store to memory at the
  1484. start and loaded again at the end
  1485. Revision 1.46 2003/05/30 18:55:21 jonas
  1486. * fixed several regvar related bugs for non-i386. make cycle with -Or now
  1487. works for ppc
  1488. Revision 1.45 2003/05/30 12:36:13 jonas
  1489. * use as little different registers on the ppc until newra is released,
  1490. since every used register must be saved
  1491. Revision 1.44 2003/05/17 13:30:08 jonas
  1492. * changed tt_persistant to tt_persistent :)
  1493. * tempcreatenode now doesn't accept a boolean anymore for persistent
  1494. temps, but a ttemptype, so you can also create ansistring temps etc
  1495. Revision 1.43 2003/05/16 14:33:31 peter
  1496. * regvar fixes
  1497. Revision 1.42 2003/04/26 20:03:49 daniel
  1498. * Bug fix in simplify
  1499. Revision 1.41 2003/04/25 20:59:35 peter
  1500. * removed funcretn,funcretsym, function result is now in varsym
  1501. and aliases for result and function name are added using absolutesym
  1502. * vs_hidden parameter for funcret passed in parameter
  1503. * vs_hidden fixes
  1504. * writenode changed to printnode and released from extdebug
  1505. * -vp option added to generate a tree.log with the nodetree
  1506. * nicer printnode for statements, callnode
  1507. Revision 1.40 2003/04/25 08:25:26 daniel
  1508. * Ifdefs around a lot of calls to cleartempgen
  1509. * Fixed registers that are allocated but not freed in several nodes
  1510. * Tweak to register allocator to cause less spills
  1511. * 8-bit registers now interfere with esi,edi and ebp
  1512. Compiler can now compile rtl successfully when using new register
  1513. allocator
  1514. Revision 1.39 2003/04/23 20:23:06 peter
  1515. * compile fix for no-newra
  1516. Revision 1.38 2003/04/23 14:42:07 daniel
  1517. * Further register allocator work. Compiler now smaller with new
  1518. allocator than without.
  1519. * Somebody forgot to adjust ppu version number
  1520. Revision 1.37 2003/04/22 23:50:23 peter
  1521. * firstpass uses expectloc
  1522. * checks if there are differences between the expectloc and
  1523. location.loc from secondpass in EXTDEBUG
  1524. Revision 1.36 2003/04/22 10:09:35 daniel
  1525. + Implemented the actual register allocator
  1526. + Scratch registers unavailable when new register allocator used
  1527. + maybe_save/maybe_restore unavailable when new register allocator used
  1528. Revision 1.35 2003/04/21 19:16:49 peter
  1529. * count address regs separate
  1530. Revision 1.34 2003/04/17 16:48:21 daniel
  1531. * Added some code to keep track of move instructions in register
  1532. allocator
  1533. Revision 1.33 2003/04/17 07:50:24 daniel
  1534. * Some work on interference graph construction
  1535. Revision 1.32 2003/03/28 19:16:57 peter
  1536. * generic constructor working for i386
  1537. * remove fixed self register
  1538. * esi added as address register for i386
  1539. Revision 1.31 2003/03/11 21:46:24 jonas
  1540. * lots of new regallocator fixes, both in generic and ppc-specific code
  1541. (ppc compiler still can't compile the linux system unit though)
  1542. Revision 1.30 2003/03/09 21:18:59 olle
  1543. + added cutils to the uses clause
  1544. Revision 1.29 2003/03/08 20:36:41 daniel
  1545. + Added newra version of Ti386shlshrnode
  1546. + Added interference graph construction code
  1547. Revision 1.28 2003/03/08 13:59:16 daniel
  1548. * Work to handle new register notation in ag386nsm
  1549. + Added newra version of Ti386moddivnode
  1550. Revision 1.27 2003/03/08 10:53:48 daniel
  1551. * Created newra version of secondmul in n386add.pas
  1552. Revision 1.26 2003/03/08 08:59:07 daniel
  1553. + $define newra will enable new register allocator
  1554. + getregisterint will return imaginary registers with $newra
  1555. + -sr switch added, will skip register allocation so you can see
  1556. the direct output of the code generator before register allocation
  1557. Revision 1.25 2003/02/26 20:50:45 daniel
  1558. * Fixed ungetreference
  1559. Revision 1.24 2003/02/19 22:39:56 daniel
  1560. * Fixed a few issues
  1561. Revision 1.23 2003/02/19 22:00:14 daniel
  1562. * Code generator converted to new register notation
  1563. - Horribily outdated todo.txt removed
  1564. Revision 1.22 2003/02/02 19:25:54 carl
  1565. * Several bugfixes for m68k target (register alloc., opcode emission)
  1566. + VIS target
  1567. + Generic add more complete (still not verified)
  1568. Revision 1.21 2003/01/08 18:43:57 daniel
  1569. * Tregister changed into a record
  1570. Revision 1.20 2002/10/05 12:43:28 carl
  1571. * fixes for Delphi 6 compilation
  1572. (warning : Some features do not work under Delphi)
  1573. Revision 1.19 2002/08/23 16:14:49 peter
  1574. * tempgen cleanup
  1575. * tt_noreuse temp type added that will be used in genentrycode
  1576. Revision 1.18 2002/08/17 22:09:47 florian
  1577. * result type handling in tcgcal.pass_2 overhauled
  1578. * better tnode.dowrite
  1579. * some ppc stuff fixed
  1580. Revision 1.17 2002/08/17 09:23:42 florian
  1581. * first part of procinfo rewrite
  1582. Revision 1.16 2002/08/06 20:55:23 florian
  1583. * first part of ppc calling conventions fix
  1584. Revision 1.15 2002/08/05 18:27:48 carl
  1585. + more more more documentation
  1586. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  1587. Revision 1.14 2002/08/04 19:06:41 carl
  1588. + added generic exception support (still does not work!)
  1589. + more documentation
  1590. Revision 1.13 2002/07/07 09:52:32 florian
  1591. * powerpc target fixed, very simple units can be compiled
  1592. * some basic stuff for better callparanode handling, far from being finished
  1593. Revision 1.12 2002/07/01 18:46:26 peter
  1594. * internal linker
  1595. * reorganized aasm layer
  1596. Revision 1.11 2002/05/18 13:34:17 peter
  1597. * readded missing revisions
  1598. Revision 1.10 2002/05/16 19:46:44 carl
  1599. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1600. + try to fix temp allocation (still in ifdef)
  1601. + generic constructor calls
  1602. + start of tassembler / tmodulebase class cleanup
  1603. Revision 1.8 2002/04/21 15:23:03 carl
  1604. + makeregsize
  1605. + changeregsize is now a local routine
  1606. Revision 1.7 2002/04/20 21:32:25 carl
  1607. + generic FPC_CHECKPOINTER
  1608. + first parameter offset in stack now portable
  1609. * rename some constants
  1610. + move some cpu stuff to other units
  1611. - remove unused constents
  1612. * fix stacksize for some targets
  1613. * fix generic size problems which depend now on EXTEND_SIZE constant
  1614. Revision 1.6 2002/04/15 19:03:31 carl
  1615. + reg2str -> std_reg2str()
  1616. Revision 1.5 2002/04/06 18:13:01 jonas
  1617. * several powerpc-related additions and fixes
  1618. Revision 1.4 2002/04/04 19:06:04 peter
  1619. * removed unused units
  1620. * use tlocation.size in cg.a_*loc*() routines
  1621. Revision 1.3 2002/04/02 17:11:29 peter
  1622. * tlocation,treference update
  1623. * LOC_CONSTANT added for better constant handling
  1624. * secondadd splitted in multiple routines
  1625. * location_force_reg added for loading a location to a register
  1626. of a specified size
  1627. * secondassignment parses now first the right and then the left node
  1628. (this is compatible with Kylix). This saves a lot of push/pop especially
  1629. with string operations
  1630. * adapted some routines to use the new cg methods
  1631. Revision 1.2 2002/04/01 19:24:25 jonas
  1632. * fixed different parameter name in interface and implementation
  1633. declaration of a method (only 1.0.x detected this)
  1634. Revision 1.1 2002/03/31 20:26:36 jonas
  1635. + a_loadfpu_* and a_loadmm_* methods in tcg
  1636. * register allocation is now handled by a class and is mostly processor
  1637. independent (+rgobj.pas and i386/rgcpu.pas)
  1638. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1639. * some small improvements and fixes to the optimizer
  1640. * some register allocation fixes
  1641. * some fpuvaroffset fixes in the unary minus node
  1642. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1643. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1644. also better optimizable)
  1645. * fixed and optimized register saving/restoring for new/dispose nodes
  1646. * LOC_FPU locations now also require their "register" field to be set to
  1647. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1648. - list field removed of the tnode class because it's not used currently
  1649. and can cause hard-to-find bugs
  1650. }