rgobj.pas 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. This unit implements the base class for the register allocator
  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. {$i fpcdefs.inc}
  18. { Allow duplicate allocations, can be used to get the .s file written }
  19. { $define ALLOWDUPREG}
  20. unit rgobj;
  21. interface
  22. uses
  23. cutils, cpubase,
  24. aasmbase,aasmtai,aasmcpu,
  25. cclasses,globtype,cgbase,cgutils,
  26. cpuinfo
  27. ;
  28. type
  29. {
  30. The interference bitmap contains of 2 layers:
  31. layer 1 - 256*256 blocks with pointers to layer 2 blocks
  32. layer 2 - blocks of 32*256 (32 bytes = 256 bits)
  33. }
  34. Tinterferencebitmap2 = array[byte] of set of byte;
  35. Pinterferencebitmap2 = ^Tinterferencebitmap2;
  36. Tinterferencebitmap1 = array[byte] of Pinterferencebitmap2;
  37. pinterferencebitmap1 = ^tinterferencebitmap1;
  38. Tinterferencebitmap=class
  39. private
  40. maxx1,
  41. maxy1 : byte;
  42. fbitmap : pinterferencebitmap1;
  43. function getbitmap(x,y:tsuperregister):boolean;
  44. procedure setbitmap(x,y:tsuperregister;b:boolean);
  45. public
  46. constructor create;
  47. destructor destroy;override;
  48. property bitmap[x,y:tsuperregister]:boolean read getbitmap write setbitmap;default;
  49. end;
  50. Tmovelistheader=record
  51. count,
  52. maxcount,
  53. sorted_until : cardinal;
  54. end;
  55. Tmovelist=record
  56. header : Tmovelistheader;
  57. data : array[tsuperregister] of Tlinkedlistitem;
  58. end;
  59. Pmovelist=^Tmovelist;
  60. {In the register allocator we keep track of move instructions.
  61. These instructions are moved between five linked lists. There
  62. is also a linked list per register to keep track about the moves
  63. it is associated with. Because we need to determine quickly in
  64. which of the five lists it is we add anu enumeradtion to each
  65. move instruction.}
  66. Tmoveset=(ms_coalesced_moves,ms_constrained_moves,ms_frozen_moves,
  67. ms_worklist_moves,ms_active_moves);
  68. Tmoveins=class(Tlinkedlistitem)
  69. moveset:Tmoveset;
  70. x,y:Tsuperregister;
  71. end;
  72. Treginfoflag=(ri_coalesced,ri_selected);
  73. Treginfoflagset=set of Treginfoflag;
  74. Treginfo=record
  75. live_start,
  76. live_end : Tai;
  77. subreg : tsubregister;
  78. alias : Tsuperregister;
  79. { The register allocator assigns each register a colour }
  80. colour : Tsuperregister;
  81. movelist : Pmovelist;
  82. adjlist : Psuperregisterworklist;
  83. degree : TSuperregister;
  84. flags : Treginfoflagset;
  85. end;
  86. Preginfo=^TReginfo;
  87. tspillreginfo = record
  88. spillreg : tregister;
  89. orgreg : tsuperregister;
  90. tempreg : tregister;
  91. regread,regwritten, mustbespilled: boolean;
  92. end;
  93. tspillregsinfo = array[0..2] of tspillreginfo;
  94. {#------------------------------------------------------------------
  95. This class implements the default register allocator. It is used by the
  96. code generator to allocate and free registers which might be valid
  97. across nodes. It also contains utility routines related to registers.
  98. Some of the methods in this class should be overriden
  99. by cpu-specific implementations.
  100. --------------------------------------------------------------------}
  101. trgobj=class
  102. preserved_by_proc : tcpuregisterset;
  103. used_in_proc : tcpuregisterset;
  104. constructor create(Aregtype:Tregistertype;
  105. Adefaultsub:Tsubregister;
  106. const Ausable:array of tsuperregister;
  107. Afirst_imaginary:Tsuperregister;
  108. Apreserved_by_proc:Tcpuregisterset);
  109. destructor destroy;override;
  110. {# Allocate a register. An internalerror will be generated if there is
  111. no more free registers which can be allocated.}
  112. function getregister(list:Taasmoutput;subreg:Tsubregister):Tregister;virtual;
  113. {# Get the register specified.}
  114. procedure getcpuregister(list:Taasmoutput;r:Tregister);virtual;
  115. procedure ungetcpuregister(list:Taasmoutput;r:Tregister);virtual;
  116. {# Get multiple registers specified.}
  117. procedure alloccpuregisters(list:Taasmoutput;r:Tcpuregisterset);virtual;
  118. {# Free multiple registers specified.}
  119. procedure dealloccpuregisters(list:Taasmoutput;r:Tcpuregisterset);virtual;
  120. function uses_registers:boolean;virtual;
  121. procedure add_reg_instruction(instr:Tai;r:tregister);
  122. procedure add_move_instruction(instr:Taicpu);
  123. {# Do the register allocation.}
  124. procedure do_register_allocation(list:Taasmoutput;headertai:tai);virtual;
  125. { Adds an interference edge.
  126. don't move this to the protected section, the arm cg requires to access this (FK) }
  127. procedure add_edge(u,v:Tsuperregister);
  128. protected
  129. regtype : Tregistertype;
  130. { default subregister used }
  131. defaultsub : tsubregister;
  132. live_registers:Tsuperregisterworklist;
  133. { can be overriden to add cpu specific interferences }
  134. procedure add_cpu_interferences(p : tai);virtual;
  135. procedure add_constraints(reg:Tregister);virtual;
  136. function getregisterinline(list:Taasmoutput;subreg:Tsubregister):Tregister;
  137. procedure ungetregisterinline(list:Taasmoutput;r:Tregister);
  138. function get_spill_subreg(r : tregister) : tsubregister;virtual;
  139. function do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;virtual;
  140. procedure do_spill_read(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);virtual;
  141. procedure do_spill_written(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);virtual;
  142. function instr_spill_register(list:Taasmoutput;
  143. instr:taicpu;
  144. const r:Tsuperregisterset;
  145. const spilltemplist:Tspill_temp_list): boolean;virtual;
  146. private
  147. {# First imaginary register.}
  148. first_imaginary : Tsuperregister;
  149. {# Highest register allocated until now.}
  150. reginfo : PReginfo;
  151. maxreginfo,
  152. maxreginfoinc,
  153. maxreg : Tsuperregister;
  154. usable_registers_cnt : word;
  155. usable_registers : array[0..maxcpuregister-1] of tsuperregister;
  156. ibitmap : Tinterferencebitmap;
  157. spillednodes,
  158. simplifyworklist,
  159. freezeworklist,
  160. spillworklist,
  161. coalescednodes,
  162. selectstack : tsuperregisterworklist;
  163. worklist_moves,
  164. active_moves,
  165. frozen_moves,
  166. coalesced_moves,
  167. constrained_moves : Tlinkedlist;
  168. {$ifdef EXTDEBUG}
  169. procedure writegraph(loopidx:longint);
  170. {$endif EXTDEBUG}
  171. {# Disposes of the reginfo array.}
  172. procedure dispose_reginfo;
  173. {# Prepare the register colouring.}
  174. procedure prepare_colouring;
  175. {# Clean up after register colouring.}
  176. procedure epilogue_colouring;
  177. {# Colour the registers; that is do the register allocation.}
  178. procedure colour_registers;
  179. procedure insert_regalloc_info(list:Taasmoutput;u:tsuperregister);
  180. procedure insert_regalloc_info_all(list:Taasmoutput);
  181. procedure generate_interference_graph(list:Taasmoutput;headertai:tai);
  182. procedure translate_registers(list:Taasmoutput);
  183. function spill_registers(list:Taasmoutput;headertai:tai):boolean;virtual;
  184. function getnewreg(subreg:tsubregister):tsuperregister;
  185. procedure add_edges_used(u:Tsuperregister);
  186. procedure add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  187. function move_related(n:Tsuperregister):boolean;
  188. procedure make_work_list;
  189. procedure sort_simplify_worklist;
  190. procedure enable_moves(n:Tsuperregister);
  191. procedure decrement_degree(m:Tsuperregister);
  192. procedure simplify;
  193. function get_alias(n:Tsuperregister):Tsuperregister;
  194. procedure add_worklist(u:Tsuperregister);
  195. function adjacent_ok(u,v:Tsuperregister):boolean;
  196. function conservative(u,v:Tsuperregister):boolean;
  197. procedure combine(u,v:Tsuperregister);
  198. procedure coalesce;
  199. procedure freeze_moves(u:Tsuperregister);
  200. procedure freeze;
  201. procedure select_spill;
  202. procedure assign_colours;
  203. procedure clear_interferences(u:Tsuperregister);
  204. end;
  205. const
  206. first_reg = 0;
  207. last_reg = high(tsuperregister)-1;
  208. maxspillingcounter = 20;
  209. implementation
  210. uses
  211. systems,
  212. globals,verbose,tgobj,procinfo;
  213. procedure sort_movelist(ml:Pmovelist);
  214. {Ok, sorting pointers is silly, but it does the job to make Trgobj.combine
  215. faster.}
  216. var h,i,p:word;
  217. t:Tlinkedlistitem;
  218. begin
  219. with ml^ do
  220. begin
  221. if header.count<2 then
  222. exit;
  223. p:=1;
  224. while 2*p<header.count do
  225. p:=2*p;
  226. while p<>0 do
  227. begin
  228. for h:=p to header.count-1 do
  229. begin
  230. i:=h;
  231. t:=data[i];
  232. repeat
  233. if ptrint(data[i-p])<=ptrint(t) then
  234. break;
  235. data[i]:=data[i-p];
  236. dec(i,p);
  237. until i<p;
  238. data[i]:=t;
  239. end;
  240. p:=p shr 1;
  241. end;
  242. header.sorted_until:=header.count-1;
  243. end;
  244. end;
  245. {******************************************************************************
  246. tinterferencebitmap
  247. ******************************************************************************}
  248. constructor tinterferencebitmap.create;
  249. begin
  250. inherited create;
  251. maxx1:=1;
  252. getmem(fbitmap,sizeof(tinterferencebitmap1)*2);
  253. fillchar(fbitmap^,sizeof(tinterferencebitmap1)*2,0);
  254. end;
  255. destructor tinterferencebitmap.destroy;
  256. var i,j:byte;
  257. begin
  258. for i:=0 to maxx1 do
  259. for j:=0 to maxy1 do
  260. if assigned(fbitmap[i,j]) then
  261. dispose(fbitmap[i,j]);
  262. freemem(fbitmap);
  263. end;
  264. function tinterferencebitmap.getbitmap(x,y:tsuperregister):boolean;
  265. var
  266. page : pinterferencebitmap2;
  267. begin
  268. result:=false;
  269. if (x shr 8>maxx1) then
  270. exit;
  271. page:=fbitmap[x shr 8,y shr 8];
  272. result:=assigned(page) and
  273. ((x and $ff) in page^[y and $ff]);
  274. end;
  275. procedure tinterferencebitmap.setbitmap(x,y:tsuperregister;b:boolean);
  276. var
  277. x1,y1 : byte;
  278. begin
  279. x1:=x shr 8;
  280. y1:=y shr 8;
  281. if x1>maxx1 then
  282. begin
  283. reallocmem(fbitmap,sizeof(tinterferencebitmap1)*(x1+1));
  284. fillchar(fbitmap[maxx1+1],sizeof(tinterferencebitmap1)*(x1-maxx1),0);
  285. maxx1:=x1;
  286. end;
  287. if not assigned(fbitmap[x1,y1]) then
  288. begin
  289. if y1>maxy1 then
  290. maxy1:=y1;
  291. new(fbitmap[x1,y1]);
  292. fillchar(fbitmap[x1,y1]^,sizeof(tinterferencebitmap2),0);
  293. end;
  294. if b then
  295. include(fbitmap[x1,y1]^[y and $ff],(x and $ff))
  296. else
  297. exclude(fbitmap[x1,y1]^[y and $ff],(x and $ff));
  298. end;
  299. {******************************************************************************
  300. trgobj
  301. ******************************************************************************}
  302. constructor trgobj.create(Aregtype:Tregistertype;
  303. Adefaultsub:Tsubregister;
  304. const Ausable:array of tsuperregister;
  305. Afirst_imaginary:Tsuperregister;
  306. Apreserved_by_proc:Tcpuregisterset);
  307. var
  308. i : Tsuperregister;
  309. begin
  310. { empty super register sets can cause very strange problems }
  311. if high(Ausable)=0 then
  312. internalerror(200210181);
  313. first_imaginary:=Afirst_imaginary;
  314. maxreg:=Afirst_imaginary;
  315. regtype:=Aregtype;
  316. defaultsub:=Adefaultsub;
  317. preserved_by_proc:=Apreserved_by_proc;
  318. used_in_proc:=[];
  319. live_registers.init;
  320. { Get reginfo for CPU registers }
  321. maxreginfo:=first_imaginary;
  322. maxreginfoinc:=16;
  323. worklist_moves:=Tlinkedlist.create;
  324. reginfo:=allocmem(first_imaginary*sizeof(treginfo));
  325. for i:=0 to first_imaginary-1 do
  326. begin
  327. reginfo[i].degree:=high(tsuperregister);
  328. reginfo[i].alias:=RS_INVALID;
  329. end;
  330. { Usable registers }
  331. fillchar(usable_registers,sizeof(usable_registers),0);
  332. for i:=low(Ausable) to high(Ausable) do
  333. usable_registers[i]:=Ausable[i];
  334. usable_registers_cnt:=high(Ausable)+1;
  335. { Initialize Worklists }
  336. spillednodes.init;
  337. simplifyworklist.init;
  338. freezeworklist.init;
  339. spillworklist.init;
  340. coalescednodes.init;
  341. selectstack.init;
  342. end;
  343. destructor trgobj.destroy;
  344. begin
  345. spillednodes.done;
  346. simplifyworklist.done;
  347. freezeworklist.done;
  348. spillworklist.done;
  349. coalescednodes.done;
  350. selectstack.done;
  351. live_registers.done;
  352. worklist_moves.free;
  353. dispose_reginfo;
  354. end;
  355. procedure Trgobj.dispose_reginfo;
  356. var i:Tsuperregister;
  357. begin
  358. if reginfo<>nil then
  359. begin
  360. for i:=0 to maxreg-1 do
  361. with reginfo[i] do
  362. begin
  363. if adjlist<>nil then
  364. dispose(adjlist,done);
  365. if movelist<>nil then
  366. dispose(movelist);
  367. end;
  368. freemem(reginfo);
  369. reginfo:=nil;
  370. end;
  371. end;
  372. function trgobj.getnewreg(subreg:tsubregister):tsuperregister;
  373. var
  374. oldmaxreginfo : tsuperregister;
  375. begin
  376. result:=maxreg;
  377. inc(maxreg);
  378. if maxreg>=last_reg then
  379. Message(parser_f_too_complex_proc);
  380. if maxreg>=maxreginfo then
  381. begin
  382. oldmaxreginfo:=maxreginfo;
  383. { Prevent overflow }
  384. if maxreginfoinc>last_reg-maxreginfo then
  385. maxreginfo:=last_reg
  386. else
  387. begin
  388. inc(maxreginfo,maxreginfoinc);
  389. if maxreginfoinc<256 then
  390. maxreginfoinc:=maxreginfoinc*2;
  391. end;
  392. reallocmem(reginfo,maxreginfo*sizeof(treginfo));
  393. { Do we really need it to clear it ? At least for 1.0.x (PFV) }
  394. fillchar(reginfo[oldmaxreginfo],(maxreginfo-oldmaxreginfo)*sizeof(treginfo),0);
  395. end;
  396. reginfo[result].subreg:=subreg;
  397. end;
  398. function trgobj.getregister(list:Taasmoutput;subreg:Tsubregister):Tregister;
  399. begin
  400. {$ifdef EXTDEBUG}
  401. if reginfo=nil then
  402. InternalError(2004020901);
  403. {$endif EXTDEBUG}
  404. if defaultsub=R_SUBNONE then
  405. result:=newreg(regtype,getnewreg(R_SUBNONE),R_SUBNONE)
  406. else
  407. result:=newreg(regtype,getnewreg(subreg),subreg);
  408. end;
  409. function trgobj.uses_registers:boolean;
  410. begin
  411. result:=(maxreg>first_imaginary);
  412. end;
  413. procedure trgobj.ungetcpuregister(list:Taasmoutput;r:Tregister);
  414. begin
  415. if (getsupreg(r)>=first_imaginary) then
  416. InternalError(2004020901);
  417. list.concat(Tai_regalloc.dealloc(r,nil));
  418. end;
  419. procedure trgobj.getcpuregister(list:Taasmoutput;r:Tregister);
  420. var
  421. supreg:Tsuperregister;
  422. begin
  423. supreg:=getsupreg(r);
  424. if supreg>=first_imaginary then
  425. internalerror(2003121503);
  426. include(used_in_proc,supreg);
  427. list.concat(Tai_regalloc.alloc(r,nil));
  428. end;
  429. procedure trgobj.alloccpuregisters(list:Taasmoutput;r:Tcpuregisterset);
  430. var i:Tsuperregister;
  431. begin
  432. for i:=0 to first_imaginary-1 do
  433. if i in r then
  434. getcpuregister(list,newreg(regtype,i,defaultsub));
  435. end;
  436. procedure trgobj.dealloccpuregisters(list:Taasmoutput;r:Tcpuregisterset);
  437. var i:Tsuperregister;
  438. begin
  439. for i:=0 to first_imaginary-1 do
  440. if i in r then
  441. ungetcpuregister(list,newreg(regtype,i,defaultsub));
  442. end;
  443. procedure trgobj.do_register_allocation(list:Taasmoutput;headertai:tai);
  444. var
  445. spillingcounter:byte;
  446. endspill:boolean;
  447. begin
  448. { Insert regalloc info for imaginary registers }
  449. insert_regalloc_info_all(list);
  450. ibitmap:=tinterferencebitmap.create;
  451. generate_interference_graph(list,headertai);
  452. { Don't do the real allocation when -sr is passed }
  453. if (cs_no_regalloc in aktglobalswitches) then
  454. exit;
  455. {Do register allocation.}
  456. spillingcounter:=0;
  457. repeat
  458. prepare_colouring;
  459. colour_registers;
  460. epilogue_colouring;
  461. endspill:=true;
  462. if spillednodes.length<>0 then
  463. begin
  464. inc(spillingcounter);
  465. if spillingcounter>maxspillingcounter then
  466. begin
  467. {$ifdef EXTDEBUG}
  468. { Only exit here so the .s file is still generated. Assembling
  469. the file will still trigger an error }
  470. exit;
  471. {$else}
  472. internalerror(200309041);
  473. {$endif}
  474. end;
  475. endspill:=not spill_registers(list,headertai);
  476. end;
  477. until endspill;
  478. ibitmap.free;
  479. translate_registers(list);
  480. dispose_reginfo;
  481. end;
  482. procedure trgobj.add_constraints(reg:Tregister);
  483. begin
  484. end;
  485. procedure trgobj.add_edge(u,v:Tsuperregister);
  486. {This procedure will add an edge to the virtual interference graph.}
  487. procedure addadj(u,v:Tsuperregister);
  488. begin
  489. with reginfo[u] do
  490. begin
  491. if adjlist=nil then
  492. new(adjlist,init);
  493. adjlist^.add(v);
  494. end;
  495. end;
  496. begin
  497. if (u<>v) and not(ibitmap[v,u]) then
  498. begin
  499. ibitmap[v,u]:=true;
  500. ibitmap[u,v]:=true;
  501. {Precoloured nodes are not stored in the interference graph.}
  502. if (u>=first_imaginary) then
  503. addadj(u,v);
  504. if (v>=first_imaginary) then
  505. addadj(v,u);
  506. end;
  507. end;
  508. procedure trgobj.add_edges_used(u:Tsuperregister);
  509. var i:word;
  510. begin
  511. with live_registers do
  512. if length>0 then
  513. for i:=0 to length-1 do
  514. add_edge(u,get_alias(buf^[i]));
  515. end;
  516. {$ifdef EXTDEBUG}
  517. procedure trgobj.writegraph(loopidx:longint);
  518. {This procedure writes out the current interference graph in the
  519. register allocator.}
  520. var f:text;
  521. i,j:Tsuperregister;
  522. begin
  523. assign(f,'igraph'+tostr(loopidx));
  524. rewrite(f);
  525. writeln(f,'Interference graph');
  526. writeln(f);
  527. write(f,' ');
  528. for i:=0 to 15 do
  529. for j:=0 to 15 do
  530. write(f,hexstr(i,1));
  531. writeln(f);
  532. write(f,' ');
  533. for i:=0 to 15 do
  534. write(f,'0123456789ABCDEF');
  535. writeln(f);
  536. for i:=0 to maxreg-1 do
  537. begin
  538. write(f,hexstr(i,2):4);
  539. for j:=0 to maxreg-1 do
  540. if ibitmap[i,j] then
  541. write(f,'*')
  542. else
  543. write(f,'-');
  544. writeln(f);
  545. end;
  546. close(f);
  547. end;
  548. {$endif EXTDEBUG}
  549. procedure trgobj.add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  550. begin
  551. with reginfo[u] do
  552. begin
  553. if movelist=nil then
  554. begin
  555. getmem(movelist,sizeof(tmovelistheader)+60*sizeof(pointer));
  556. movelist^.header.maxcount:=60;
  557. movelist^.header.count:=0;
  558. movelist^.header.sorted_until:=0;
  559. end
  560. else
  561. begin
  562. if movelist^.header.count>=movelist^.header.maxcount then
  563. begin
  564. movelist^.header.maxcount:=movelist^.header.maxcount*2;
  565. reallocmem(movelist,sizeof(tmovelistheader)+movelist^.header.maxcount*sizeof(pointer));
  566. end;
  567. end;
  568. movelist^.data[movelist^.header.count]:=data;
  569. inc(movelist^.header.count);
  570. end;
  571. end;
  572. procedure trgobj.add_reg_instruction(instr:Tai;r:tregister);
  573. var
  574. supreg : tsuperregister;
  575. begin
  576. supreg:=getsupreg(r);
  577. {$ifdef extdebug}
  578. if supreg>=maxreginfo then
  579. internalerror(200411061);
  580. {$endif extdebug}
  581. if supreg>=first_imaginary then
  582. with reginfo[supreg] do
  583. begin
  584. if not assigned(live_start) then
  585. live_start:=instr;
  586. live_end:=instr;
  587. end;
  588. end;
  589. procedure trgobj.add_move_instruction(instr:Taicpu);
  590. {This procedure notifies a certain as a move instruction so the
  591. register allocator can try to eliminate it.}
  592. var i:Tmoveins;
  593. ssupreg,dsupreg:Tsuperregister;
  594. begin
  595. {$ifdef extdebug}
  596. if (instr.oper[O_MOV_SOURCE]^.typ<>top_reg) or
  597. (instr.oper[O_MOV_DEST]^.typ<>top_reg) then
  598. internalerror(200311291);
  599. {$endif}
  600. i:=Tmoveins.create;
  601. i.moveset:=ms_worklist_moves;
  602. worklist_moves.insert(i);
  603. ssupreg:=getsupreg(instr.oper[O_MOV_SOURCE]^.reg);
  604. add_to_movelist(ssupreg,i);
  605. dsupreg:=getsupreg(instr.oper[O_MOV_DEST]^.reg);
  606. if ssupreg<>dsupreg then
  607. {Avoid adding the same move instruction twice to a single register.}
  608. add_to_movelist(dsupreg,i);
  609. i.x:=ssupreg;
  610. i.y:=dsupreg;
  611. end;
  612. function trgobj.move_related(n:Tsuperregister):boolean;
  613. var i:cardinal;
  614. begin
  615. move_related:=false;
  616. with reginfo[n] do
  617. if movelist<>nil then
  618. with movelist^ do
  619. for i:=0 to header.count-1 do
  620. if Tmoveins(data[i]).moveset in [ms_worklist_moves,ms_active_moves] then
  621. begin
  622. move_related:=true;
  623. break;
  624. end;
  625. end;
  626. procedure Trgobj.sort_simplify_worklist;
  627. {Sorts the simplifyworklist by the number of interferences the
  628. registers in it cause. This allows simplify to execute in
  629. constant time.}
  630. var p,h,i,leni,lent:word;
  631. t:Tsuperregister;
  632. adji,adjt:Psuperregisterworklist;
  633. begin
  634. with simplifyworklist do
  635. begin
  636. if length<2 then
  637. exit;
  638. p:=1;
  639. while 2*p<length do
  640. p:=2*p;
  641. while p<>0 do
  642. begin
  643. for h:=p to length-1 do
  644. begin
  645. i:=h;
  646. t:=buf^[i];
  647. adjt:=reginfo[buf^[i]].adjlist;
  648. lent:=0;
  649. if adjt<>nil then
  650. lent:=adjt^.length;
  651. repeat
  652. adji:=reginfo[buf^[i-p]].adjlist;
  653. leni:=0;
  654. if adji<>nil then
  655. leni:=adji^.length;
  656. if leni<=lent then
  657. break;
  658. buf^[i]:=buf^[i-p];
  659. dec(i,p)
  660. until i<p;
  661. buf^[i]:=t;
  662. end;
  663. p:=p shr 1;
  664. end;
  665. end;
  666. end;
  667. procedure trgobj.make_work_list;
  668. var n:Tsuperregister;
  669. begin
  670. {If we have 7 cpu registers, and the degree of a node is 7, we cannot
  671. assign it to any of the registers, thus it is significant.}
  672. for n:=first_imaginary to maxreg-1 do
  673. with reginfo[n] do
  674. begin
  675. if adjlist=nil then
  676. degree:=0
  677. else
  678. degree:=adjlist^.length;
  679. if degree>=usable_registers_cnt then
  680. spillworklist.add(n)
  681. else if move_related(n) then
  682. freezeworklist.add(n)
  683. else
  684. simplifyworklist.add(n);
  685. end;
  686. sort_simplify_worklist;
  687. end;
  688. procedure trgobj.prepare_colouring;
  689. begin
  690. make_work_list;
  691. active_moves:=Tlinkedlist.create;
  692. frozen_moves:=Tlinkedlist.create;
  693. coalesced_moves:=Tlinkedlist.create;
  694. constrained_moves:=Tlinkedlist.create;
  695. selectstack.clear;
  696. end;
  697. procedure trgobj.enable_moves(n:Tsuperregister);
  698. var m:Tlinkedlistitem;
  699. i:cardinal;
  700. begin
  701. with reginfo[n] do
  702. if movelist<>nil then
  703. for i:=0 to movelist^.header.count-1 do
  704. begin
  705. m:=movelist^.data[i];
  706. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  707. if Tmoveins(m).moveset=ms_active_moves then
  708. begin
  709. {Move m from the set active_moves to the set worklist_moves.}
  710. active_moves.remove(m);
  711. Tmoveins(m).moveset:=ms_worklist_moves;
  712. worklist_moves.concat(m);
  713. end;
  714. end;
  715. end;
  716. procedure Trgobj.decrement_degree(m:Tsuperregister);
  717. var adj : Psuperregisterworklist;
  718. n : tsuperregister;
  719. d,i : word;
  720. begin
  721. with reginfo[m] do
  722. begin
  723. d:=degree;
  724. if d=0 then
  725. internalerror(200312151);
  726. dec(degree);
  727. if d=usable_registers_cnt then
  728. begin
  729. {Enable moves for m.}
  730. enable_moves(m);
  731. {Enable moves for adjacent.}
  732. adj:=adjlist;
  733. if adj<>nil then
  734. for i:=1 to adj^.length do
  735. begin
  736. n:=adj^.buf^[i-1];
  737. if reginfo[n].flags*[ri_selected,ri_coalesced]<>[] then
  738. enable_moves(n);
  739. end;
  740. {Remove the node from the spillworklist.}
  741. if not spillworklist.delete(m) then
  742. internalerror(200310145);
  743. if move_related(m) then
  744. freezeworklist.add(m)
  745. else
  746. simplifyworklist.add(m);
  747. end;
  748. end;
  749. end;
  750. procedure trgobj.simplify;
  751. var adj : Psuperregisterworklist;
  752. m,n : Tsuperregister;
  753. i : word;
  754. begin
  755. {We take the element with the least interferences out of the
  756. simplifyworklist. Since the simplifyworklist is now sorted, we
  757. no longer need to search, but we can simply take the first element.}
  758. m:=simplifyworklist.get;
  759. {Push it on the selectstack.}
  760. selectstack.add(m);
  761. with reginfo[m] do
  762. begin
  763. include(flags,ri_selected);
  764. adj:=adjlist;
  765. end;
  766. if adj<>nil then
  767. for i:=1 to adj^.length do
  768. begin
  769. n:=adj^.buf^[i-1];
  770. if (n>=first_imaginary) and
  771. (reginfo[n].flags*[ri_selected,ri_coalesced]=[]) then
  772. decrement_degree(n);
  773. end;
  774. end;
  775. function trgobj.get_alias(n:Tsuperregister):Tsuperregister;
  776. begin
  777. while ri_coalesced in reginfo[n].flags do
  778. n:=reginfo[n].alias;
  779. get_alias:=n;
  780. end;
  781. procedure trgobj.add_worklist(u:Tsuperregister);
  782. begin
  783. if (u>=first_imaginary) and
  784. (not move_related(u)) and
  785. (reginfo[u].degree<usable_registers_cnt) then
  786. begin
  787. if not freezeworklist.delete(u) then
  788. internalerror(200308161); {must be found}
  789. simplifyworklist.add(u);
  790. end;
  791. end;
  792. function trgobj.adjacent_ok(u,v:Tsuperregister):boolean;
  793. {Check wether u and v should be coalesced. u is precoloured.}
  794. function ok(t,r:Tsuperregister):boolean;
  795. begin
  796. ok:=(t<first_imaginary) or
  797. (reginfo[t].degree<usable_registers_cnt) or
  798. ibitmap[r,t];
  799. end;
  800. var adj : Psuperregisterworklist;
  801. i : word;
  802. n : tsuperregister;
  803. begin
  804. with reginfo[v] do
  805. begin
  806. adjacent_ok:=true;
  807. adj:=adjlist;
  808. if adj<>nil then
  809. for i:=1 to adj^.length do
  810. begin
  811. n:=adj^.buf^[i-1];
  812. if (flags*[ri_coalesced,ri_selected]=[]) and not ok(n,u) then
  813. begin
  814. adjacent_ok:=false;
  815. break;
  816. end;
  817. end;
  818. end;
  819. end;
  820. function trgobj.conservative(u,v:Tsuperregister):boolean;
  821. var adj : Psuperregisterworklist;
  822. done : Tsuperregisterset; {To prevent that we count nodes twice.}
  823. i,k:word;
  824. n : tsuperregister;
  825. begin
  826. k:=0;
  827. supregset_reset(done,false,maxreg);
  828. with reginfo[u] do
  829. begin
  830. adj:=adjlist;
  831. if adj<>nil then
  832. for i:=1 to adj^.length do
  833. begin
  834. n:=adj^.buf^[i-1];
  835. if flags*[ri_coalesced,ri_selected]=[] then
  836. begin
  837. supregset_include(done,n);
  838. if reginfo[n].degree>=usable_registers_cnt then
  839. inc(k);
  840. end;
  841. end;
  842. end;
  843. adj:=reginfo[v].adjlist;
  844. if adj<>nil then
  845. for i:=1 to adj^.length do
  846. begin
  847. n:=adj^.buf^[i-1];
  848. if not supregset_in(done,n) and
  849. (reginfo[n].degree>=usable_registers_cnt) and
  850. (reginfo[u].flags*[ri_coalesced,ri_selected]=[]) then
  851. inc(k);
  852. end;
  853. conservative:=(k<usable_registers_cnt);
  854. end;
  855. procedure trgobj.combine(u,v:Tsuperregister);
  856. var adj : Psuperregisterworklist;
  857. i,n,p,q:cardinal;
  858. t : tsuperregister;
  859. searched:Tlinkedlistitem;
  860. label l1;
  861. begin
  862. if not freezeworklist.delete(v) then
  863. spillworklist.delete(v);
  864. coalescednodes.add(v);
  865. include(reginfo[v].flags,ri_coalesced);
  866. reginfo[v].alias:=u;
  867. {Combine both movelists. Since the movelists are sets, only add
  868. elements that are not already present. The movelists cannot be
  869. empty by definition; nodes are only coalesced if there is a move
  870. between them. To prevent quadratic time blowup (movelists of
  871. especially machine registers can get very large because of moves
  872. generated during calls) we need to go into disgusting complexity.
  873. (See webtbs/tw2242 for an example that stresses this.)
  874. We want to sort the movelist to be able to search logarithmically.
  875. Unfortunately, sorting the movelist every time before searching
  876. is counter-productive, since the movelist usually grows with a few
  877. items at a time. Therefore, we split the movelist into a sorted
  878. and an unsorted part and search through both. If the unsorted part
  879. becomes too large, we sort.}
  880. if assigned(reginfo[u].movelist) then
  881. begin
  882. {We have to weigh the cost of sorting the list against searching
  883. the cost of the unsorted part. I use factor of 8 here; if the
  884. number of items is less than 8 times the numer of unsorted items,
  885. we'll sort the list.}
  886. with reginfo[u].movelist^ do
  887. if header.count<8*(header.count-header.sorted_until) then
  888. sort_movelist(reginfo[u].movelist);
  889. if assigned(reginfo[v].movelist) then
  890. begin
  891. for n:=0 to reginfo[v].movelist^.header.count-1 do
  892. begin
  893. {Binary search the sorted part of the list.}
  894. searched:=reginfo[v].movelist^.data[n];
  895. p:=0;
  896. q:=reginfo[u].movelist^.header.sorted_until;
  897. i:=0;
  898. if q<>0 then
  899. repeat
  900. i:=(p+q) shr 1;
  901. if ptrint(searched)>ptrint(reginfo[u].movelist^.data[i]) then
  902. p:=i+1
  903. else
  904. q:=i;
  905. until p=q;
  906. with reginfo[u].movelist^ do
  907. if searched<>data[i] then
  908. begin
  909. {Linear search the unsorted part of the list.}
  910. for i:=header.sorted_until+1 to header.count-1 do
  911. if searched=data[i] then
  912. goto l1;
  913. {Not found -> add}
  914. add_to_movelist(u,searched);
  915. l1:
  916. end;
  917. end;
  918. end;
  919. end;
  920. enable_moves(v);
  921. adj:=reginfo[v].adjlist;
  922. if adj<>nil then
  923. for i:=1 to adj^.length do
  924. begin
  925. t:=adj^.buf^[i-1];
  926. with reginfo[t] do
  927. if not(ri_coalesced in flags) then
  928. begin
  929. {t has a connection to v. Since we are adding v to u, we
  930. need to connect t to u. However, beware if t was already
  931. connected to u...}
  932. if (ibitmap[t,u]) and not (ri_selected in flags) then
  933. {... because in that case, we are actually removing an edge
  934. and the degree of t decreases.}
  935. decrement_degree(t)
  936. else
  937. begin
  938. add_edge(t,u);
  939. {We have added an edge to t and u. So their degree increases.
  940. However, v is added to u. That means its neighbours will
  941. no longer point to v, but to u instead. Therefore, only the
  942. degree of u increases.}
  943. if (u>=first_imaginary) and not (ri_selected in flags) then
  944. inc(reginfo[u].degree);
  945. end;
  946. end;
  947. end;
  948. if (reginfo[u].degree>=usable_registers_cnt) and freezeworklist.delete(u) then
  949. spillworklist.add(u);
  950. end;
  951. procedure trgobj.coalesce;
  952. var m:Tmoveins;
  953. x,y,u,v:Tsuperregister;
  954. begin
  955. m:=Tmoveins(worklist_moves.getfirst);
  956. x:=get_alias(m.x);
  957. y:=get_alias(m.y);
  958. if (y<first_imaginary) then
  959. begin
  960. u:=y;
  961. v:=x;
  962. end
  963. else
  964. begin
  965. u:=x;
  966. v:=y;
  967. end;
  968. if (u=v) then
  969. begin
  970. m.moveset:=ms_coalesced_moves; {Already coalesced.}
  971. coalesced_moves.insert(m);
  972. add_worklist(u);
  973. end
  974. {Do u and v interfere? In that case the move is constrained. Two
  975. precoloured nodes interfere allways. If v is precoloured, by the above
  976. code u is precoloured, thus interference...}
  977. else if (v<first_imaginary) or ibitmap[u,v] then
  978. begin
  979. m.moveset:=ms_constrained_moves; {Cannot coalesce yet...}
  980. constrained_moves.insert(m);
  981. add_worklist(u);
  982. add_worklist(v);
  983. end
  984. {Next test: is it possible and a good idea to coalesce??}
  985. else if ((u<first_imaginary) and adjacent_ok(u,v)) or
  986. ((u>=first_imaginary) and conservative(u,v)) then
  987. begin
  988. m.moveset:=ms_coalesced_moves; {Move coalesced!}
  989. coalesced_moves.insert(m);
  990. combine(u,v);
  991. add_worklist(u);
  992. end
  993. else
  994. begin
  995. m.moveset:=ms_active_moves;
  996. active_moves.insert(m);
  997. end;
  998. end;
  999. procedure trgobj.freeze_moves(u:Tsuperregister);
  1000. var i:cardinal;
  1001. m:Tlinkedlistitem;
  1002. v,x,y:Tsuperregister;
  1003. begin
  1004. if reginfo[u].movelist<>nil then
  1005. for i:=0 to reginfo[u].movelist^.header.count-1 do
  1006. begin
  1007. m:=reginfo[u].movelist^.data[i];
  1008. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  1009. begin
  1010. x:=Tmoveins(m).x;
  1011. y:=Tmoveins(m).y;
  1012. if get_alias(y)=get_alias(u) then
  1013. v:=get_alias(x)
  1014. else
  1015. v:=get_alias(y);
  1016. {Move m from active_moves/worklist_moves to frozen_moves.}
  1017. if Tmoveins(m).moveset=ms_active_moves then
  1018. active_moves.remove(m)
  1019. else
  1020. worklist_moves.remove(m);
  1021. Tmoveins(m).moveset:=ms_frozen_moves;
  1022. frozen_moves.insert(m);
  1023. if (v>=first_imaginary) and not(move_related(v)) and
  1024. (reginfo[v].degree<usable_registers_cnt) then
  1025. begin
  1026. freezeworklist.delete(v);
  1027. simplifyworklist.add(v);
  1028. end;
  1029. end;
  1030. end;
  1031. end;
  1032. procedure trgobj.freeze;
  1033. var n:Tsuperregister;
  1034. begin
  1035. { We need to take a random element out of the freezeworklist. We take
  1036. the last element. Dirty code! }
  1037. n:=freezeworklist.get;
  1038. {Add it to the simplifyworklist.}
  1039. simplifyworklist.add(n);
  1040. freeze_moves(n);
  1041. end;
  1042. procedure trgobj.select_spill;
  1043. var
  1044. n : tsuperregister;
  1045. adj : psuperregisterworklist;
  1046. max,p,i:word;
  1047. begin
  1048. { We must look for the element with the most interferences in the
  1049. spillworklist. This is required because those registers are creating
  1050. the most conflicts and keeping them in a register will not reduce the
  1051. complexity and even can cause the help registers for the spilling code
  1052. to get too much conflicts with the result that the spilling code
  1053. will never converge (PFV) }
  1054. max:=0;
  1055. p:=0;
  1056. with spillworklist do
  1057. begin
  1058. {Safe: This procedure is only called if length<>0}
  1059. for i:=0 to length-1 do
  1060. begin
  1061. adj:=reginfo[buf^[i]].adjlist;
  1062. if assigned(adj) and (adj^.length>max) then
  1063. begin
  1064. p:=i;
  1065. max:=adj^.length;
  1066. end;
  1067. end;
  1068. n:=buf^[p];
  1069. deleteidx(p);
  1070. end;
  1071. simplifyworklist.add(n);
  1072. freeze_moves(n);
  1073. end;
  1074. procedure trgobj.assign_colours;
  1075. {Assign_colours assigns the actual colours to the registers.}
  1076. var adj : Psuperregisterworklist;
  1077. i,j,k : word;
  1078. n,a,c : Tsuperregister;
  1079. colourednodes : Tsuperregisterset;
  1080. adj_colours:set of 0..255;
  1081. found : boolean;
  1082. begin
  1083. spillednodes.clear;
  1084. {Reset colours}
  1085. for n:=0 to maxreg-1 do
  1086. reginfo[n].colour:=n;
  1087. {Colour the cpu registers...}
  1088. supregset_reset(colourednodes,false,maxreg);
  1089. for n:=0 to first_imaginary-1 do
  1090. supregset_include(colourednodes,n);
  1091. {Now colour the imaginary registers on the select-stack.}
  1092. for i:=selectstack.length downto 1 do
  1093. begin
  1094. n:=selectstack.buf^[i-1];
  1095. {Create a list of colours that we cannot assign to n.}
  1096. adj_colours:=[];
  1097. adj:=reginfo[n].adjlist;
  1098. if adj<>nil then
  1099. for j:=0 to adj^.length-1 do
  1100. begin
  1101. a:=get_alias(adj^.buf^[j]);
  1102. if supregset_in(colourednodes,a) and (reginfo[a].colour<=255) then
  1103. include(adj_colours,reginfo[a].colour);
  1104. end;
  1105. if regtype=R_INTREGISTER then
  1106. include(adj_colours,RS_STACK_POINTER_REG);
  1107. {Assume a spill by default...}
  1108. found:=false;
  1109. {Search for a colour not in this list.}
  1110. for k:=0 to usable_registers_cnt-1 do
  1111. begin
  1112. c:=usable_registers[k];
  1113. if not(c in adj_colours) then
  1114. begin
  1115. reginfo[n].colour:=c;
  1116. found:=true;
  1117. supregset_include(colourednodes,n);
  1118. include(used_in_proc,c);
  1119. break;
  1120. end;
  1121. end;
  1122. if not found then
  1123. spillednodes.add(n);
  1124. end;
  1125. {Finally colour the nodes that were coalesced.}
  1126. for i:=1 to coalescednodes.length do
  1127. begin
  1128. n:=coalescednodes.buf^[i-1];
  1129. k:=get_alias(n);
  1130. reginfo[n].colour:=reginfo[k].colour;
  1131. if reginfo[k].colour<maxcpuregister then
  1132. include(used_in_proc,reginfo[k].colour);
  1133. end;
  1134. end;
  1135. procedure trgobj.colour_registers;
  1136. begin
  1137. repeat
  1138. if simplifyworklist.length<>0 then
  1139. simplify
  1140. else if not(worklist_moves.empty) then
  1141. coalesce
  1142. else if freezeworklist.length<>0 then
  1143. freeze
  1144. else if spillworklist.length<>0 then
  1145. select_spill;
  1146. until (simplifyworklist.length=0) and
  1147. worklist_moves.empty and
  1148. (freezeworklist.length=0) and
  1149. (spillworklist.length=0);
  1150. assign_colours;
  1151. end;
  1152. procedure trgobj.epilogue_colouring;
  1153. var
  1154. i : Tsuperregister;
  1155. begin
  1156. worklist_moves.clear;
  1157. active_moves.destroy;
  1158. active_moves:=nil;
  1159. frozen_moves.destroy;
  1160. frozen_moves:=nil;
  1161. coalesced_moves.destroy;
  1162. coalesced_moves:=nil;
  1163. constrained_moves.destroy;
  1164. constrained_moves:=nil;
  1165. for i:=0 to maxreg-1 do
  1166. with reginfo[i] do
  1167. if movelist<>nil then
  1168. begin
  1169. dispose(movelist);
  1170. movelist:=nil;
  1171. end;
  1172. end;
  1173. procedure trgobj.clear_interferences(u:Tsuperregister);
  1174. {Remove node u from the interference graph and remove all collected
  1175. move instructions it is associated with.}
  1176. var i : word;
  1177. v : Tsuperregister;
  1178. adj,adj2 : Psuperregisterworklist;
  1179. begin
  1180. adj:=reginfo[u].adjlist;
  1181. if adj<>nil then
  1182. begin
  1183. for i:=1 to adj^.length do
  1184. begin
  1185. v:=adj^.buf^[i-1];
  1186. {Remove (u,v) and (v,u) from bitmap.}
  1187. ibitmap[u,v]:=false;
  1188. ibitmap[v,u]:=false;
  1189. {Remove (v,u) from adjacency list.}
  1190. adj2:=reginfo[v].adjlist;
  1191. if adj2<>nil then
  1192. begin
  1193. adj2^.delete(u);
  1194. if adj2^.length=0 then
  1195. begin
  1196. dispose(adj2,done);
  1197. reginfo[v].adjlist:=nil;
  1198. end;
  1199. end;
  1200. end;
  1201. {Remove ( u,* ) from adjacency list.}
  1202. dispose(adj,done);
  1203. reginfo[u].adjlist:=nil;
  1204. end;
  1205. end;
  1206. function trgobj.getregisterinline(list:Taasmoutput;subreg:Tsubregister):Tregister;
  1207. var
  1208. p : Tsuperregister;
  1209. begin
  1210. p:=getnewreg(subreg);
  1211. live_registers.add(p);
  1212. result:=newreg(regtype,p,subreg);
  1213. add_edges_used(p);
  1214. add_constraints(result);
  1215. end;
  1216. procedure trgobj.ungetregisterinline(list:Taasmoutput;r:Tregister);
  1217. var
  1218. supreg:Tsuperregister;
  1219. begin
  1220. supreg:=getsupreg(r);
  1221. live_registers.delete(supreg);
  1222. insert_regalloc_info(list,supreg);
  1223. end;
  1224. procedure trgobj.insert_regalloc_info(list:Taasmoutput;u:tsuperregister);
  1225. var
  1226. p : tai;
  1227. r : tregister;
  1228. palloc,
  1229. pdealloc : tai_regalloc;
  1230. begin
  1231. { Insert regallocs for all imaginary registers }
  1232. with reginfo[u] do
  1233. begin
  1234. r:=newreg(regtype,u,subreg);
  1235. if assigned(live_start) then
  1236. begin
  1237. { Generate regalloc and bind it to an instruction, this
  1238. is needed to find all live registers belonging to an
  1239. instruction during the spilling }
  1240. if live_start.typ=ait_instruction then
  1241. palloc:=tai_regalloc.alloc(r,live_start)
  1242. else
  1243. palloc:=tai_regalloc.alloc(r,nil);
  1244. if live_end.typ=ait_instruction then
  1245. pdealloc:=tai_regalloc.dealloc(r,live_end)
  1246. else
  1247. pdealloc:=tai_regalloc.dealloc(r,nil);
  1248. { Insert live start allocation before the instruction/reg_a_sync }
  1249. list.insertbefore(palloc,live_start);
  1250. { Insert live end deallocation before reg allocations
  1251. to reduce conflicts }
  1252. p:=live_end;
  1253. while assigned(p) and
  1254. assigned(p.previous) and
  1255. (tai(p.previous).typ=ait_regalloc) and
  1256. (tai_regalloc(p.previous).ratype=ra_alloc) and
  1257. (tai_regalloc(p.previous).reg<>r) do
  1258. p:=tai(p.previous);
  1259. { , but add release after a reg_a_sync }
  1260. if assigned(p) and
  1261. (p.typ=ait_regalloc) and
  1262. (tai_regalloc(p).ratype=ra_sync) then
  1263. p:=tai(p.next);
  1264. if assigned(p) then
  1265. list.insertbefore(pdealloc,p)
  1266. else
  1267. list.concat(pdealloc);
  1268. end
  1269. {$ifdef EXTDEBUG}
  1270. else
  1271. Comment(V_Warning,'Register '+std_regname(r)+' not used');
  1272. {$endif EXTDEBUG}
  1273. end;
  1274. end;
  1275. procedure trgobj.insert_regalloc_info_all(list:Taasmoutput);
  1276. var
  1277. supreg : tsuperregister;
  1278. begin
  1279. { Insert regallocs for all imaginary registers }
  1280. for supreg:=first_imaginary to maxreg-1 do
  1281. insert_regalloc_info(list,supreg);
  1282. end;
  1283. procedure trgobj.add_cpu_interferences(p : tai);
  1284. begin
  1285. end;
  1286. procedure trgobj.generate_interference_graph(list:Taasmoutput;headertai:tai);
  1287. var
  1288. p : tai;
  1289. {$ifdef EXTDEBUG}
  1290. i : integer;
  1291. {$endif EXTDEBUG}
  1292. supreg : tsuperregister;
  1293. begin
  1294. { All allocations are available. Now we can generate the
  1295. interference graph. Walk through all instructions, we can
  1296. start with the headertai, because before the header tai is
  1297. only symbols. }
  1298. live_registers.clear;
  1299. p:=headertai;
  1300. while assigned(p) do
  1301. begin
  1302. if p.typ=ait_regalloc then
  1303. with Tai_regalloc(p) do
  1304. begin
  1305. if (getregtype(reg)=regtype) then
  1306. begin
  1307. supreg:=getsupreg(reg);
  1308. case ratype of
  1309. ra_alloc :
  1310. begin
  1311. live_registers.add(supreg);
  1312. add_edges_used(supreg);
  1313. end;
  1314. ra_dealloc :
  1315. begin
  1316. live_registers.delete(supreg);
  1317. add_edges_used(supreg);
  1318. end;
  1319. end;
  1320. { constraints needs always to be updated }
  1321. add_constraints(reg);
  1322. end;
  1323. end;
  1324. add_cpu_interferences(p);
  1325. p:=Tai(p.next);
  1326. end;
  1327. {$ifdef EXTDEBUG}
  1328. if live_registers.length>0 then
  1329. begin
  1330. for i:=0 to live_registers.length-1 do
  1331. begin
  1332. { Only report for imaginary registers }
  1333. if live_registers.buf^[i]>=first_imaginary then
  1334. Comment(V_Warning,'Register '+std_regname(newreg(R_INTREGISTER,live_registers.buf^[i],defaultsub))+' not released');
  1335. end;
  1336. end;
  1337. {$endif}
  1338. end;
  1339. procedure Trgobj.translate_registers(list:taasmoutput);
  1340. var
  1341. hp,p,q:Tai;
  1342. i:shortint;
  1343. {$ifdef arm}
  1344. so:pshifterop;
  1345. {$endif arm}
  1346. begin
  1347. { Leave when no imaginary registers are used }
  1348. if maxreg<=first_imaginary then
  1349. exit;
  1350. p:=Tai(list.first);
  1351. while assigned(p) do
  1352. begin
  1353. case p.typ of
  1354. ait_regalloc:
  1355. with Tai_regalloc(p) do
  1356. begin
  1357. if (getregtype(reg)=regtype) then
  1358. begin
  1359. { Only alloc/dealloc is needed for the optimizer, remove
  1360. other regalloc }
  1361. if not(ratype in [ra_alloc,ra_dealloc]) then
  1362. begin
  1363. q:=Tai(next);
  1364. list.remove(p);
  1365. p.free;
  1366. p:=q;
  1367. continue;
  1368. end
  1369. else
  1370. begin
  1371. setsupreg(reg,reginfo[getsupreg(reg)].colour);
  1372. {
  1373. Remove sequences of release and
  1374. allocation of the same register like. Other combinations
  1375. of release/allocate need to stay in the list.
  1376. # Register X released
  1377. # Register X allocated
  1378. }
  1379. if assigned(previous) and
  1380. (ratype=ra_alloc) and
  1381. (Tai(previous).typ=ait_regalloc) and
  1382. (Tai_regalloc(previous).reg=reg) and
  1383. (Tai_regalloc(previous).ratype=ra_dealloc) then
  1384. begin
  1385. q:=Tai(next);
  1386. hp:=tai(previous);
  1387. list.remove(hp);
  1388. hp.free;
  1389. list.remove(p);
  1390. p.free;
  1391. p:=q;
  1392. continue;
  1393. end;
  1394. end;
  1395. end;
  1396. end;
  1397. ait_instruction:
  1398. with Taicpu(p) do
  1399. begin
  1400. aktfilepos:=fileinfo;
  1401. for i:=0 to ops-1 do
  1402. with oper[i]^ do
  1403. case typ of
  1404. Top_reg:
  1405. if (getregtype(reg)=regtype) then
  1406. setsupreg(reg,reginfo[getsupreg(reg)].colour);
  1407. Top_ref:
  1408. begin
  1409. if regtype=R_INTREGISTER then
  1410. with ref^ do
  1411. begin
  1412. if base<>NR_NO then
  1413. setsupreg(base,reginfo[getsupreg(base)].colour);
  1414. if index<>NR_NO then
  1415. setsupreg(index,reginfo[getsupreg(index)].colour);
  1416. end;
  1417. end;
  1418. {$ifdef arm}
  1419. Top_shifterop:
  1420. begin
  1421. if regtype=R_INTREGISTER then
  1422. begin
  1423. so:=shifterop;
  1424. if so^.rs<>NR_NO then
  1425. setsupreg(so^.rs,reginfo[getsupreg(so^.rs)].colour);
  1426. end;
  1427. end;
  1428. {$endif arm}
  1429. end;
  1430. { Maybe the operation can be removed when
  1431. it is a move and both arguments are the same }
  1432. if is_same_reg_move(regtype) then
  1433. begin
  1434. q:=Tai(p.next);
  1435. list.remove(p);
  1436. p.free;
  1437. p:=q;
  1438. continue;
  1439. end;
  1440. end;
  1441. end;
  1442. p:=Tai(p.next);
  1443. end;
  1444. aktfilepos:=current_procinfo.exitpos;
  1445. end;
  1446. function trgobj.spill_registers(list:Taasmoutput;headertai:tai):boolean;
  1447. { Returns true if any help registers have been used }
  1448. var
  1449. i : word;
  1450. t : tsuperregister;
  1451. p,q : Tai;
  1452. regs_to_spill_set:Tsuperregisterset;
  1453. spill_temps : ^Tspill_temp_list;
  1454. supreg : tsuperregister;
  1455. templist : taasmoutput;
  1456. begin
  1457. spill_registers:=false;
  1458. live_registers.clear;
  1459. for i:=first_imaginary to maxreg-1 do
  1460. exclude(reginfo[i].flags,ri_selected);
  1461. spill_temps:=allocmem(sizeof(treference)*maxreg);
  1462. supregset_reset(regs_to_spill_set,false,$ffff);
  1463. { Allocate temps and insert in front of the list }
  1464. templist:=taasmoutput.create;
  1465. {Safe: this procedure is only called if there are spilled nodes.}
  1466. with spillednodes do
  1467. for i:=0 to length-1 do
  1468. begin
  1469. t:=buf^[i];
  1470. {Alternative representation.}
  1471. supregset_include(regs_to_spill_set,t);
  1472. {Clear all interferences of the spilled register.}
  1473. clear_interferences(t);
  1474. {Get a temp for the spilled register, the size must at least equal a complete register,
  1475. take also care of the fact that subreg can be larger than a single register like doubles
  1476. that occupy 2 registers }
  1477. tg.gettemp(templist,
  1478. max(tcgsize2size[reg_cgsize(newreg(regtype,t,R_SUBWHOLE))],
  1479. tcgsize2size[reg_cgsize(newreg(regtype,t,reginfo[t].subreg))]),
  1480. tt_noreuse,spill_temps^[t]);
  1481. end;
  1482. list.insertlistafter(headertai,templist);
  1483. templist.free;
  1484. { Walk through all instructions, we can start with the headertai,
  1485. because before the header tai is only symbols }
  1486. p:=headertai;
  1487. while assigned(p) do
  1488. begin
  1489. case p.typ of
  1490. ait_regalloc:
  1491. with Tai_regalloc(p) do
  1492. begin
  1493. if (getregtype(reg)=regtype) then
  1494. begin
  1495. {A register allocation of a spilled register can be removed.}
  1496. supreg:=getsupreg(reg);
  1497. if supregset_in(regs_to_spill_set,supreg) then
  1498. begin
  1499. q:=Tai(p.next);
  1500. list.remove(p);
  1501. p.free;
  1502. p:=q;
  1503. continue;
  1504. end
  1505. else
  1506. begin
  1507. case ratype of
  1508. ra_alloc :
  1509. live_registers.add(supreg);
  1510. ra_dealloc :
  1511. live_registers.delete(supreg);
  1512. end;
  1513. end;
  1514. end;
  1515. end;
  1516. ait_instruction:
  1517. with Taicpu(p) do
  1518. begin
  1519. aktfilepos:=fileinfo;
  1520. if instr_spill_register(list,taicpu(p),regs_to_spill_set,spill_temps^) then
  1521. spill_registers:=true;
  1522. end;
  1523. end;
  1524. p:=Tai(p.next);
  1525. end;
  1526. aktfilepos:=current_procinfo.exitpos;
  1527. {Safe: this procedure is only called if there are spilled nodes.}
  1528. with spillednodes do
  1529. for i:=0 to length-1 do
  1530. tg.ungettemp(list,spill_temps^[buf^[i]]);
  1531. freemem(spill_temps);
  1532. end;
  1533. function trgobj.do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;
  1534. begin
  1535. result:=false;
  1536. end;
  1537. procedure Trgobj.do_spill_read(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);
  1538. begin
  1539. list.insertafter(spilling_create_load(spilltemp,tempreg),pos);
  1540. end;
  1541. procedure Trgobj.do_spill_written(list:Taasmoutput;pos:tai;const spilltemp:treference;tempreg:tregister);
  1542. begin
  1543. list.insertafter(spilling_create_store(tempreg,spilltemp),pos);
  1544. end;
  1545. function trgobj.get_spill_subreg(r : tregister) : tsubregister;
  1546. begin
  1547. result:=defaultsub;
  1548. end;
  1549. function trgobj.instr_spill_register(list:Taasmoutput;
  1550. instr:taicpu;
  1551. const r:Tsuperregisterset;
  1552. const spilltemplist:Tspill_temp_list): boolean;
  1553. var
  1554. counter, regindex: longint;
  1555. regs: tspillregsinfo;
  1556. spilled: boolean;
  1557. procedure addreginfo(reg: tregister; operation: topertype);
  1558. var
  1559. i, tmpindex: longint;
  1560. supreg : tsuperregister;
  1561. begin
  1562. tmpindex := regindex;
  1563. supreg:=getsupreg(reg);
  1564. { did we already encounter this register? }
  1565. for i := 0 to pred(regindex) do
  1566. if (regs[i].orgreg = supreg) then
  1567. begin
  1568. tmpindex := i;
  1569. break;
  1570. end;
  1571. if tmpindex > high(regs) then
  1572. internalerror(2003120301);
  1573. regs[tmpindex].orgreg := supreg;
  1574. regs[tmpindex].spillreg:=reg;
  1575. if supregset_in(r,supreg) then
  1576. begin
  1577. { add/update info on this register }
  1578. regs[tmpindex].mustbespilled := true;
  1579. case operation of
  1580. operand_read:
  1581. regs[tmpindex].regread := true;
  1582. operand_write:
  1583. regs[tmpindex].regwritten := true;
  1584. operand_readwrite:
  1585. begin
  1586. regs[tmpindex].regread := true;
  1587. regs[tmpindex].regwritten := true;
  1588. end;
  1589. end;
  1590. spilled := true;
  1591. end;
  1592. inc(regindex,ord(regindex=tmpindex));
  1593. end;
  1594. procedure tryreplacereg(var reg: tregister);
  1595. var
  1596. i: longint;
  1597. supreg: tsuperregister;
  1598. begin
  1599. supreg:=getsupreg(reg);
  1600. for i:=0 to pred(regindex) do
  1601. if (regs[i].mustbespilled) and
  1602. (regs[i].orgreg=supreg) then
  1603. begin
  1604. { Only replace supreg }
  1605. setsupreg(reg,getsupreg(regs[i].tempreg));
  1606. break;
  1607. end;
  1608. end;
  1609. var
  1610. loadpos,
  1611. storepos : tai;
  1612. oldlive_registers : tsuperregisterworklist;
  1613. begin
  1614. result := false;
  1615. fillchar(regs,sizeof(regs),0);
  1616. for counter := low(regs) to high(regs) do
  1617. regs[counter].orgreg := RS_INVALID;
  1618. spilled := false;
  1619. regindex := 0;
  1620. { check whether and if so which and how (read/written) this instructions contains
  1621. registers that must be spilled }
  1622. for counter := 0 to instr.ops-1 do
  1623. with instr.oper[counter]^ do
  1624. begin
  1625. case typ of
  1626. top_reg:
  1627. begin
  1628. if (getregtype(reg) = regtype) then
  1629. addreginfo(reg,instr.spilling_get_operation_type(counter));
  1630. end;
  1631. top_ref:
  1632. begin
  1633. if regtype in [R_INTREGISTER,R_ADDRESSREGISTER] then
  1634. with ref^ do
  1635. begin
  1636. if (base <> NR_NO) then
  1637. addreginfo(base,instr.spilling_get_operation_type_ref(counter,base));
  1638. if (index <> NR_NO) then
  1639. addreginfo(index,instr.spilling_get_operation_type_ref(counter,index));
  1640. end;
  1641. end;
  1642. {$ifdef ARM}
  1643. top_shifterop:
  1644. begin
  1645. if regtype in [R_INTREGISTER,R_ADDRESSREGISTER] then
  1646. if shifterop^.rs<>NR_NO then
  1647. addreginfo(shifterop^.rs,operand_read);
  1648. end;
  1649. {$endif ARM}
  1650. end;
  1651. end;
  1652. { if no spilling for this instruction we can leave }
  1653. if not spilled then
  1654. exit;
  1655. {$ifdef x86}
  1656. { Try replacing the register with the spilltemp. This is usefull only
  1657. for the i386,x86_64 that support memory locations for several instructions }
  1658. for counter := 0 to pred(regindex) do
  1659. with regs[counter] do
  1660. begin
  1661. if mustbespilled then
  1662. begin
  1663. if do_spill_replace(list,instr,orgreg,spilltemplist[orgreg]) then
  1664. mustbespilled:=false;
  1665. end;
  1666. end;
  1667. {$endif x86}
  1668. {
  1669. There are registers that need are spilled. We generate the
  1670. following code for it. The used positions where code need
  1671. to be inserted are marked using #. Note that code is always inserted
  1672. before the positions using pos.previous. This way the position is always
  1673. the same since pos doesn't change, but pos.previous is modified everytime
  1674. new code is inserted.
  1675. [
  1676. - reg_allocs load spills
  1677. - load spills
  1678. ]
  1679. [#loadpos
  1680. - reg_deallocs
  1681. - reg_allocs
  1682. ]
  1683. [
  1684. - reg_deallocs for load-only spills
  1685. - reg_allocs for store-only spills
  1686. ]
  1687. [#instr
  1688. - original instruction
  1689. ]
  1690. [
  1691. - store spills
  1692. - reg_deallocs store spills
  1693. ]
  1694. [#storepos
  1695. ]
  1696. }
  1697. result := true;
  1698. oldlive_registers.copyfrom(live_registers);
  1699. { Process all tai_regallocs belonging to this instruction, ignore explicit
  1700. inserted regallocs. These can happend for example in i386:
  1701. mov ref,ireg26
  1702. <regdealloc ireg26, instr=taicpu of lea>
  1703. <regalloc edi, insrt=nil>
  1704. lea [ireg26+ireg17],edi
  1705. All released registers are also added to the live_registers because
  1706. they can't be used during the spilling }
  1707. loadpos:=tai(instr.previous);
  1708. while assigned(loadpos) and
  1709. (loadpos.typ=ait_regalloc) and
  1710. ((tai_regalloc(loadpos).instr=nil) or
  1711. (tai_regalloc(loadpos).instr=instr)) do
  1712. begin
  1713. { Only add deallocs belonging to the instruction. Explicit inserted deallocs
  1714. belong to the previous instruction and not the current instruction }
  1715. if (tai_regalloc(loadpos).instr=instr) and
  1716. (tai_regalloc(loadpos).ratype=ra_dealloc) then
  1717. live_registers.add(getsupreg(tai_regalloc(loadpos).reg));
  1718. loadpos:=tai(loadpos.previous);
  1719. end;
  1720. loadpos:=tai(loadpos.next);
  1721. { Load the spilled registers }
  1722. for counter := 0 to pred(regindex) do
  1723. with regs[counter] do
  1724. begin
  1725. if mustbespilled and regread then
  1726. begin
  1727. tempreg:=getregisterinline(list,get_spill_subreg(regs[counter].spillreg));
  1728. do_spill_read(list,tai(loadpos.previous),spilltemplist[orgreg],tempreg);
  1729. end;
  1730. end;
  1731. { Release temp registers of read-only registers, and add reference of the instruction
  1732. to the reginfo }
  1733. for counter := 0 to pred(regindex) do
  1734. with regs[counter] do
  1735. begin
  1736. if mustbespilled and regread and (not regwritten) then
  1737. begin
  1738. { The original instruction will be the next that uses this register }
  1739. add_reg_instruction(instr,tempreg);
  1740. ungetregisterinline(list,tempreg);
  1741. end;
  1742. end;
  1743. { Allocate temp registers of write-only registers, and add reference of the instruction
  1744. to the reginfo }
  1745. for counter := 0 to pred(regindex) do
  1746. with regs[counter] do
  1747. begin
  1748. if mustbespilled and regwritten then
  1749. begin
  1750. { When the register is also loaded there is already a register assigned }
  1751. if (not regread) then
  1752. tempreg:=getregisterinline(list,get_spill_subreg(regs[counter].spillreg));
  1753. { The original instruction will be the next that uses this register, this
  1754. also needs to be done for read-write registers }
  1755. add_reg_instruction(instr,tempreg);
  1756. end;
  1757. end;
  1758. { store the spilled registers }
  1759. storepos:=tai(instr.next);
  1760. for counter := 0 to pred(regindex) do
  1761. with regs[counter] do
  1762. begin
  1763. if mustbespilled and regwritten then
  1764. begin
  1765. do_spill_written(list,tai(storepos.previous),spilltemplist[orgreg],tempreg);
  1766. ungetregisterinline(list,tempreg);
  1767. end;
  1768. end;
  1769. { now all spilling code is generated we can restore the live registers. This
  1770. must be done after the store because the store can need an extra register
  1771. that also needs to conflict with the registers of the instruction }
  1772. live_registers.done;
  1773. live_registers:=oldlive_registers;
  1774. { substitute registers }
  1775. for counter:=0 to instr.ops-1 do
  1776. with instr.oper[counter]^ do
  1777. begin
  1778. case typ of
  1779. top_reg:
  1780. begin
  1781. if (getregtype(reg) = regtype) then
  1782. tryreplacereg(reg);
  1783. end;
  1784. top_ref:
  1785. begin
  1786. if regtype in [R_INTREGISTER,R_ADDRESSREGISTER] then
  1787. begin
  1788. tryreplacereg(ref^.base);
  1789. tryreplacereg(ref^.index);
  1790. end;
  1791. end;
  1792. {$ifdef ARM}
  1793. top_shifterop:
  1794. begin
  1795. if regtype in [R_INTREGISTER,R_ADDRESSREGISTER] then
  1796. tryreplacereg(shifterop^.rs);
  1797. end;
  1798. {$endif ARM}
  1799. end;
  1800. end;
  1801. end;
  1802. end.