rgobj.pas 85 KB

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