rgobj.pas 85 KB

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