rgobj.pas 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672
  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. {# @abstract(Abstract register allocator unit)
  22. This unit contains services to allocate, free
  23. references and registers which are used by
  24. the code generator.
  25. }
  26. {*******************************************************************************
  27. (applies to new register allocator)
  28. Register allocator introduction.
  29. Free Pascal uses a Chaitin style register allocator. We use a variant similair
  30. to the one described in the book "Modern compiler implementation in C" by
  31. Andrew W. Appel., published by Cambridge University Press.
  32. The register allocator that is described by Appel uses a much improved way
  33. of register coalescing, called "iterated register coalescing". Instead
  34. of doing coalescing as a prepass to the register allocation, the coalescing
  35. is done inside the register allocator. This has the advantage that the
  36. register allocator can coalesce very aggresively without introducing spills.
  37. Reading this book is recommended for a complete understanding. Here is a small
  38. introduction.
  39. The code generator thinks it has an infinite amount of registers. Our processor
  40. has a limited amount of registers. Therefore we must reduce the amount of
  41. registers until there are less enough to fit into the processors registers.
  42. Registers can interfere or not interfere. If two imaginary registers interfere
  43. they cannot be placed into the same psysical register. Reduction of registers
  44. is done by:
  45. - "coalescing" Two registers that do not interfere are combined
  46. into one register.
  47. - "spilling" A register is changed into a memory location and the generated
  48. code is modified to use the memory location instead of the register.
  49. Register allocation is a graph colouring problem. Each register is a colour, and
  50. if two registers interfere there is a connection between them in the graph.
  51. In addition to the imaginary registers in the code generator, the psysical
  52. CPU registers are also present in this graph. This allows us to make
  53. interferences between imaginary registers and cpu registers. This is very
  54. usefull for describing archtectural constraints, like for example that
  55. the div instruction modifies edx, so variables that are in use at that time
  56. cannot be stored into edx. This can be modelled by making edx interfere
  57. with those variables.
  58. Graph colouring is an NP complete problem. Therefore we use an approximation
  59. that pushes registers to colour on to a stack. This is done in the "simplify"
  60. procedure.
  61. The register allocator first checks which registers are a candidate for
  62. coalescing.
  63. *******************************************************************************}
  64. unit rgobj;
  65. interface
  66. uses
  67. cutils, cpubase,
  68. cpuinfo,
  69. aasmbase,aasmtai,aasmcpu,
  70. cclasses,globtype,cginfo,cgbase,node
  71. {$ifdef delphi}
  72. ,dmisc
  73. {$endif}
  74. ;
  75. const
  76. ALL_OTHERREGISTERS=[low(tregisterindex)..high(tregisterindex)];
  77. type
  78. regvarother_longintarray = array[tregisterindex] of longint;
  79. regvarother_booleanarray = array[tregisterindex] of boolean;
  80. regvarint_longintarray = array[first_int_supreg..last_int_supreg] of longint;
  81. regvarint_ptreearray = array[first_int_supreg..last_int_supreg] of tnode;
  82. tpushedsavedloc = record
  83. case byte of
  84. 0: (pushed: boolean);
  85. 1: (ofs: longint);
  86. end;
  87. tpushedsavedother = array[tregisterindex] of tpushedsavedloc;
  88. Tinterferencebitmap=array[Tsuperregister] of set of Tsuperregister;
  89. Tinterferenceadjlist=array[Tsuperregister] of Pstring;
  90. Tinterferencegraph=record
  91. bitmap:Tinterferencebitmap;
  92. adjlist:Tinterferenceadjlist;
  93. end;
  94. Pinterferencegraph=^Tinterferencegraph;
  95. Tmovelist=record
  96. count:cardinal;
  97. data:array[0..$ffff] of Tlinkedlistitem;
  98. end;
  99. Pmovelist=^Tmovelist;
  100. {In the register allocator we keep track of move instructions.
  101. These instructions are moved between five linked lists. There
  102. is also a linked list per register to keep track about the moves
  103. it is associated with. Because we need to determine quickly in
  104. which of the five lists it is we add anu enumeradtion to each
  105. move instruction.}
  106. Tmoveset=(ms_coalesced_moves,ms_constrained_moves,ms_frozen_moves,
  107. ms_worklist_moves,ms_active_moves);
  108. Tmoveins=class(Tlinkedlistitem)
  109. moveset:Tmoveset;
  110. { $ifdef ra_debug}
  111. x,y:Tsuperregister;
  112. { $endif}
  113. instruction:Taicpu;
  114. end;
  115. {#
  116. This class implements the abstract register allocator
  117. It is used by the code generator to allocate and free
  118. registers which might be valid across nodes. It also
  119. contains utility routines related to registers.
  120. Some of the methods in this class should be overriden
  121. by cpu-specific implementations.
  122. }
  123. trgobj = class
  124. { The "usableregsxxx" contain all registers of type "xxx" that }
  125. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  126. { contain all registers of type "xxx" that aren't currently }
  127. { allocated }
  128. maxintreg:Tsuperregister;
  129. usable_registers:string[32];
  130. unusedregsint,usableregsint:Tsuperregisterset;
  131. unusedregsaddr,usableregsaddr:Tsuperregisterset;
  132. unusedregsfpu,usableregsfpu : Tsuperregisterset;
  133. unusedregsmm,usableregsmm : Tsuperregisterset;
  134. { these counters contain the number of elements in the }
  135. { unusedregsxxx/usableregsxxx sets }
  136. countunusedregsfpu,
  137. countunusedregsmm : byte;
  138. countusableregsint,
  139. countusableregsaddr,
  140. countusableregsfpu,
  141. countusableregsmm : byte;
  142. { Contains the registers which are really used by the proc itself.
  143. It doesn't take care of registers used by called procedures
  144. }
  145. preserved_by_proc_int,
  146. used_in_proc_int : Tsuperregisterset;
  147. used_in_proc_other : totherregisterset;
  148. reg_pushes_other : regvarother_longintarray;
  149. is_reg_var_other : regvarother_booleanarray;
  150. is_reg_var_int : Tsuperregisterset;
  151. regvar_loaded_other : regvarother_booleanarray;
  152. regvar_loaded_int : Tsuperregisterset;
  153. colour : array[Tsuperregister] of Tsuperregister;
  154. spillednodes : string;
  155. { tries to hold the amount of times which the current tree is processed }
  156. t_times: longint;
  157. constructor create(Acpu_registers:byte;const Ausable:string);
  158. destructor destroy;override;
  159. {# Allocate a general purpose register
  160. An internalerror will be generated if there
  161. is no more free registers which can be allocated
  162. }
  163. function getregisterint(list:Taasmoutput;size:Tcgsize):Tregister;
  164. procedure add_constraints(reg:Tregister);virtual;
  165. {# Allocate an ABT register
  166. An internalerror will be generated if there
  167. is no more free registers which can be allocated
  168. An explanantion of abt registers can be found near the implementation.
  169. }
  170. function getabtregisterint(list:Taasmoutput;size:Tcgsize):Tregister;
  171. {# Free a general purpose register
  172. @param(r register to free)
  173. }
  174. procedure ungetregisterint(list: taasmoutput; r : tregister); virtual;
  175. {# Allocate a floating point register
  176. An internalerror will be generated if there
  177. is no more free registers which can be allocated
  178. }
  179. function getregisterfpu(list: taasmoutput;size:Tcgsize) : tregister; virtual;
  180. {# Free a floating point register
  181. @param(r register to free)
  182. }
  183. procedure ungetregisterfpu(list: taasmoutput; r : tregister;size:TCGsize); virtual;
  184. function getregistermm(list: taasmoutput) : tregister; virtual;
  185. procedure ungetregistermm(list: taasmoutput; r : tregister); virtual;
  186. {# Allocate an address register.
  187. Address registers are the only registers which can
  188. be used as a base register in references (treference).
  189. On most cpu's this is the same as a general purpose
  190. register.
  191. An internalerror will be generated if there
  192. is no more free registers which can be allocated
  193. }
  194. function getaddressregister(list:Taasmoutput):Tregister;virtual;
  195. procedure ungetaddressregister(list: taasmoutput; r: tregister); virtual;
  196. {# Verify if the specified register is an address or
  197. general purpose register. Returns TRUE if @var(reg)
  198. is an adress register.
  199. This routine should only be used to check on
  200. general purpose or address register. It will
  201. not work on multimedia or floating point
  202. registers
  203. @param(reg register to verify)
  204. }
  205. function isaddressregister(reg: tregister): boolean; virtual;
  206. {# Tries to allocate the passed register, if possible
  207. @param(r specific register to allocate)
  208. }
  209. function getexplicitregisterint(list:Taasmoutput;r:Tregister):Tregister;virtual;
  210. {# Tries to allocate the passed fpu register, if possible
  211. @param(r specific register to allocate)
  212. }
  213. function getexplicitregisterfpu(list : taasmoutput; r : Tregister) : tregister;virtual;
  214. procedure allocexplicitregistersint(list:Taasmoutput;r:Tsuperregisterset);
  215. procedure deallocexplicitregistersint(list:Taasmoutput;r:Tsuperregisterset);
  216. {# Deallocate any kind of register }
  217. procedure ungetregister(list: taasmoutput; r : tregister); virtual;
  218. {# Deallocate all registers which are allocated
  219. in the specified reference. On most systems,
  220. this will free the base and index registers
  221. of the specified reference.
  222. @param(ref reference which must have its registers freed)
  223. }
  224. procedure ungetreference(list: taasmoutput; const ref : treference); virtual;
  225. {# Convert a register to a specified register size, and return that register size }
  226. function makeregsize(reg: tregister; size: tcgsize): tregister; virtual;
  227. {# saves register variables (restoring happens automatically) }
  228. procedure saveotherregvars(list:Taasmoutput;const s:Totherregisterset);
  229. {# Saves in temporary references (allocated via the temp. allocator)
  230. the registers defined in @var(s). The registers are only saved
  231. if they are currently in use, otherwise they are left as is.
  232. On processors which have instructions which manipulate the stack,
  233. this routine should be overriden for performance reasons.
  234. @param(list) List to add the instruction to
  235. @param(saved) Array of saved register information
  236. @param(s) Registers which might require saving
  237. }
  238. procedure saveusedotherregisters(list:Taasmoutput;
  239. var saved:Tpushedsavedother;
  240. const s:Totherregisterset);virtual;
  241. {# Restores the registers which were saved with a call
  242. to @var(saveusedregisters).
  243. On processors which have instructions which manipulate the stack,
  244. this routine should be overriden for performance reasons.
  245. }
  246. procedure restoreusedotherregisters(list:Taasmoutput;
  247. const saved:Tpushedsavedother);virtual;
  248. { used when deciding which registers to use for regvars }
  249. procedure incrementotherregisterpushed(const s: totherregisterset);
  250. procedure clearregistercount;
  251. procedure resetusableregisters;virtual;
  252. procedure makeregvarint(reg:Tsuperregister);
  253. procedure makeregvarother(reg:Tregister);
  254. procedure saveStateForInline(var state: pointer);virtual;
  255. procedure restoreStateAfterInline(var state: pointer);virtual;
  256. procedure saveUnusedState(var state: pointer);virtual;
  257. procedure restoreUnusedState(var state: pointer);virtual;
  258. {$ifdef EXTDEBUG}
  259. procedure writegraph(loopidx:longint);
  260. {$endif EXTDEBUG}
  261. procedure add_move_instruction(instr:Taicpu);
  262. procedure prepare_colouring;
  263. procedure epilogue_colouring;
  264. procedure colour_registers;
  265. function spill_registers(list:Taasmoutput;headertai:tai;const regs_to_spill:string):boolean;
  266. procedure add_edge(u,v:Tsuperregister);
  267. protected
  268. cpu_registers:byte;
  269. igraph:Tinterferencegraph;
  270. degree:array[0..255] of byte;
  271. alias:array[Tsuperregister] of Tsuperregister;
  272. simplifyworklist,freezeworklist,spillworklist:string;
  273. coalescednodes:string;
  274. selectstack:string;
  275. abtlist:string;
  276. movelist:array[Tsuperregister] of Pmovelist;
  277. worklist_moves,active_moves,frozen_moves,
  278. coalesced_moves,constrained_moves:Tlinkedlist;
  279. { the following two contain the common (generic) code for all }
  280. { get- and ungetregisterxxx functions/procedures }
  281. function getregistergenother(list: taasmoutput; const lowreg, highreg: tsuperregister;
  282. var unusedregs:Tsuperregisterset;var countunusedregs:byte): tregister;
  283. function getregistergenint(list:Taasmoutput;subreg:Tsubregister;
  284. const lowreg,highreg:Tsuperregister;
  285. var fusedinproc,unusedregs:Tsuperregisterset):Tregister;
  286. procedure ungetregistergen(list: taasmoutput; r: tregister;
  287. const usableregs:tsuperregisterset;var unusedregs: tsuperregisterset; var countunusedregs: byte);
  288. procedure ungetregistergenint(list:taasmoutput;r:Tregister;
  289. const usableregs:Tsuperregisterset;
  290. var unusedregs:Tsuperregisterset);
  291. procedure getregisterintinline(list:Taasmoutput;position:Tai;subreg:Tsubregister;var result:Tregister);
  292. procedure ungetregisterintinline(list:Taasmoutput;position:Tai;r:Tregister);
  293. procedure add_edges_used(u:Tsuperregister);
  294. procedure add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  295. function move_related(n:Tsuperregister):boolean;
  296. procedure make_work_list;
  297. procedure enable_moves(n:Tsuperregister);
  298. procedure decrement_degree(m:Tsuperregister);
  299. procedure simplify;
  300. function get_alias(n:Tsuperregister):Tsuperregister;
  301. procedure add_worklist(u:Tsuperregister);
  302. function adjacent_ok(u,v:Tsuperregister):boolean;
  303. function conservative(u,v:Tsuperregister):boolean;
  304. procedure combine(u,v:Tsuperregister);
  305. procedure coalesce;
  306. procedure freeze_moves(u:Tsuperregister);
  307. procedure freeze;
  308. procedure select_spill;
  309. procedure assign_colours;
  310. procedure clear_interferences(u:Tsuperregister);
  311. end;
  312. trgobjclass = class of trgobj;
  313. const
  314. {# This value is used in tsaved. If the array value is equal
  315. to this, then this means that this register is not used.
  316. }
  317. reg_not_saved = $7fffffff;
  318. var
  319. rg : trgobj;
  320. { trerefence handling }
  321. {# Clear to zero a treference }
  322. procedure reference_reset(var ref : treference);
  323. {# Clear to zero a treference, and set is base address
  324. to base register.
  325. }
  326. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  327. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  328. procedure reference_release(list: taasmoutput; const ref : treference);
  329. { This routine verifies if two references are the same, and
  330. if so, returns TRUE, otherwise returns false.
  331. }
  332. function references_equal(sref : treference;dref : treference) : boolean;
  333. { tlocation handling }
  334. procedure location_reset(var l : tlocation;lt:TCGLoc;lsize:TCGSize);
  335. procedure location_release(list: taasmoutput; const l : tlocation);
  336. procedure location_freetemp(list: taasmoutput; const l : tlocation);
  337. procedure location_copy(var destloc:tlocation; const sourceloc : tlocation);
  338. procedure location_swap(var destloc,sourceloc : tlocation);
  339. type
  340. psavedstate = ^tsavedstate;
  341. tsavedstate = record
  342. unusedregsint,usableregsint : Tsuperregisterset;
  343. unusedregsaddr,usableregsaddr : Tsuperregisterset;
  344. unusedregsfpu,usableregsfpu : totherregisterset;
  345. unusedregsmm,usableregsmm : totherregisterset;
  346. countunusedregsfpu,
  347. countunusedregsmm : byte;
  348. countusableregsint,
  349. countusableregsfpu,
  350. countusableregsmm : byte;
  351. { contains the registers which are really used by the proc itself }
  352. used_in_proc_int : Tsuperregisterset;
  353. used_in_proc_other : totherregisterset;
  354. reg_pushes_other : regvarother_longintarray;
  355. reg_pushes_int : regvarint_longintarray;
  356. is_reg_var_other : regvarother_booleanarray;
  357. is_reg_var_int : Tsuperregisterset;
  358. regvar_loaded_other: regvarother_booleanarray;
  359. regvar_loaded_int: Tsuperregisterset;
  360. end;
  361. punusedstate = ^tunusedstate;
  362. tunusedstate = record
  363. unusedregsaddr : Tsuperregisterset;
  364. unusedregsfpu : totherregisterset;
  365. unusedregsmm : totherregisterset;
  366. countunusedregsfpu,
  367. countunusedregsmm : byte;
  368. end;
  369. implementation
  370. uses
  371. systems,
  372. globals,verbose,
  373. cgobj,tgobj;
  374. constructor Trgobj.create(Acpu_registers:byte;const Ausable:string);
  375. var i:Tsuperregister;
  376. begin
  377. used_in_proc_int := [];
  378. used_in_proc_other:=[];
  379. t_times := 0;
  380. resetusableregisters;
  381. maxintreg:=first_int_imreg;
  382. cpu_registers:=Acpu_registers;
  383. unusedregsint:=[0..254]; { 255 (RS_INVALID) can't be used }
  384. unusedregsfpu:=usableregsfpu;
  385. unusedregsmm:=usableregsmm;
  386. countunusedregsfpu:=countusableregsfpu;
  387. countunusedregsmm:=countusableregsmm;
  388. {$ifdef powerpc}
  389. preserved_by_proc_int:=[RS_R13..RS_R31];
  390. {$else powerpc}
  391. preserved_by_proc_int:=[];
  392. {$endif powerpc}
  393. fillchar(igraph,sizeof(igraph),0);
  394. fillchar(degree,sizeof(degree),0);
  395. {Precoloured nodes should have an infinite degree, which we can approach
  396. by 255.}
  397. for i:=first_int_supreg to last_int_supreg do
  398. degree[i]:=255;
  399. fillchar(movelist,sizeof(movelist),0);
  400. worklist_moves:=Tlinkedlist.create;
  401. usable_registers:=Ausable;
  402. abtlist:='';
  403. fillchar(colour,sizeof(colour),RS_INVALID);
  404. end;
  405. destructor Trgobj.destroy;
  406. var i:Tsuperregister;
  407. begin
  408. for i:=low(Tsuperregister) to high(Tsuperregister) do
  409. begin
  410. if igraph.adjlist[i]<>nil then
  411. dispose(igraph.adjlist[i]);
  412. if movelist[i]<>nil then
  413. dispose(movelist[i]);
  414. end;
  415. worklist_moves.free;
  416. end;
  417. function trgobj.getregistergenother(list: taasmoutput; const lowreg, highreg: tsuperregister;
  418. var unusedregs: tsuperregisterset; var countunusedregs: byte): tregister;
  419. var
  420. i: tsuperregister;
  421. r: Tregister;
  422. begin
  423. for i:=lowreg to highreg do
  424. begin
  425. if i in unusedregs then
  426. begin
  427. exclude(unusedregs,i);
  428. include(used_in_proc_other,i);
  429. dec(countunusedregs);
  430. {$warning Only FPU Registers supported}
  431. r:=newreg(R_FPUREGISTER,i,R_SUBNONE);
  432. list.concat(tai_regalloc.alloc(r));
  433. result := r;
  434. exit;
  435. end;
  436. end;
  437. internalerror(10);
  438. end;
  439. function Trgobj.getregistergenint(list:Taasmoutput;
  440. subreg:Tsubregister;
  441. const lowreg,highreg:Tsuperregister;
  442. var fusedinproc,unusedregs:Tsuperregisterset):Tregister;
  443. var i,p:Tsuperregister;
  444. r:Tregister;
  445. min : byte;
  446. adj : pstring;
  447. begin
  448. if maxintreg<highreg then
  449. begin
  450. inc(maxintreg);
  451. p:=maxintreg;
  452. min:=0;
  453. end
  454. else
  455. begin
  456. min:=$ff;
  457. p:=first_int_imreg;
  458. for i:=lowreg to maxintreg do
  459. if (i in unusedregs) and
  460. (pos(char(i),abtlist)=0) then
  461. begin
  462. adj:=igraph.adjlist[Tsuperregister(i)];
  463. if adj=nil then
  464. begin
  465. p:=i;
  466. min:=0;
  467. break; {We won't find smaller ones.}
  468. end
  469. else
  470. if length(adj^)<min then
  471. begin
  472. p:=i;
  473. min:=length(adj^);
  474. if min=0 then
  475. break; {We won't find smaller ones.}
  476. end;
  477. end;
  478. if min=$ff then
  479. begin
  480. {$ifdef ALLOWDUPREG}
  481. result:=newreg(R_INTREGISTER,RS_INVALID,subreg);
  482. exit;
  483. {$else}
  484. internalerror(10);
  485. {$endif}
  486. end;
  487. end;
  488. exclude(unusedregs,p);
  489. include(fusedinproc,p);
  490. r:=newreg(R_INTREGISTER,p,subreg);
  491. list.concat(Tai_regalloc.alloc(r));
  492. add_edges_used(p);
  493. add_constraints(r);
  494. result:=r;
  495. end;
  496. procedure trgobj.ungetregistergen(list: taasmoutput; r: tregister;
  497. const usableregs: tsuperregisterset; var unusedregs: tsuperregisterset; var countunusedregs: byte);
  498. var
  499. supreg : tsuperregister;
  500. begin
  501. supreg:=getsupreg(r);
  502. { takes much time }
  503. if not(supreg in usableregs) then
  504. exit;
  505. if (supreg in unusedregs) then
  506. exit
  507. else
  508. inc(countunusedregs);
  509. include(unusedregs,supreg);
  510. list.concat(tai_regalloc.dealloc(r));
  511. end;
  512. procedure trgobj.ungetregistergenint(list:taasmoutput;r:Tregister;
  513. const usableregs:Tsuperregisterset;
  514. var unusedregs:Tsuperregisterset);
  515. var
  516. supreg:Tsuperregister;
  517. begin
  518. supreg:=getsupreg(r);
  519. { takes much time }
  520. if supreg in is_reg_var_int then
  521. exit;
  522. if (supreg in unusedregs) then
  523. exit;
  524. include(unusedregs,supreg);
  525. list.concat(tai_regalloc.dealloc(r));
  526. add_edges_used(supreg);
  527. add_constraints(r);
  528. end;
  529. function trgobj.getregisterint(list:taasmoutput;size:Tcgsize):Tregister;
  530. var subreg:Tsubregister;
  531. begin
  532. subreg:=cgsize2subreg(size);
  533. result:=getregistergenint(list,
  534. subreg,
  535. first_int_imreg,
  536. last_int_imreg,
  537. used_in_proc_int,
  538. unusedregsint);
  539. add_constraints(getregisterint);
  540. end;
  541. procedure Trgobj.add_constraints(reg:Tregister);
  542. begin
  543. end;
  544. procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
  545. begin
  546. ungetregistergenint(list,r,usableregsint,unusedregsint);
  547. end;
  548. { tries to allocate the passed register, if possible }
  549. function trgobj.getexplicitregisterint(list:Taasmoutput;r:Tregister):Tregister;
  550. var supreg : tsuperregister;
  551. begin
  552. supreg:=getsupreg(r);
  553. if supreg in unusedregsint then
  554. begin
  555. exclude(unusedregsint,supreg);
  556. include(used_in_proc_int,supreg);
  557. list.concat(tai_regalloc.alloc(r));
  558. add_edges_used(supreg);
  559. add_constraints(r);
  560. end
  561. else
  562. {$ifndef ALLOWDUPREG}
  563. internalerror(200301103)
  564. {$endif ALLOWDUPREG}
  565. ;
  566. getexplicitregisterint:=r;
  567. end;
  568. procedure Trgobj.allocexplicitregistersint(list:Taasmoutput;r:Tsuperregisterset);
  569. var reg:Tregister;
  570. i:Tsuperregister;
  571. begin
  572. if unusedregsint*r=r then
  573. begin
  574. unusedregsint:=unusedregsint-r;
  575. used_in_proc_int:=used_in_proc_int+r;
  576. for i:=first_int_supreg to last_int_supreg do
  577. if i in r then
  578. begin
  579. add_edges_used(i);
  580. reg:=newreg(R_INTREGISTER,i,R_SUBWHOLE);
  581. list.concat(Tai_regalloc.alloc(reg));
  582. end;
  583. end
  584. else
  585. {$ifndef ALLOWDUPREG}
  586. internalerror(200305061)
  587. {$endif ALLOWDUPREG}
  588. ;
  589. end;
  590. procedure Trgobj.deallocexplicitregistersint(list:Taasmoutput;r:Tsuperregisterset);
  591. var reg:Tregister;
  592. i:Tsuperregister;
  593. begin
  594. if unusedregsint*r=[] then
  595. begin
  596. unusedregsint:=unusedregsint+r;
  597. for i:=last_int_supreg downto first_int_supreg do
  598. if i in r then
  599. begin
  600. reg:=newreg(R_INTREGISTER,i,R_SUBWHOLE);
  601. list.concat(Tai_regalloc.dealloc(reg));
  602. end;
  603. end
  604. else
  605. {$ifndef ALLOWDUPREG}
  606. internalerror(200305061)
  607. {$endif ALLOWDUPREG}
  608. ;
  609. end;
  610. { tries to allocate the passed register, if possible }
  611. function trgobj.getexplicitregisterfpu(list : taasmoutput; r : Tregister) : tregister;
  612. var
  613. supreg : tsuperregister;
  614. begin
  615. supreg:=getsupreg(r);
  616. if supreg in unusedregsfpu then
  617. begin
  618. dec(countunusedregsfpu);
  619. exclude(unusedregsfpu,supreg);
  620. include(used_in_proc_other,supreg);
  621. list.concat(tai_regalloc.alloc(r));
  622. getexplicitregisterfpu:=r;
  623. end
  624. else
  625. {$warning Size for FPU reg is maybe not correct}
  626. getexplicitregisterfpu:=getregisterfpu(list,OS_F32);
  627. end;
  628. function trgobj.getregisterfpu(list: taasmoutput;size:Tcgsize) : tregister;
  629. begin
  630. if countunusedregsfpu=0 then
  631. internalerror(10);
  632. {$warning TODO firstsavefpureg}
  633. result := getregistergenother(list,firstsavefpureg,lastsavefpureg,
  634. unusedregsfpu,countunusedregsfpu);
  635. end;
  636. procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister;size:TCGsize);
  637. begin
  638. ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
  639. countunusedregsfpu);
  640. end;
  641. function trgobj.getregistermm(list: taasmoutput) : tregister;
  642. begin
  643. if countunusedregsmm=0 then
  644. internalerror(10);
  645. result := getregistergenother(list,firstsavemmreg,lastsavemmreg,
  646. unusedregsmm,countunusedregsmm);
  647. end;
  648. procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
  649. begin
  650. ungetregistergen(list,r,usableregsmm,unusedregsmm,
  651. countunusedregsmm);
  652. end;
  653. function trgobj.getaddressregister(list:Taasmoutput): tregister;
  654. begin
  655. {An address register is OS_INT per definition.}
  656. result := getregisterint(list,OS_INT);
  657. end;
  658. procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
  659. begin
  660. ungetregisterint(list,r);
  661. end;
  662. function trgobj.isaddressregister(reg: tregister): boolean;
  663. begin
  664. result := true;
  665. end;
  666. procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
  667. begin
  668. if r=NR_NO then
  669. exit;
  670. if getregtype(r)=R_FPUREGISTER then
  671. ungetregisterfpu(list,r,OS_NO)
  672. else if getregtype(r)=R_MMXREGISTER then
  673. ungetregistermm(list,r)
  674. else if getregtype(r)=R_ADDRESSREGISTER then
  675. ungetaddressregister(list,r)
  676. else internalerror(2002070602);
  677. end;
  678. procedure trgobj.ungetreference(list : taasmoutput; const ref : treference);
  679. begin
  680. if (ref.base<>NR_NO) and (ref.base<>NR_FRAME_POINTER_REG) then
  681. ungetregisterint(list,ref.base);
  682. if (ref.index<>NR_NO) and (ref.index<>NR_FRAME_POINTER_REG) then
  683. ungetregisterint(list,ref.index);
  684. end;
  685. procedure trgobj.saveotherregvars(list: taasmoutput; const s: totherregisterset);
  686. var
  687. r: Tregister;
  688. begin
  689. if not(cs_regvars in aktglobalswitches) then
  690. exit;
  691. {$warning TODO firstsavefpureg}
  692. {
  693. if firstsavefpureg <> NR_NO then
  694. for r.enum := firstsavefpureg to lastsavefpureg do
  695. if is_reg_var_other[r.enum] and
  696. (r.enum in s) then
  697. store_regvar(list,r);
  698. if firstsavemmreg <> R_NO then
  699. for r.enum := firstsavemmreg to lastsavemmreg do
  700. if is_reg_var_other[r.enum] and
  701. (r.enum in s) then
  702. store_regvar(list,r);
  703. }
  704. end;
  705. procedure trgobj.saveusedotherregisters(list: taasmoutput;
  706. var saved : tpushedsavedother; const s: totherregisterset);
  707. var
  708. r : tregister;
  709. hr : treference;
  710. begin
  711. used_in_proc_other:=used_in_proc_other + s;
  712. {$warning TODO firstsavefpureg}
  713. (*
  714. { don't try to save the fpu registers if not desired (e.g. for }
  715. { the 80x86) }
  716. if firstsavefpureg <> R_NO then
  717. for r.enum:=firstsavefpureg to lastsavefpureg do
  718. begin
  719. saved[r.enum].ofs:=reg_not_saved;
  720. { if the register is used by the calling subroutine and if }
  721. { it's not a regvar (those are handled separately) }
  722. if not is_reg_var_other[r.enum] and
  723. (r.enum in s) and
  724. { and is present in use }
  725. not(r.enum in unusedregsfpu) then
  726. begin
  727. { then save it }
  728. tg.GetTemp(list,extended_size,tt_persistent,hr);
  729. saved[r.enum].ofs:=hr.offset;
  730. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  731. cg.a_reg_dealloc(list,r);
  732. include(unusedregsfpu,r.enum);
  733. inc(countunusedregsfpu);
  734. end;
  735. end;
  736. { don't save the vector registers if there's no support for them }
  737. if firstsavemmreg <> R_NO then
  738. for r.enum:=firstsavemmreg to lastsavemmreg do
  739. begin
  740. saved[r.enum].ofs:=reg_not_saved;
  741. { if the register is in use and if it's not a regvar (those }
  742. { are handled separately), save it }
  743. if not is_reg_var_other[r.enum] and
  744. (r.enum in s) and
  745. { and is present in use }
  746. not(r.enum in unusedregsmm) then
  747. begin
  748. { then save it }
  749. tg.GetTemp(list,mmreg_size,tt_persistent,hr);
  750. saved[r.enum].ofs:=hr.offset;
  751. cg.a_loadmm_reg_ref(list,r,hr);
  752. cg.a_reg_dealloc(list,r);
  753. include(unusedregsmm,r.enum);
  754. inc(countunusedregsmm);
  755. end;
  756. end;
  757. *)
  758. end;
  759. procedure trgobj.restoreusedotherregisters(list : taasmoutput;
  760. const saved : tpushedsavedother);
  761. var
  762. r,r2 : tregister;
  763. hr : treference;
  764. begin
  765. {$warning TODO firstsavefpureg}
  766. (*
  767. if firstsavemmreg <> R_NO then
  768. for r.enum:=lastsavemmreg downto firstsavemmreg do
  769. begin
  770. if saved[r.enum].ofs <> reg_not_saved then
  771. begin
  772. r2.enum:=R_INTREGISTER;
  773. r2.number:=NR_FRAME_POINTER_REG;
  774. reference_reset_base(hr,r2,saved[r.enum].ofs);
  775. cg.a_reg_alloc(list,r);
  776. cg.a_loadmm_ref_reg(list,hr,r);
  777. if not (r.enum in unusedregsmm) then
  778. { internalerror(10)
  779. in n386cal we always save/restore the reg *state*
  780. using save/restoreunusedstate -> the current state
  781. may not be real (JM) }
  782. else
  783. begin
  784. dec(countunusedregsmm);
  785. exclude(unusedregsmm,r.enum);
  786. end;
  787. tg.UnGetTemp(list,hr);
  788. end;
  789. end;
  790. if firstsavefpureg <> R_NO then
  791. for r.enum:=lastsavefpureg downto firstsavefpureg do
  792. begin
  793. if saved[r.enum].ofs <> reg_not_saved then
  794. begin
  795. r2.enum:=R_INTREGISTER;
  796. r2.number:=NR_FRAME_POINTER_REG;
  797. reference_reset_base(hr,r2,saved[r.enum].ofs);
  798. cg.a_reg_alloc(list,r);
  799. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  800. if not (r.enum in unusedregsfpu) then
  801. { internalerror(10)
  802. in n386cal we always save/restore the reg *state*
  803. using save/restoreunusedstate -> the current state
  804. may not be real (JM) }
  805. else
  806. begin
  807. dec(countunusedregsfpu);
  808. exclude(unusedregsfpu,r.enum);
  809. end;
  810. tg.UnGetTemp(list,hr);
  811. end;
  812. end;
  813. *)
  814. end;
  815. procedure trgobj.incrementotherregisterpushed(const s:Totherregisterset);
  816. {$ifdef i386}
  817. var
  818. regi : Tregister;
  819. {$endif i386}
  820. begin
  821. {$warning TODO firstsavefpureg}
  822. (*
  823. {$ifdef i386}
  824. if firstsavefpureg <> R_NO then
  825. for regi:=firstsavefpureg to lastsavefpureg do
  826. begin
  827. if (regi in s) then
  828. inc(reg_pushes_other[regi],t_times*2);
  829. end;
  830. if firstsavemmreg <> R_NO then
  831. for regi:=firstsavemmreg to lastsavemmreg do
  832. begin
  833. if (regi in s) then
  834. inc(reg_pushes_other[regi],t_times*2);
  835. end;
  836. {$endif i386}
  837. *)
  838. end;
  839. procedure trgobj.clearregistercount;
  840. begin
  841. fillchar(reg_pushes_other,sizeof(reg_pushes_other),0);
  842. {ifndef i386}
  843. { all used registers will have to be saved at the start and restored }
  844. { at the end, but otoh regpara's do not have to be saved to memory }
  845. { at the start (there is a move from regpara to regvar most of the }
  846. { time though) -> set cost to 100+20 }
  847. {$warning TODO firstsavefpureg}
  848. (*
  849. filldword(reg_pushes_other[firstsavefpureg],ord(lastsavefpureg)-ord(firstsavefpureg)+1,120);
  850. *)
  851. {endif not i386}
  852. fillchar(is_reg_var_other,sizeof(is_reg_var_other),false);
  853. is_reg_var_int:=[];
  854. fillchar(regvar_loaded_other,sizeof(regvar_loaded_other),false);
  855. regvar_loaded_int:=[];
  856. end;
  857. procedure trgobj.resetusableregisters;
  858. begin
  859. { initialize fields with constant values from cpubase }
  860. countusableregsint := cpubase.c_countusableregsint;
  861. countusableregsfpu := cpubase.c_countusableregsfpu;
  862. countusableregsmm := cpubase.c_countusableregsmm;
  863. usableregsint := cpubase.usableregsint;
  864. usableregsfpu := cpubase.usableregsfpu;
  865. usableregsmm := cpubase.usableregsmm;
  866. clearregistercount;
  867. end;
  868. procedure trgobj.makeregvarint(reg:Tsuperregister);
  869. begin
  870. dec(countusableregsint);
  871. include(is_reg_var_int,reg);
  872. end;
  873. procedure trgobj.makeregvarother(reg: tregister);
  874. begin
  875. (*
  876. if reg.enum>lastreg then
  877. internalerror(200301081);
  878. if reg.enum in intregs then
  879. internalerror(200301151)
  880. else if reg.enum in fpuregs then
  881. begin
  882. dec(countusableregsfpu);
  883. dec(countunusedregsfpu);
  884. exclude(usableregsfpu,reg.enum);
  885. exclude(unusedregsfpu,reg.enum);
  886. include(used_in_proc_other,reg.enum);
  887. end
  888. else if reg.enum in mmregs then
  889. begin
  890. dec(countusableregsmm);
  891. dec(countunusedregsmm);
  892. exclude(usableregsmm,reg.enum);
  893. exclude(unusedregsmm,reg.enum);
  894. include(used_in_proc_other,reg.enum);
  895. end;
  896. is_reg_var_other[reg.enum]:=true;
  897. *)
  898. end;
  899. procedure trgobj.saveStateForInline(var state: pointer);
  900. begin
  901. new(psavedstate(state));
  902. psavedstate(state)^.unusedregsint := unusedregsint;
  903. psavedstate(state)^.usableregsint := usableregsint;
  904. psavedstate(state)^.unusedregsfpu := unusedregsfpu;
  905. psavedstate(state)^.usableregsfpu := usableregsfpu;
  906. psavedstate(state)^.unusedregsmm := unusedregsmm;
  907. psavedstate(state)^.usableregsmm := usableregsmm;
  908. psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  909. psavedstate(state)^.countunusedregsmm := countunusedregsmm;
  910. psavedstate(state)^.countusableregsint := countusableregsint;
  911. psavedstate(state)^.countusableregsfpu := countusableregsfpu;
  912. psavedstate(state)^.countusableregsmm := countusableregsmm;
  913. psavedstate(state)^.used_in_proc_int := used_in_proc_int;
  914. psavedstate(state)^.used_in_proc_other := used_in_proc_other;
  915. psavedstate(state)^.reg_pushes_other := reg_pushes_other;
  916. psavedstate(state)^.is_reg_var_int := is_reg_var_int;
  917. psavedstate(state)^.is_reg_var_other := is_reg_var_other;
  918. psavedstate(state)^.regvar_loaded_int := regvar_loaded_int;
  919. psavedstate(state)^.regvar_loaded_other := regvar_loaded_other;
  920. end;
  921. procedure trgobj.restoreStateAfterInline(var state: pointer);
  922. begin
  923. unusedregsint := psavedstate(state)^.unusedregsint;
  924. usableregsint := psavedstate(state)^.usableregsint;
  925. unusedregsfpu := psavedstate(state)^.unusedregsfpu;
  926. usableregsfpu := psavedstate(state)^.usableregsfpu;
  927. unusedregsmm := psavedstate(state)^.unusedregsmm;
  928. usableregsmm := psavedstate(state)^.usableregsmm;
  929. countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
  930. countunusedregsmm := psavedstate(state)^.countunusedregsmm;
  931. countusableregsint := psavedstate(state)^.countusableregsint;
  932. countusableregsfpu := psavedstate(state)^.countusableregsfpu;
  933. countusableregsmm := psavedstate(state)^.countusableregsmm;
  934. used_in_proc_int := psavedstate(state)^.used_in_proc_int;
  935. used_in_proc_other := psavedstate(state)^.used_in_proc_other;
  936. reg_pushes_other := psavedstate(state)^.reg_pushes_other;
  937. is_reg_var_int := psavedstate(state)^.is_reg_var_int;
  938. is_reg_var_other := psavedstate(state)^.is_reg_var_other;
  939. regvar_loaded_other := psavedstate(state)^.regvar_loaded_other;
  940. regvar_loaded_int := psavedstate(state)^.regvar_loaded_int;
  941. dispose(psavedstate(state));
  942. state := nil;
  943. end;
  944. procedure trgobj.saveUnusedState(var state: pointer);
  945. begin
  946. new(punusedstate(state));
  947. punusedstate(state)^.unusedregsfpu := unusedregsfpu;
  948. punusedstate(state)^.unusedregsmm := unusedregsmm;
  949. punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  950. punusedstate(state)^.countunusedregsmm := countunusedregsmm;
  951. end;
  952. procedure trgobj.restoreUnusedState(var state: pointer);
  953. begin
  954. unusedregsfpu := punusedstate(state)^.unusedregsfpu;
  955. unusedregsmm := punusedstate(state)^.unusedregsmm;
  956. countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
  957. countunusedregsmm := punusedstate(state)^.countunusedregsmm;
  958. dispose(punusedstate(state));
  959. state := nil;
  960. end;
  961. procedure Trgobj.add_edge(u,v:Tsuperregister);
  962. {This procedure will add an edge to the virtual interference graph.}
  963. procedure addadj(u,v:Tsuperregister);
  964. begin
  965. if igraph.adjlist[u]=nil then
  966. begin
  967. getmem(igraph.adjlist[u],16);
  968. igraph.adjlist[u]^:='';
  969. end
  970. else if (length(igraph.adjlist[u]^) and 15)=15 then
  971. reallocmem(igraph.adjlist[u],length(igraph.adjlist[u]^)+16);
  972. igraph.adjlist[u]^:=igraph.adjlist[u]^+char(v);
  973. end;
  974. begin
  975. if (u<>v) and not(v in igraph.bitmap[u]) then
  976. begin
  977. include(igraph.bitmap[u],v);
  978. include(igraph.bitmap[v],u);
  979. {Precoloured nodes are not stored in the interference graph.}
  980. if not(u in [first_int_supreg..last_int_supreg]) then
  981. begin
  982. addadj(u,v);
  983. inc(degree[u]);
  984. end;
  985. if not(v in [first_int_supreg..last_int_supreg]) then
  986. begin
  987. addadj(v,u);
  988. inc(degree[v]);
  989. end;
  990. end;
  991. end;
  992. procedure Trgobj.add_edges_used(u:Tsuperregister);
  993. var i:Tsuperregister;
  994. begin
  995. for i:=0 to maxintreg do
  996. if not(i in unusedregsint) then
  997. add_edge(u,i);
  998. end;
  999. {$ifdef EXTDEBUG}
  1000. procedure Trgobj.writegraph(loopidx:longint);
  1001. {This procedure writes out the current interference graph in the
  1002. register allocator.}
  1003. var f:text;
  1004. i,j:Tsuperregister;
  1005. begin
  1006. assign(f,'igraph'+tostr(loopidx));
  1007. rewrite(f);
  1008. writeln(f,'Interference graph');
  1009. writeln(f);
  1010. write(f,' ');
  1011. for i:=0 to 15 do
  1012. for j:=0 to 15 do
  1013. write(f,hexstr(i,1));
  1014. writeln(f);
  1015. write(f,' ');
  1016. for i:=0 to 15 do
  1017. write(f,'0123456789ABCDEF');
  1018. writeln(f);
  1019. for i:=0 to 255 do
  1020. begin
  1021. write(f,hexstr(i,2):4);
  1022. for j:=0 to 255 do
  1023. if j in igraph.bitmap[i] then
  1024. write(f,'*')
  1025. else
  1026. write(f,'-');
  1027. writeln(f);
  1028. end;
  1029. close(f);
  1030. end;
  1031. {$endif EXTDEBUG}
  1032. procedure Trgobj.add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  1033. begin
  1034. if movelist[u]=nil then
  1035. begin
  1036. getmem(movelist[u],64);
  1037. movelist[u]^.count:=0;
  1038. end
  1039. else if (movelist[u]^.count and 15)=15 then
  1040. reallocmem(movelist[u],(movelist[u]^.count+1)*4+64);
  1041. movelist[u]^.data[movelist[u]^.count]:=data;
  1042. inc(movelist[u]^.count);
  1043. end;
  1044. procedure Trgobj.add_move_instruction(instr:Taicpu);
  1045. {This procedure notifies a certain as a move instruction so the
  1046. register allocator can try to eliminate it.}
  1047. var i:Tmoveins;
  1048. ssupreg,dsupreg:Tsuperregister;
  1049. begin
  1050. i:=Tmoveins.create;
  1051. i.moveset:=ms_worklist_moves;
  1052. i.instruction:=instr;
  1053. worklist_moves.insert(i);
  1054. ssupreg:=getsupreg(instr.oper[O_MOV_SOURCE].reg);
  1055. add_to_movelist(ssupreg,i);
  1056. dsupreg:=getsupreg(instr.oper[O_MOV_DEST].reg);
  1057. if ssupreg<>dsupreg then
  1058. {Avoid adding the same move instruction twice to a single register.}
  1059. add_to_movelist(dsupreg,i);
  1060. i.x:=ssupreg;
  1061. i.y:=dsupreg;
  1062. end;
  1063. function Trgobj.move_related(n:Tsuperregister):boolean;
  1064. var i:cardinal;
  1065. begin
  1066. move_related:=false;
  1067. if movelist[n]<>nil then
  1068. begin
  1069. for i:=0 to movelist[n]^.count-1 do
  1070. if Tmoveins(movelist[n]^.data[i]).moveset in
  1071. [ms_worklist_moves,ms_active_moves] then
  1072. begin
  1073. move_related:=true;
  1074. break;
  1075. end;
  1076. end;
  1077. end;
  1078. procedure Trgobj.make_work_list;
  1079. var n:Tsuperregister;
  1080. begin
  1081. {If we have 7 cpu registers, and the degree of a node is 7, we cannot
  1082. assign it to any of the registers, thus it is significant.}
  1083. for n:=first_int_imreg to maxintreg do
  1084. if degree[n]>=cpu_registers then
  1085. spillworklist:=spillworklist+char(n)
  1086. else if move_related(n) then
  1087. freezeworklist:=freezeworklist+char(n)
  1088. else
  1089. simplifyworklist:=simplifyworklist+char(n);
  1090. end;
  1091. procedure Trgobj.prepare_colouring;
  1092. begin
  1093. make_work_list;
  1094. active_moves:=Tlinkedlist.create;
  1095. frozen_moves:=Tlinkedlist.create;
  1096. coalesced_moves:=Tlinkedlist.create;
  1097. constrained_moves:=Tlinkedlist.create;
  1098. fillchar(alias,sizeof(alias),0);
  1099. coalescednodes:='';
  1100. selectstack:='';
  1101. end;
  1102. procedure Trgobj.enable_moves(n:Tsuperregister);
  1103. var m:Tlinkedlistitem;
  1104. i:cardinal;
  1105. begin
  1106. if movelist[n]<>nil then
  1107. for i:=0 to movelist[n]^.count-1 do
  1108. begin
  1109. m:=movelist[n]^.data[i];
  1110. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  1111. begin
  1112. if Tmoveins(m).moveset=ms_active_moves then
  1113. begin
  1114. {Move m from the set active_moves to the set worklist_moves.}
  1115. active_moves.remove(m);
  1116. Tmoveins(m).moveset:=ms_worklist_moves;
  1117. worklist_moves.concat(m);
  1118. end;
  1119. end;
  1120. end;
  1121. end;
  1122. procedure Trgobj.decrement_degree(m:Tsuperregister);
  1123. var adj:Pstring;
  1124. d:byte;
  1125. i,p:byte;
  1126. n:char;
  1127. begin
  1128. {$ifdef ALLOWDUPREG}
  1129. if m=RS_INVALID then
  1130. exit;
  1131. {$endif}
  1132. d:=degree[m];
  1133. if degree[m]>0 then
  1134. dec(degree[m]);
  1135. if d=cpu_registers then
  1136. begin
  1137. {Enable moves for m.}
  1138. enable_moves(m);
  1139. {Enable moves for adjacent.}
  1140. adj:=igraph.adjlist[m];
  1141. if adj<>nil then
  1142. for i:=1 to length(adj^) do
  1143. begin
  1144. n:=adj^[i];
  1145. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  1146. enable_moves(Tsuperregister(n));
  1147. end;
  1148. {Remove the node from the spillworklist.}
  1149. p:=pos(char(m),spillworklist);
  1150. if p=0 then
  1151. internalerror(200305301); {must be found}
  1152. if length(spillworklist)>1 then
  1153. spillworklist[p]:=spillworklist[length(spillworklist)];
  1154. dec(spillworklist[0]);
  1155. if move_related(m) then
  1156. freezeworklist:=freezeworklist+char(m)
  1157. else
  1158. simplifyworklist:=simplifyworklist+char(m);
  1159. end;
  1160. end;
  1161. procedure Trgobj.simplify;
  1162. var adj:Pstring;
  1163. i,min,p:byte;
  1164. m:char;
  1165. n:Tsuperregister;
  1166. begin
  1167. {We the element with the least interferences out of the
  1168. simplifyworklist.}
  1169. min:=$ff;
  1170. p:=1;
  1171. for i:=1 to length(simplifyworklist) do
  1172. begin
  1173. adj:=igraph.adjlist[Tsuperregister(simplifyworklist[i])];
  1174. if adj=nil then
  1175. begin
  1176. min:=0;
  1177. break; {We won't find smaller ones.}
  1178. end
  1179. else
  1180. if length(adj^)<min then
  1181. begin
  1182. min:=length(adj^);
  1183. if min=0 then
  1184. break; {We won't find smaller ones.}
  1185. p:=i;
  1186. end;
  1187. end;
  1188. n:=Tsuperregister(simplifyworklist[p]);
  1189. if length(simplifyworklist)>1 then
  1190. simplifyworklist[p]:=simplifyworklist[length(simplifyworklist)];
  1191. dec(simplifyworklist[0]);
  1192. {Push it on the selectstack.}
  1193. selectstack:=selectstack+char(n);
  1194. adj:=igraph.adjlist[n];
  1195. if adj<>nil then
  1196. for i:=1 to length(adj^) do
  1197. begin
  1198. m:=adj^[i];
  1199. if ((pos(m,selectstack) or pos(m,coalescednodes))=0) and
  1200. not (Tsuperregister(m) in [first_int_supreg..last_int_supreg]) then
  1201. decrement_degree(Tsuperregister(m));
  1202. end;
  1203. end;
  1204. function Trgobj.get_alias(n:Tsuperregister):Tsuperregister;
  1205. begin
  1206. while pos(char(n),coalescednodes)<>0 do
  1207. n:=alias[n];
  1208. get_alias:=n;
  1209. end;
  1210. procedure Trgobj.add_worklist(u:Tsuperregister);
  1211. var p:byte;
  1212. begin
  1213. if not(u in [first_int_supreg..last_int_supreg]) and
  1214. not move_related(u) and
  1215. (degree[u]<cpu_registers) then
  1216. begin
  1217. p:=pos(char(u),freezeworklist);
  1218. if p=0 then
  1219. internalerror(200308161); {must be found}
  1220. if length(freezeworklist)>1 then
  1221. freezeworklist[p]:=freezeworklist[length(freezeworklist)];
  1222. dec(freezeworklist[0]);
  1223. simplifyworklist:=simplifyworklist+char(u);
  1224. end;
  1225. end;
  1226. function Trgobj.adjacent_ok(u,v:Tsuperregister):boolean;
  1227. {Check wether u and v should be coalesced. u is precoloured.}
  1228. function ok(t,r:Tsuperregister):boolean;
  1229. begin
  1230. ok:=(degree[t]<cpu_registers) or
  1231. (t in [first_int_supreg..last_int_supreg]) or
  1232. (r in igraph.bitmap[t]);
  1233. end;
  1234. var adj:Pstring;
  1235. i:byte;
  1236. t:char;
  1237. begin
  1238. adjacent_ok:=true;
  1239. adj:=igraph.adjlist[v];
  1240. if adj<>nil then
  1241. for i:=1 to length(adj^) do
  1242. begin
  1243. t:=adj^[i];
  1244. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  1245. if not ok(Tsuperregister(t),u) then
  1246. begin
  1247. adjacent_ok:=false;
  1248. break;
  1249. end;
  1250. end;
  1251. end;
  1252. function Trgobj.conservative(u,v:Tsuperregister):boolean;
  1253. var adj:Pstring;
  1254. done:set of char; {To prevent that we count nodes twice.}
  1255. i,k:byte;
  1256. n:char;
  1257. begin
  1258. k:=0;
  1259. done:=[];
  1260. adj:=igraph.adjlist[u];
  1261. if adj<>nil then
  1262. for i:=1 to length(adj^) do
  1263. begin
  1264. n:=adj^[i];
  1265. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  1266. begin
  1267. include(done,n);
  1268. if degree[Tsuperregister(n)]>=cpu_registers then
  1269. inc(k);
  1270. end;
  1271. end;
  1272. adj:=igraph.adjlist[v];
  1273. if adj<>nil then
  1274. for i:=1 to length(adj^) do
  1275. begin
  1276. n:=adj^[i];
  1277. if ((pos(n,selectstack) or pos(n,coalescednodes))=0) and
  1278. not (n in done) and
  1279. (degree[Tsuperregister(n)]>=cpu_registers) then
  1280. inc(k);
  1281. end;
  1282. conservative:=(k<cpu_registers);
  1283. end;
  1284. procedure Trgobj.combine(u,v:Tsuperregister);
  1285. var add:boolean;
  1286. adj:Pstring;
  1287. i,p:byte;
  1288. n,o:cardinal;
  1289. t:char;
  1290. decrement:boolean;
  1291. begin
  1292. p:=pos(char(v),freezeworklist);
  1293. if p<>0 then
  1294. delete(freezeworklist,p,1)
  1295. else
  1296. delete(spillworklist,pos(char(v),spillworklist),1);
  1297. coalescednodes:=coalescednodes+char(v);
  1298. alias[v]:=u;
  1299. {Combine both movelists. Since the movelists are sets, only add
  1300. elements that are not already present.}
  1301. if assigned(movelist[v]) then
  1302. begin
  1303. for n:=0 to movelist[v]^.count-1 do
  1304. begin
  1305. add:=true;
  1306. for o:=0 to movelist[u]^.count-1 do
  1307. if movelist[u]^.data[o]=movelist[v]^.data[n] then
  1308. begin
  1309. add:=false;
  1310. break;
  1311. end;
  1312. if add then
  1313. add_to_movelist(u,movelist[v]^.data[n]);
  1314. end;
  1315. enable_moves(v);
  1316. end;
  1317. adj:=igraph.adjlist[v];
  1318. if adj<>nil then
  1319. for i:=1 to length(adj^) do
  1320. begin
  1321. t:=adj^[i];
  1322. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  1323. begin
  1324. decrement:=(Tsuperregister(t)<>u) and not(u in igraph.bitmap[Tsuperregister(t)]);
  1325. add_edge(Tsuperregister(t),u);
  1326. {Do not call decrement_degree because it might move nodes between
  1327. lists while the degree does not change (add_edge will increase it).
  1328. Instead, we will decrement manually. (Only if the degree has been
  1329. increased.)}
  1330. if decrement and not (Tsuperregister(t) in [first_int_supreg..last_int_supreg])
  1331. and (degree[Tsuperregister(t)]>0) then
  1332. dec(degree[Tsuperregister(t)]);
  1333. end;
  1334. end;
  1335. p:=pos(char(u),freezeworklist);
  1336. if (degree[u]>=cpu_registers) and (p<>0) then
  1337. begin
  1338. delete(freezeworklist,p,1);
  1339. spillworklist:=spillworklist+char(u);
  1340. end;
  1341. end;
  1342. procedure Trgobj.coalesce;
  1343. var m:Tmoveins;
  1344. x,y,u,v:Tsuperregister;
  1345. begin
  1346. m:=Tmoveins(worklist_moves.getfirst);
  1347. x:=get_alias(getsupreg(m.instruction.oper[0].reg));
  1348. y:=get_alias(getsupreg(m.instruction.oper[1].reg));
  1349. if y in [first_int_supreg..last_int_supreg] then
  1350. begin
  1351. u:=y;
  1352. v:=x;
  1353. end
  1354. else
  1355. begin
  1356. u:=x;
  1357. v:=y;
  1358. end;
  1359. if (u=v) then
  1360. begin
  1361. m.moveset:=ms_coalesced_moves; {Already coalesced.}
  1362. coalesced_moves.insert(m);
  1363. add_worklist(u);
  1364. end
  1365. {Do u and v interfere? In that case the move is constrained. Two
  1366. precoloured nodes interfere allways. If v is precoloured, by the above
  1367. code u is precoloured, thus interference...}
  1368. else if (v in [first_int_supreg..last_int_supreg]) or (u in igraph.bitmap[v]) then
  1369. begin
  1370. m.moveset:=ms_constrained_moves; {Cannot coalesce yet...}
  1371. constrained_moves.insert(m);
  1372. add_worklist(u);
  1373. add_worklist(v);
  1374. end
  1375. {Next test: is it possible and a good idea to coalesce??}
  1376. else if ((u in [first_int_supreg..last_int_supreg]) and adjacent_ok(u,v)) or
  1377. (not(u in [first_int_supreg..last_int_supreg]) and conservative(u,v)) then
  1378. begin
  1379. m.moveset:=ms_coalesced_moves; {Move coalesced!}
  1380. coalesced_moves.insert(m);
  1381. combine(u,v);
  1382. add_worklist(u);
  1383. end
  1384. else
  1385. begin
  1386. m.moveset:=ms_active_moves;
  1387. active_moves.insert(m);
  1388. end;
  1389. end;
  1390. procedure Trgobj.freeze_moves(u:Tsuperregister);
  1391. var i:cardinal;
  1392. m:Tlinkedlistitem;
  1393. v,x,y:Tsuperregister;
  1394. begin
  1395. if movelist[u]<>nil then
  1396. for i:=0 to movelist[u]^.count-1 do
  1397. begin
  1398. m:=movelist[u]^.data[i];
  1399. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  1400. begin
  1401. x:=getsupreg(Tmoveins(m).instruction.oper[0].reg);
  1402. y:=getsupreg(Tmoveins(m).instruction.oper[1].reg);
  1403. if get_alias(y)=get_alias(u) then
  1404. v:=get_alias(x)
  1405. else
  1406. v:=get_alias(y);
  1407. {Move m from active_moves/worklist_moves to frozen_moves.}
  1408. if Tmoveins(m).moveset=ms_active_moves then
  1409. active_moves.remove(m)
  1410. else
  1411. worklist_moves.remove(m);
  1412. Tmoveins(m).moveset:=ms_frozen_moves;
  1413. frozen_moves.insert(m);
  1414. if not(v in [first_int_supreg..last_int_supreg]) and
  1415. not(move_related(v)) and
  1416. (degree[v]<cpu_registers) then
  1417. begin
  1418. delete(freezeworklist,pos(char(v),freezeworklist),1);
  1419. simplifyworklist:=simplifyworklist+char(v);
  1420. end;
  1421. end;
  1422. end;
  1423. end;
  1424. procedure Trgobj.freeze;
  1425. var n:Tsuperregister;
  1426. begin
  1427. {We need to take a random element out of the freezeworklist. We take
  1428. the last element. Dirty code!}
  1429. n:=Tsuperregister(freezeworklist[byte(freezeworklist[0])]);
  1430. dec(freezeworklist[0]);
  1431. {Add it to the simplifyworklist.}
  1432. simplifyworklist:=simplifyworklist+char(n);
  1433. freeze_moves(n);
  1434. end;
  1435. procedure Trgobj.select_spill;
  1436. var
  1437. n : char;
  1438. begin
  1439. {This code is WAY too naive. We need not to select just a register, but
  1440. the register that is used the least...}
  1441. n:=spillworklist[byte(spillworklist[0])];
  1442. dec(spillworklist[0]);
  1443. simplifyworklist:=simplifyworklist+n;
  1444. freeze_moves(Tsuperregister(n));
  1445. end;
  1446. procedure Trgobj.assign_colours;
  1447. {Assign_colours assigns the actual colours to the registers.}
  1448. var adj:Pstring;
  1449. i,j,k:byte;
  1450. n,a,c:Tsuperregister;
  1451. adj_colours,colourednodes:set of Tsuperregister;
  1452. w:char;
  1453. begin
  1454. spillednodes:='';
  1455. {Reset colours}
  1456. for i:=0 to maxintreg do
  1457. colour[i]:=i;
  1458. {Colour the cpu registers...}
  1459. colourednodes:=[first_int_supreg..last_int_supreg];
  1460. {Now colour the imaginary registers on the select-stack.}
  1461. for i:=length(selectstack) downto 1 do
  1462. begin
  1463. n:=Tsuperregister(selectstack[i]);
  1464. {Create a list of colours that we cannot assign to n.}
  1465. adj_colours:=[];
  1466. adj:=igraph.adjlist[n];
  1467. if adj<>nil then
  1468. for j:=1 to length(adj^) do
  1469. begin
  1470. w:=adj^[j];
  1471. a:=get_alias(Tsuperregister(w));
  1472. if a in colourednodes then
  1473. include(adj_colours,colour[a]);
  1474. end;
  1475. include(adj_colours,RS_STACK_POINTER_REG);
  1476. {Assume a spill by default...}
  1477. spillednodes:=spillednodes+char(n);
  1478. {Search for a colour not in this list.}
  1479. for k:=1 to length(usable_registers) do
  1480. begin
  1481. c:=Tsuperregister(usable_registers[k]);
  1482. if not(c in adj_colours) then
  1483. begin
  1484. colour[n]:=c;
  1485. dec(spillednodes[0]); {Colour found: no spill.}
  1486. include(colourednodes,n);
  1487. if n in used_in_proc_int then
  1488. include(used_in_proc_int,c);
  1489. break;
  1490. end;
  1491. end;
  1492. end;
  1493. {Finally colour the nodes that were coalesced.}
  1494. for i:=1 to length(coalescednodes) do
  1495. begin
  1496. n:=Tsuperregister(coalescednodes[i]);
  1497. k:=get_alias(n);
  1498. colour[n]:=colour[k];
  1499. if n in used_in_proc_int then
  1500. include(used_in_proc_int,colour[k]);
  1501. end;
  1502. {$ifdef ra_debug}
  1503. if aktfilepos.line=-1 then
  1504. begin
  1505. writeln('colourlist ',length(freezeworklist));
  1506. for i:=0 to maxintreg do
  1507. writeln(i:4,' ',colour[i]:4)
  1508. end;
  1509. {$endif ra_debug}
  1510. end;
  1511. procedure Trgobj.colour_registers;
  1512. begin
  1513. repeat
  1514. if length(simplifyworklist)<>0 then
  1515. simplify
  1516. else if not(worklist_moves.empty) then
  1517. coalesce
  1518. else if length(freezeworklist)<>0 then
  1519. freeze
  1520. else if length(spillworklist)<>0 then
  1521. select_spill;
  1522. until (length(simplifyworklist)=0) and
  1523. worklist_moves.empty and
  1524. (length(freezeworklist)=0) and
  1525. (length(spillworklist)=0);
  1526. assign_colours;
  1527. end;
  1528. procedure Trgobj.epilogue_colouring;
  1529. {
  1530. procedure move_to_worklist_moves(list:Tlinkedlist);
  1531. var p:Tlinkedlistitem;
  1532. begin
  1533. p:=list.first;
  1534. while p<>nil do
  1535. begin
  1536. Tmoveins(p).moveset:=ms_worklist_moves;
  1537. p:=p.next;
  1538. end;
  1539. worklist_moves.concatlist(list);
  1540. end;
  1541. }
  1542. var i:Tsuperregister;
  1543. begin
  1544. worklist_moves.clear;
  1545. {$ifdef Principle_wrong_by_definition}
  1546. {Move everything back to worklist_moves.}
  1547. move_to_worklist_moves(active_moves);
  1548. move_to_worklist_moves(frozen_moves);
  1549. move_to_worklist_moves(coalesced_moves);
  1550. move_to_worklist_moves(constrained_moves);
  1551. {$endif Principle_wrong_by_definition}
  1552. active_moves.destroy;
  1553. active_moves:=nil;
  1554. frozen_moves.destroy;
  1555. frozen_moves:=nil;
  1556. coalesced_moves.destroy;
  1557. coalesced_moves:=nil;
  1558. constrained_moves.destroy;
  1559. constrained_moves:=nil;
  1560. for i:=0 to 255 do
  1561. if movelist[i]<>nil then
  1562. begin
  1563. dispose(movelist[i]);
  1564. movelist[i]:=0;
  1565. end;
  1566. end;
  1567. procedure Trgobj.clear_interferences(u:Tsuperregister);
  1568. {Remove node u from the interference graph and remove all collected
  1569. move instructions it is associated with.}
  1570. var i:byte;
  1571. j,k,count:cardinal;
  1572. v:Tsuperregister;
  1573. m,n:Tmoveins;
  1574. begin
  1575. if igraph.adjlist[u]<>nil then
  1576. begin
  1577. for i:=1 to length(igraph.adjlist[u]^) do
  1578. begin
  1579. v:=Tsuperregister(igraph.adjlist[u]^[i]);
  1580. {Remove (u,v) and (v,u) from bitmap.}
  1581. exclude(igraph.bitmap[u],v);
  1582. exclude(igraph.bitmap[v],u);
  1583. {Remove (v,u) from adjacency list.}
  1584. if igraph.adjlist[v]<>nil then
  1585. begin
  1586. delete(igraph.adjlist[v]^,pos(char(v),igraph.adjlist[v]^),1);
  1587. if length(igraph.adjlist[v]^)=0 then
  1588. begin
  1589. dispose(igraph.adjlist[v]);
  1590. igraph.adjlist[v]:=nil;
  1591. end;
  1592. end;
  1593. end;
  1594. {Remove ( u,* ) from adjacency list.}
  1595. dispose(igraph.adjlist[u]);
  1596. igraph.adjlist[u]:=nil;
  1597. end;
  1598. {$ifdef Principle_wrong_by_definition}
  1599. {Now remove the moves.}
  1600. if movelist[u]<>nil then
  1601. begin
  1602. for j:=0 to movelist[u]^.count-1 do
  1603. begin
  1604. m:=Tmoveins(movelist[u]^.data[j]);
  1605. {Get the other register of the move instruction.}
  1606. v:=m.instruction.oper[0].reg.number shr 8;
  1607. if v=u then
  1608. v:=m.instruction.oper[1].reg.number shr 8;
  1609. repeat
  1610. repeat
  1611. if (u<>v) and (movelist[v]<>nil) then
  1612. begin
  1613. {Remove the move from it's movelist.}
  1614. count:=movelist[v]^.count-1;
  1615. for k:=0 to count do
  1616. if m=movelist[v]^.data[k] then
  1617. begin
  1618. if k<>count then
  1619. movelist[v]^.data[k]:=movelist[v]^.data[count];
  1620. dec(movelist[v]^.count);
  1621. if count=0 then
  1622. begin
  1623. dispose(movelist[v]);
  1624. movelist[v]:=nil;
  1625. end;
  1626. break;
  1627. end;
  1628. end;
  1629. {The complexity is enourmous: the register might have been
  1630. coalesced. In that case it's movelists have been added to
  1631. it's coalescing alias. (DM)}
  1632. v:=alias[v];
  1633. until v=0;
  1634. {And also register u might have been coalesced.}
  1635. u:=alias[u];
  1636. until u=0;
  1637. case m.moveset of
  1638. ms_coalesced_moves:
  1639. coalesced_moves.remove(m);
  1640. ms_constrained_moves:
  1641. constrained_moves.remove(m);
  1642. ms_frozen_moves:
  1643. frozen_moves.remove(m);
  1644. ms_worklist_moves:
  1645. worklist_moves.remove(m);
  1646. ms_active_moves:
  1647. active_moves.remove(m);
  1648. end;
  1649. end;
  1650. dispose(movelist[u]);
  1651. movelist[u]:=nil;
  1652. end;
  1653. {$endif Principle_wrong_by_definition}
  1654. end;
  1655. procedure Trgobj.getregisterintinline(list:Taasmoutput;position:Tai;subreg:Tsubregister;var result:Tregister);
  1656. var min,p,i:Tsuperregister;
  1657. r:Tregister;
  1658. adj:Pstring;
  1659. begin
  1660. if maxintreg<last_int_imreg then
  1661. begin
  1662. inc(maxintreg);
  1663. p:=maxintreg;
  1664. min:=0;
  1665. end
  1666. else
  1667. begin
  1668. min:=$ff;
  1669. p:=first_int_imreg;
  1670. for i:=first_int_imreg to maxintreg do
  1671. if (i in unusedregsint) and
  1672. (pos(char(i),abtlist)=0) and
  1673. (pos(char(i),spillednodes)=0) then
  1674. begin
  1675. adj:=igraph.adjlist[Tsuperregister(i)];
  1676. if adj=nil then
  1677. begin
  1678. p:=i;
  1679. min:=0;
  1680. break; {We won't find smaller ones.}
  1681. end
  1682. else
  1683. if length(adj^)<min then
  1684. begin
  1685. p:=i;
  1686. min:=length(adj^);
  1687. if min=0 then
  1688. break; {We won't find smaller ones.}
  1689. end;
  1690. end;
  1691. if min=$ff then
  1692. begin
  1693. {$ifdef ALLOWDUPREG}
  1694. result:=newreg(R_INTREGISTER,RS_INVALID,subreg);
  1695. exit;
  1696. {$else}
  1697. internalerror(10);
  1698. {$endif}
  1699. end;
  1700. end;
  1701. {$ifdef ra_debug}
  1702. writeln('Spilling temp: ',p,' min ',min);
  1703. {$endif ra_debug}
  1704. exclude(unusedregsint,p);
  1705. include(used_in_proc_int,p);
  1706. r:=newreg(R_INTREGISTER,p,subreg);
  1707. if position=nil then
  1708. list.insert(Tai_regalloc.alloc(r))
  1709. else
  1710. list.insertafter(Tai_regalloc.alloc(r),position);
  1711. add_edges_used(p);
  1712. add_constraints(r);
  1713. result:=r;
  1714. end;
  1715. {In some cases we can get in big trouble. See this example:
  1716. ; register reg23d released
  1717. ; register eax allocated
  1718. ; register ebx allocated
  1719. ; register ecx allocated
  1720. ; register edx allocated
  1721. ; register esi allocated
  1722. ; register edi allocated
  1723. call [reg23d]
  1724. This code is ok, *except* when reg23d is spilled. In that case the
  1725. spilled would introduce a help register which can never get
  1726. allocated to a real register because it interferes with all of them.
  1727. To solve this we introduce the ABT ("avoid big trouble :)" ) registers.
  1728. If you allocate an ABT register you get a register that has less
  1729. than cpu_register interferences and will not be allocated ever again
  1730. by the normal register get procedures. In other words it is for sure it
  1731. will never get spilled.}
  1732. function Trgobj.getabtregisterint(list:Taasmoutput;size:Tcgsize):Tregister;
  1733. var p,i:Tsuperregister;
  1734. r:Tregister;
  1735. subreg:tsubregister;
  1736. found:boolean;
  1737. min : byte;
  1738. adj:Pstring;
  1739. begin
  1740. min:=$ff;
  1741. for i:=1 to length(abtlist) do
  1742. if Tsuperregister(abtlist[i]) in unusedregsint then
  1743. begin
  1744. p:=tsuperregister(abtlist[i]);
  1745. min:=0;
  1746. break;
  1747. end;
  1748. if min>0 then
  1749. begin
  1750. if maxintreg<last_int_imreg then
  1751. begin
  1752. inc(maxintreg);
  1753. p:=maxintreg;
  1754. min:=0;
  1755. end
  1756. else
  1757. begin
  1758. p:=first_int_imreg;
  1759. for i:=first_int_imreg to maxintreg do
  1760. if (i in unusedregsint) and
  1761. ((igraph.adjlist[i]=nil) or
  1762. (length(igraph.adjlist[i]^)<cpu_registers)) then
  1763. begin
  1764. adj:=igraph.adjlist[i];
  1765. if adj=nil then
  1766. begin
  1767. p:=i;
  1768. min:=0;
  1769. break; {We won't find smaller ones.}
  1770. end
  1771. else
  1772. if length(adj^)<min then
  1773. begin
  1774. p:=i;
  1775. min:=length(adj^);
  1776. if min=0 then
  1777. break; {We won't find smaller ones.}
  1778. end;
  1779. end;
  1780. end;
  1781. if min=$ff then
  1782. begin
  1783. {$ifdef ALLOWDUPREG}
  1784. result:=newreg(R_INTREGISTER,RS_INVALID,cgsize2subreg(size));
  1785. exit;
  1786. {$else}
  1787. internalerror(10);
  1788. {$endif}
  1789. end;
  1790. end;
  1791. exclude(unusedregsint,p);
  1792. include(used_in_proc_int,p);
  1793. subreg:=cgsize2subreg(size);
  1794. r:=newreg(R_INTREGISTER,p,subreg);
  1795. list.concat(Tai_regalloc.alloc(r));
  1796. getabtregisterint:=r;
  1797. add_edges_used(p);
  1798. add_constraints(r);
  1799. if pos(char(p),abtlist)=0 then
  1800. abtlist:=abtlist+char(p);
  1801. end;
  1802. procedure Trgobj.ungetregisterintinline(list:Taasmoutput;position:Tai;r:Tregister);
  1803. var supreg:Tsuperregister;
  1804. begin
  1805. supreg:=getsupreg(r);
  1806. include(unusedregsint,supreg);
  1807. if position=nil then
  1808. list.insert(Tai_regalloc.dealloc(r))
  1809. else
  1810. list.insertafter(Tai_regalloc.dealloc(r),position);
  1811. add_edges_used(supreg);
  1812. add_constraints(r);
  1813. end;
  1814. function Trgobj.spill_registers(list:Taasmoutput;headertai:tai;const regs_to_spill:string):boolean;
  1815. {Returns true if any help registers have been used.}
  1816. var i:byte;
  1817. p,q:Tai;
  1818. regs_to_spill_set:Tsuperregisterset;
  1819. spill_temps:^Tspill_temp_list;
  1820. templist : taasmoutput;
  1821. supreg : tsuperregister;
  1822. begin
  1823. aktfilepos:=current_procinfo.entrypos;
  1824. spill_registers:=false;
  1825. unusedregsint:=[0..255];
  1826. fillchar(degree,sizeof(degree),0);
  1827. {Precoloured nodes should have an infinite degree, which we can approach
  1828. by 255.}
  1829. for i:=first_int_supreg to last_int_supreg do
  1830. degree[i]:=255;
  1831. { exclude(unusedregsint,RS_STACK_POINTER_REG);}
  1832. if current_procinfo.framepointer=NR_FRAME_POINTER_REG then
  1833. {Make sure the register allocator won't allocate registers into ebp.}
  1834. exclude(unusedregsint,RS_FRAME_POINTER_REG);
  1835. new(spill_temps);
  1836. fillchar(spill_temps^,sizeof(spill_temps^),0);
  1837. regs_to_spill_set:=[];
  1838. { Allocate temps and insert in front of the list }
  1839. templist:=taasmoutput.create;
  1840. for i:=1 to length(regs_to_spill) do
  1841. begin
  1842. {Alternative representation.}
  1843. include(regs_to_spill_set,Tsuperregister(regs_to_spill[i]));
  1844. {Clear all interferences of the spilled register.}
  1845. clear_interferences(Tsuperregister(regs_to_spill[i]));
  1846. {Get a temp for the spilled register}
  1847. tg.gettemp(templist,4,tt_noreuse,spill_temps^[Tsuperregister(regs_to_spill[i])]);
  1848. end;
  1849. list.insertlistafter(headertai,templist);
  1850. templist.free;
  1851. { Walk through all instructions, we can start with the headertai,
  1852. because before the header tai is only symbols }
  1853. p:=headertai;
  1854. while assigned(p) do
  1855. begin
  1856. case p.typ of
  1857. ait_regalloc:
  1858. begin
  1859. {A register allocation of a spilled register can be removed.}
  1860. supreg:=getsupreg(Tai_regalloc(p).reg);
  1861. if supreg in regs_to_spill_set then
  1862. begin
  1863. q:=p;
  1864. p:=Tai(p.next);
  1865. list.remove(q);
  1866. continue;
  1867. end
  1868. else
  1869. if Tai_regalloc(p).allocation then
  1870. exclude(unusedregsint,supreg)
  1871. else
  1872. include(unusedregsint,supreg);
  1873. end;
  1874. ait_instruction:
  1875. begin
  1876. aktfilepos:=Taicpu_abstract(p).fileinfo
  1877. ;
  1878. if Taicpu_abstract(p).spill_registers(list,@getregisterintinline,
  1879. @ungetregisterintinline,
  1880. regs_to_spill_set,
  1881. unusedregsint,
  1882. spill_temps^) then
  1883. spill_registers:=true;
  1884. if Taicpu_abstract(p).is_move then
  1885. add_move_instruction(Taicpu(p));
  1886. end;
  1887. end;
  1888. p:=Tai(p.next);
  1889. end;
  1890. aktfilepos:=current_procinfo.exitpos;
  1891. for i:=1 to length(regs_to_spill) do
  1892. begin
  1893. tg.ungettemp(list,spill_temps^[Tsuperregister(regs_to_spill[i])]);
  1894. end;
  1895. dispose(spill_temps);
  1896. end;
  1897. {****************************************************************************
  1898. TReference
  1899. ****************************************************************************}
  1900. procedure reference_reset(var ref : treference);
  1901. begin
  1902. FillChar(ref,sizeof(treference),0);
  1903. {$ifdef arm}
  1904. ref.signindex:=1;
  1905. {$endif arm}
  1906. end;
  1907. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  1908. begin
  1909. reference_reset(ref);
  1910. ref.base:=base;
  1911. ref.offset:=offset;
  1912. end;
  1913. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  1914. begin
  1915. reference_reset(ref);
  1916. ref.symbol:=sym;
  1917. ref.offset:=offset;
  1918. end;
  1919. procedure reference_release(list: taasmoutput; const ref : treference);
  1920. begin
  1921. rg.ungetreference(list,ref);
  1922. end;
  1923. function references_equal(sref : treference;dref : treference):boolean;
  1924. begin
  1925. references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
  1926. end;
  1927. { on most processors , this routine does nothing, overriden currently }
  1928. { only by 80x86 processor. }
  1929. function trgobj.makeregsize(reg: tregister; size: tcgsize): tregister;
  1930. begin
  1931. makeregsize := reg;
  1932. end;
  1933. {****************************************************************************
  1934. TLocation
  1935. ****************************************************************************}
  1936. procedure location_reset(var l : tlocation;lt:TCGLoc;lsize:TCGSize);
  1937. begin
  1938. FillChar(l,sizeof(tlocation),0);
  1939. l.loc:=lt;
  1940. l.size:=lsize;
  1941. {$ifdef arm}
  1942. if l.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  1943. l.reference.signindex:=1;
  1944. {$endif arm}
  1945. end;
  1946. procedure location_release(list: taasmoutput; const l : tlocation);
  1947. begin
  1948. case l.loc of
  1949. LOC_REGISTER,LOC_CREGISTER :
  1950. begin
  1951. rg.ungetregisterint(list,l.register);
  1952. if l.size in [OS_64,OS_S64] then
  1953. rg.ungetregisterint(list,l.registerhigh);
  1954. end;
  1955. LOC_FPUREGISTER,LOC_CFPUREGISTER :
  1956. rg.ungetregisterfpu(list,l.register,l.size);
  1957. LOC_CREFERENCE,LOC_REFERENCE :
  1958. rg.ungetreference(list, l.reference);
  1959. end;
  1960. end;
  1961. procedure location_freetemp(list:taasmoutput; const l : tlocation);
  1962. begin
  1963. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1964. tg.ungetiftemp(list,l.reference);
  1965. end;
  1966. procedure location_copy(var destloc:tlocation; const sourceloc : tlocation);
  1967. begin
  1968. destloc:=sourceloc;
  1969. end;
  1970. procedure location_swap(var destloc,sourceloc : tlocation);
  1971. var
  1972. swapl : tlocation;
  1973. begin
  1974. swapl := destloc;
  1975. destloc := sourceloc;
  1976. sourceloc := swapl;
  1977. end;
  1978. end.
  1979. {
  1980. $Log$
  1981. Revision 1.80 2003-09-30 19:54:42 peter
  1982. * reuse registers with the least conflicts
  1983. Revision 1.79 2003/09/29 20:58:56 peter
  1984. * optimized releasing of registers
  1985. Revision 1.78 2003/09/28 13:41:12 peter
  1986. * return reg 255 when allowdupreg is defined
  1987. Revision 1.77 2003/09/25 16:19:32 peter
  1988. * fix filepositions
  1989. * insert spill temp allocations at the start of the proc
  1990. Revision 1.76 2003/09/16 16:17:01 peter
  1991. * varspez in calls to push_addr_param
  1992. Revision 1.75 2003/09/12 19:07:42 daniel
  1993. * Fixed fast spilling functionality by re-adding the code that initializes
  1994. precoloured nodes to degree 255. I would like to play hangman on the one
  1995. who removed that code.
  1996. Revision 1.74 2003/09/11 11:54:59 florian
  1997. * improved arm code generation
  1998. * move some protected and private field around
  1999. * the temp. register for register parameters/arguments are now released
  2000. before the move to the parameter register is done. This improves
  2001. the code in a lot of cases.
  2002. Revision 1.73 2003/09/09 20:59:27 daniel
  2003. * Adding register allocation order
  2004. Revision 1.72 2003/09/09 15:55:44 peter
  2005. * use register with least interferences in spillregister
  2006. Revision 1.71 2003/09/07 22:09:35 peter
  2007. * preparations for different default calling conventions
  2008. * various RA fixes
  2009. Revision 1.70 2003/09/03 21:06:45 peter
  2010. * fixes for FPU register allocation
  2011. Revision 1.69 2003/09/03 15:55:01 peter
  2012. * NEWRA branch merged
  2013. Revision 1.68 2003/09/03 11:18:37 florian
  2014. * fixed arm concatcopy
  2015. + arm support in the common compiler sources added
  2016. * moved some generic cg code around
  2017. + tfputype added
  2018. * ...
  2019. Revision 1.67.2.5 2003/08/31 20:44:07 peter
  2020. * fixed getexplicitregisterint tregister value
  2021. Revision 1.67.2.4 2003/08/31 20:40:50 daniel
  2022. * Fixed add_edges_used
  2023. Revision 1.67.2.3 2003/08/29 17:28:59 peter
  2024. * next batch of updates
  2025. Revision 1.67.2.2 2003/08/28 18:35:08 peter
  2026. * tregister changed to cardinal
  2027. Revision 1.67.2.1 2003/08/27 19:55:54 peter
  2028. * first tregister patch
  2029. Revision 1.67 2003/08/23 10:46:21 daniel
  2030. * Register allocator bugfix for h2pas
  2031. Revision 1.66 2003/08/17 16:59:20 jonas
  2032. * fixed regvars so they work with newra (at least for ppc)
  2033. * fixed some volatile register bugs
  2034. + -dnotranslation option for -dnewra, which causes the registers not to
  2035. be translated from virtual to normal registers. Requires support in
  2036. the assembler writer as well, which is only implemented in aggas/
  2037. agppcgas currently
  2038. Revision 1.65 2003/08/17 14:32:48 daniel
  2039. * Precoloured nodes now have an infinite degree approached with 255,
  2040. like they should.
  2041. Revision 1.64 2003/08/17 08:48:02 daniel
  2042. * Another register allocator bug fixed.
  2043. * cpu_registers set to 6 for i386
  2044. Revision 1.63 2003/08/09 18:56:54 daniel
  2045. * cs_regalloc renamed to cs_regvars to avoid confusion with register
  2046. allocator
  2047. * Some preventive changes to i386 spillinh code
  2048. Revision 1.62 2003/08/03 14:09:50 daniel
  2049. * Fixed a register allocator bug
  2050. * Figured out why -dnewra generates superfluous "mov reg1,reg2"
  2051. statements: changes in location_force. These moves are now no longer
  2052. constrained so they are optimized away.
  2053. Revision 1.61 2003/07/21 13:32:39 jonas
  2054. * add_edges_used() is now also called for registers allocated with
  2055. getexplicitregisterint()
  2056. * writing the intereference graph is now only done with -dradebug2 and
  2057. the created files are now called "igraph.<module_name>"
  2058. Revision 1.60 2003/07/06 15:31:21 daniel
  2059. * Fixed register allocator. *Lots* of fixes.
  2060. Revision 1.59 2003/07/06 15:00:47 jonas
  2061. * fixed my previous completely broken commit. It's not perfect though,
  2062. registers > last_int_supreg and < max_intreg may still be "translated"
  2063. Revision 1.58 2003/07/06 14:45:05 jonas
  2064. * support integer registers that are not managed by newra (ie. don't
  2065. translate register numbers that fall outside the range
  2066. first_int_supreg..last_int_supreg)
  2067. Revision 1.57 2003/07/02 22:18:04 peter
  2068. * paraloc splitted in callerparaloc,calleeparaloc
  2069. * sparc calling convention updates
  2070. Revision 1.56 2003/06/17 16:34:44 jonas
  2071. * lots of newra fixes (need getfuncretparaloc implementation for i386)!
  2072. * renamed all_intregisters to volatile_intregisters and made it
  2073. processor dependent
  2074. Revision 1.55 2003/06/14 14:53:50 jonas
  2075. * fixed newra cycle for x86
  2076. * added constants for indicating source and destination operands of the
  2077. "move reg,reg" instruction to aasmcpu (and use those in rgobj)
  2078. Revision 1.54 2003/06/13 21:19:31 peter
  2079. * current_procdef removed, use current_procinfo.procdef instead
  2080. Revision 1.53 2003/06/12 21:11:10 peter
  2081. * ungetregisterfpu gets size parameter
  2082. Revision 1.52 2003/06/12 16:43:07 peter
  2083. * newra compiles for sparc
  2084. Revision 1.51 2003/06/09 14:54:26 jonas
  2085. * (de)allocation of registers for parameters is now performed properly
  2086. (and checked on the ppc)
  2087. - removed obsolete allocation of all parameter registers at the start
  2088. of a procedure (and deallocation at the end)
  2089. Revision 1.50 2003/06/03 21:11:09 peter
  2090. * cg.a_load_* get a from and to size specifier
  2091. * makeregsize only accepts newregister
  2092. * i386 uses generic tcgnotnode,tcgunaryminus
  2093. Revision 1.49 2003/06/03 13:01:59 daniel
  2094. * Register allocator finished
  2095. Revision 1.48 2003/06/01 21:38:06 peter
  2096. * getregisterfpu size parameter added
  2097. * op_const_reg size parameter added
  2098. * sparc updates
  2099. Revision 1.47 2003/05/31 20:31:11 jonas
  2100. * set inital costs of assigning a variable to a register to 120 for
  2101. non-i386, because the used register must be store to memory at the
  2102. start and loaded again at the end
  2103. Revision 1.46 2003/05/30 18:55:21 jonas
  2104. * fixed several regvar related bugs for non-i386. make cycle with -Or now
  2105. works for ppc
  2106. Revision 1.45 2003/05/30 12:36:13 jonas
  2107. * use as little different registers on the ppc until newra is released,
  2108. since every used register must be saved
  2109. Revision 1.44 2003/05/17 13:30:08 jonas
  2110. * changed tt_persistant to tt_persistent :)
  2111. * tempcreatenode now doesn't accept a boolean anymore for persistent
  2112. temps, but a ttemptype, so you can also create ansistring temps etc
  2113. Revision 1.43 2003/05/16 14:33:31 peter
  2114. * regvar fixes
  2115. Revision 1.42 2003/04/26 20:03:49 daniel
  2116. * Bug fix in simplify
  2117. Revision 1.41 2003/04/25 20:59:35 peter
  2118. * removed funcretn,funcretsym, function result is now in varsym
  2119. and aliases for result and function name are added using absolutesym
  2120. * vs_hidden parameter for funcret passed in parameter
  2121. * vs_hidden fixes
  2122. * writenode changed to printnode and released from extdebug
  2123. * -vp option added to generate a tree.log with the nodetree
  2124. * nicer printnode for statements, callnode
  2125. Revision 1.40 2003/04/25 08:25:26 daniel
  2126. * Ifdefs around a lot of calls to cleartempgen
  2127. * Fixed registers that are allocated but not freed in several nodes
  2128. * Tweak to register allocator to cause less spills
  2129. * 8-bit registers now interfere with esi,edi and ebp
  2130. Compiler can now compile rtl successfully when using new register
  2131. allocator
  2132. Revision 1.39 2003/04/23 20:23:06 peter
  2133. * compile fix for no-newra
  2134. Revision 1.38 2003/04/23 14:42:07 daniel
  2135. * Further register allocator work. Compiler now smaller with new
  2136. allocator than without.
  2137. * Somebody forgot to adjust ppu version number
  2138. Revision 1.37 2003/04/22 23:50:23 peter
  2139. * firstpass uses expectloc
  2140. * checks if there are differences between the expectloc and
  2141. location.loc from secondpass in EXTDEBUG
  2142. Revision 1.36 2003/04/22 10:09:35 daniel
  2143. + Implemented the actual register allocator
  2144. + Scratch registers unavailable when new register allocator used
  2145. + maybe_save/maybe_restore unavailable when new register allocator used
  2146. Revision 1.35 2003/04/21 19:16:49 peter
  2147. * count address regs separate
  2148. Revision 1.34 2003/04/17 16:48:21 daniel
  2149. * Added some code to keep track of move instructions in register
  2150. allocator
  2151. Revision 1.33 2003/04/17 07:50:24 daniel
  2152. * Some work on interference graph construction
  2153. Revision 1.32 2003/03/28 19:16:57 peter
  2154. * generic constructor working for i386
  2155. * remove fixed self register
  2156. * esi added as address register for i386
  2157. Revision 1.31 2003/03/11 21:46:24 jonas
  2158. * lots of new regallocator fixes, both in generic and ppc-specific code
  2159. (ppc compiler still can't compile the linux system unit though)
  2160. Revision 1.30 2003/03/09 21:18:59 olle
  2161. + added cutils to the uses clause
  2162. Revision 1.29 2003/03/08 20:36:41 daniel
  2163. + Added newra version of Ti386shlshrnode
  2164. + Added interference graph construction code
  2165. Revision 1.28 2003/03/08 13:59:16 daniel
  2166. * Work to handle new register notation in ag386nsm
  2167. + Added newra version of Ti386moddivnode
  2168. Revision 1.27 2003/03/08 10:53:48 daniel
  2169. * Created newra version of secondmul in n386add.pas
  2170. Revision 1.26 2003/03/08 08:59:07 daniel
  2171. + $define newra will enable new register allocator
  2172. + getregisterint will return imaginary registers with $newra
  2173. + -sr switch added, will skip register allocation so you can see
  2174. the direct output of the code generator before register allocation
  2175. Revision 1.25 2003/02/26 20:50:45 daniel
  2176. * Fixed ungetreference
  2177. Revision 1.24 2003/02/19 22:39:56 daniel
  2178. * Fixed a few issues
  2179. Revision 1.23 2003/02/19 22:00:14 daniel
  2180. * Code generator converted to new register notation
  2181. - Horribily outdated todo.txt removed
  2182. Revision 1.22 2003/02/02 19:25:54 carl
  2183. * Several bugfixes for m68k target (register alloc., opcode emission)
  2184. + VIS target
  2185. + Generic add more complete (still not verified)
  2186. Revision 1.21 2003/01/08 18:43:57 daniel
  2187. * Tregister changed into a record
  2188. Revision 1.20 2002/10/05 12:43:28 carl
  2189. * fixes for Delphi 6 compilation
  2190. (warning : Some features do not work under Delphi)
  2191. Revision 1.19 2002/08/23 16:14:49 peter
  2192. * tempgen cleanup
  2193. * tt_noreuse temp type added that will be used in genentrycode
  2194. Revision 1.18 2002/08/17 22:09:47 florian
  2195. * result type handling in tcgcal.pass_2 overhauled
  2196. * better tnode.dowrite
  2197. * some ppc stuff fixed
  2198. Revision 1.17 2002/08/17 09:23:42 florian
  2199. * first part of procinfo rewrite
  2200. Revision 1.16 2002/08/06 20:55:23 florian
  2201. * first part of ppc calling conventions fix
  2202. Revision 1.15 2002/08/05 18:27:48 carl
  2203. + more more more documentation
  2204. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  2205. Revision 1.14 2002/08/04 19:06:41 carl
  2206. + added generic exception support (still does not work!)
  2207. + more documentation
  2208. Revision 1.13 2002/07/07 09:52:32 florian
  2209. * powerpc target fixed, very simple units can be compiled
  2210. * some basic stuff for better callparanode handling, far from being finished
  2211. Revision 1.12 2002/07/01 18:46:26 peter
  2212. * internal linker
  2213. * reorganized aasm layer
  2214. Revision 1.11 2002/05/18 13:34:17 peter
  2215. * readded missing revisions
  2216. Revision 1.10 2002/05/16 19:46:44 carl
  2217. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  2218. + try to fix temp allocation (still in ifdef)
  2219. + generic constructor calls
  2220. + start of tassembler / tmodulebase class cleanup
  2221. Revision 1.8 2002/04/21 15:23:03 carl
  2222. + makeregsize
  2223. + changeregsize is now a local routine
  2224. Revision 1.7 2002/04/20 21:32:25 carl
  2225. + generic FPC_CHECKPOINTER
  2226. + first parameter offset in stack now portable
  2227. * rename some constants
  2228. + move some cpu stuff to other units
  2229. - remove unused constents
  2230. * fix stacksize for some targets
  2231. * fix generic size problems which depend now on EXTEND_SIZE constant
  2232. Revision 1.6 2002/04/15 19:03:31 carl
  2233. + reg2str -> std_reg2str()
  2234. Revision 1.5 2002/04/06 18:13:01 jonas
  2235. * several powerpc-related additions and fixes
  2236. Revision 1.4 2002/04/04 19:06:04 peter
  2237. * removed unused units
  2238. * use tlocation.size in cg.a_*loc*() routines
  2239. Revision 1.3 2002/04/02 17:11:29 peter
  2240. * tlocation,treference update
  2241. * LOC_CONSTANT added for better constant handling
  2242. * secondadd splitted in multiple routines
  2243. * location_force_reg added for loading a location to a register
  2244. of a specified size
  2245. * secondassignment parses now first the right and then the left node
  2246. (this is compatible with Kylix). This saves a lot of push/pop especially
  2247. with string operations
  2248. * adapted some routines to use the new cg methods
  2249. Revision 1.2 2002/04/01 19:24:25 jonas
  2250. * fixed different parameter name in interface and implementation
  2251. declaration of a method (only 1.0.x detected this)
  2252. Revision 1.1 2002/03/31 20:26:36 jonas
  2253. + a_loadfpu_* and a_loadmm_* methods in tcg
  2254. * register allocation is now handled by a class and is mostly processor
  2255. independent (+rgobj.pas and i386/rgcpu.pas)
  2256. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  2257. * some small improvements and fixes to the optimizer
  2258. * some register allocation fixes
  2259. * some fpuvaroffset fixes in the unary minus node
  2260. * push/popusedregisters is now called rg.save/restoreusedregisters and
  2261. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  2262. also better optimizable)
  2263. * fixed and optimized register saving/restoring for new/dispose nodes
  2264. * LOC_FPU locations now also require their "register" field to be set to
  2265. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  2266. - list field removed of the tnode class because it's not used currently
  2267. and can cause hard-to-find bugs
  2268. }