rgobj.pas 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138
  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. {# @abstract(Abstract register allocator unit)
  20. This unit contains services to allocate, free
  21. references and registers which are used by
  22. the code generator.
  23. }
  24. {*******************************************************************************
  25. (applies to new register allocator)
  26. Register allocator introduction.
  27. Free Pascal uses a Chaitin style register allocator similair to the one
  28. described in the book "Modern compiler implementation in C" by Andrew W. Appel.,
  29. published by Cambridge University Press.
  30. Reading this book is recommended for a complete understanding. Here is a small
  31. introduction.
  32. The code generator thinks it has an infinite amount of registers. Our processorhas a limited amount of registers. Therefore we must reduce the amount of
  33. registers until there are less enough to fit into the processors registers.
  34. Registers can interfere or not interfere. If two imaginary registers interfere
  35. they cannot be placed into the same psysical register. Reduction of registers
  36. is done by:
  37. - "coalescing" Two registers that do not interfere are combined
  38. into one register.
  39. - "spilling" A register is changed into a memory location and the generated
  40. code is modified to use the memory location instead of the register.
  41. Register allocation is a graph colouring problem. Each register is a colour, and
  42. if two registers interfere there is a connection between them in the graph.
  43. In addition to the imaginary registers in the code generator, the psysical
  44. CPU registers are also present in this graph. This allows us to make
  45. interferences between imaginary registers and cpu registers. This is very
  46. usefull for describing archtectural constraints, like for example that
  47. the div instruction modifies edx, so variables that are in use at that time
  48. cannot be stored into edx. This can be modelled by making edx interfere
  49. with those variables.
  50. *******************************************************************************}
  51. unit rgobj;
  52. interface
  53. uses
  54. cutils, cpubase,
  55. cpuinfo,
  56. aasmbase,aasmtai,aasmcpu,
  57. cclasses,globtype,cginfo,cgbase,node
  58. {$ifdef delphi}
  59. ,dmisc
  60. {$endif}
  61. ;
  62. type
  63. regvar_longintarray = array[firstreg..lastreg] of longint;
  64. regvarint_longintarray = array[first_supreg..last_supreg] of longint;
  65. regvar_booleanarray = array[firstreg..lastreg] of boolean;
  66. regvar_ptreearray = array[firstreg..lastreg] of tnode;
  67. tpushedsavedloc = record
  68. case byte of
  69. 0: (pushed: boolean);
  70. 1: (ofs: longint);
  71. end;
  72. tpushedsaved = array[firstreg..lastreg] of tpushedsavedloc;
  73. Tpushedsavedint = array[first_supreg..last_supreg] of Tpushedsavedloc;
  74. Tinterferencebitmap=array[Tsuperregister] of set of Tsuperregister;
  75. Tinterferenceadjlist=array[Tsuperregister] of Pstring;
  76. Tinterferencegraph=record
  77. bitmap:Tinterferencebitmap;
  78. adjlist:Tinterferenceadjlist;
  79. end;
  80. Pinterferencegraph=^Tinterferencegraph;
  81. Tmovelist=record
  82. count:cardinal;
  83. data:array[0..$ffff] of Tlinkedlistitem;
  84. end;
  85. Pmovelist=^Tmovelist;
  86. {In the register allocator we keep track of move instructions.
  87. These instructions are moved between five linked lists. There
  88. is also a linked list per register to keep track about the moves
  89. it is associated with. Because we need to determine quickly in
  90. which of the five lists it is we add anu enumeradtion to each
  91. move instruction.}
  92. Tmoveset=(ms_coalesced_moves,ms_constrained_moves,ms_frozen_moves,
  93. ms_worklist_moves,ms_active_moves);
  94. Tmoveins=class(Tlinkedlistitem)
  95. moveset:Tmoveset;
  96. instruction:Taicpu;
  97. end;
  98. {#
  99. This class implements the abstract register allocator
  100. It is used by the code generator to allocate and free
  101. registers which might be valid across nodes. It also
  102. contains utility routines related to registers.
  103. Some of the methods in this class should be overriden
  104. by cpu-specific implementations.
  105. }
  106. trgobj = class
  107. { The "usableregsxxx" contain all registers of type "xxx" that }
  108. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  109. { contain all registers of type "xxx" that aren't currenly }
  110. { allocated }
  111. lastintreg,maxintreg:Tsuperregister;
  112. unusedregsint,usableregsint:Tsupregset;
  113. unusedregsaddr,usableregsaddr:Tsupregset;
  114. unusedregsfpu,usableregsfpu : tregisterset;
  115. unusedregsmm,usableregsmm : tregisterset;
  116. { these counters contain the number of elements in the }
  117. { unusedregsxxx/usableregsxxx sets }
  118. countunusedregsint,
  119. countunusedregsaddr,
  120. countunusedregsfpu,
  121. countunusedregsmm : byte;
  122. countusableregsint,
  123. countusableregsaddr,
  124. countusableregsfpu,
  125. countusableregsmm : byte;
  126. { Contains the registers which are really used by the proc itself.
  127. It doesn't take care of registers used by called procedures
  128. }
  129. usedbyproc,
  130. usedinproc : tregisterset;
  131. usedintbyproc,
  132. usedaddrbyproc,
  133. usedintinproc,
  134. usedaddrinproc:Tsupregset;
  135. reg_pushes : regvar_longintarray;
  136. reg_pushes_int : regvarint_longintarray;
  137. is_reg_var : regvar_booleanarray;
  138. is_reg_var_int:Tsupregset;
  139. regvar_loaded: regvar_booleanarray;
  140. regvar_loaded_int: Tsupregset;
  141. {$ifdef newra}
  142. colour:array[Tsuperregister] of Tsuperregister;
  143. spillednodes:string;
  144. {$endif}
  145. { tries to hold the amount of times which the current tree is processed }
  146. t_times: longint;
  147. constructor create(Acpu_registers:byte);
  148. {# Allocate a general purpose register
  149. An internalerror will be generated if there
  150. is no more free registers which can be allocated
  151. }
  152. function getregisterint(list:Taasmoutput;size:Tcgsize):Tregister;virtual;
  153. {# Free a general purpose register
  154. @param(r register to free)
  155. }
  156. procedure ungetregisterint(list: taasmoutput; r : tregister); virtual;
  157. {# Allocate a floating point register
  158. An internalerror will be generated if there
  159. is no more free registers which can be allocated
  160. }
  161. function getregisterfpu(list: taasmoutput) : tregister; virtual;
  162. {# Free a floating point register
  163. @param(r register to free)
  164. }
  165. procedure ungetregisterfpu(list: taasmoutput; r : tregister); virtual;
  166. function getregistermm(list: taasmoutput) : tregister; virtual;
  167. procedure ungetregistermm(list: taasmoutput; r : tregister); virtual;
  168. {# Allocate an address register.
  169. Address registers are the only registers which can
  170. be used as a base register in references (treference).
  171. On most cpu's this is the same as a general purpose
  172. register.
  173. An internalerror will be generated if there
  174. is no more free registers which can be allocated
  175. }
  176. function getaddressregister(list:Taasmoutput):Tregister;virtual;
  177. procedure ungetaddressregister(list: taasmoutput; r: tregister); virtual;
  178. {# Verify if the specified register is an address or
  179. general purpose register. Returns TRUE if @var(reg)
  180. is an adress register.
  181. This routine should only be used to check on
  182. general purpose or address register. It will
  183. not work on multimedia or floating point
  184. registers
  185. @param(reg register to verify)
  186. }
  187. function isaddressregister(reg: tregister): boolean; virtual;
  188. {# Tries to allocate the passed register, if possible
  189. @param(r specific register to allocate)
  190. }
  191. function getexplicitregisterint(list:Taasmoutput;r:Tnewregister):Tregister;virtual;
  192. {# Tries to allocate the passed fpu register, if possible
  193. @param(r specific register to allocate)
  194. }
  195. function getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  196. {# Deallocate any kind of register }
  197. procedure ungetregister(list: taasmoutput; r : tregister); virtual;
  198. {# Deallocate all registers which are allocated
  199. in the specified reference. On most systems,
  200. this will free the base and index registers
  201. of the specified reference.
  202. @param(ref reference which must have its registers freed)
  203. }
  204. procedure ungetreference(list: taasmoutput; const ref : treference); virtual;
  205. {# Reset the register allocator information (usable registers etc).
  206. Please note that it is mortal sins to call cleartempgen during
  207. graph colouring (that is between prepare_colouring and
  208. epilogue_colouring).
  209. }
  210. procedure cleartempgen;virtual;
  211. {# Convert a register to a specified register size, and return that register size }
  212. function makeregsize(reg: tregister; size: tcgsize): tregister; virtual;
  213. {# saves register variables (restoring happens automatically) }
  214. procedure saveintregvars(list:Taasmoutput;const s:Tsupregset);
  215. procedure saveotherregvars(list:Taasmoutput;const s:Tregisterset);
  216. {# Saves in temporary references (allocated via the temp. allocator)
  217. the registers defined in @var(s). The registers are only saved
  218. if they are currently in use, otherwise they are left as is.
  219. On processors which have instructions which manipulate the stack,
  220. this routine should be overriden for performance reasons.
  221. @param(list) List to add the instruction to
  222. @param(saved) Array of saved register information
  223. @param(s) Registers which might require saving
  224. }
  225. procedure saveusedintregisters(list:Taasmoutput;
  226. var saved:Tpushedsavedint;
  227. const s:Tsupregset);virtual;
  228. procedure saveusedotherregisters(list:Taasmoutput;
  229. var saved:Tpushedsaved;
  230. const s:Tregisterset);virtual;
  231. {# Restores the registers which were saved with a call
  232. to @var(saveusedregisters).
  233. On processors which have instructions which manipulate the stack,
  234. this routine should be overriden for performance reasons.
  235. }
  236. procedure restoreusedintregisters(list:Taasmoutput;
  237. const saved:Tpushedsavedint);virtual;
  238. procedure restoreusedotherregisters(list:Taasmoutput;
  239. const saved:Tpushedsaved);virtual;
  240. { used when deciding which registers to use for regvars }
  241. procedure incrementintregisterpushed(const s:Tsupregset);
  242. procedure incrementotherregisterpushed(const s: tregisterset);
  243. procedure clearregistercount;
  244. procedure resetusableregisters;virtual;
  245. procedure makeregvarint(reg:Tnewregister);
  246. procedure makeregvarother(reg:Tregister);
  247. procedure saveStateForInline(var state: pointer);virtual;
  248. procedure restoreStateAfterInline(var state: pointer);virtual;
  249. procedure saveUnusedState(var state: pointer);virtual;
  250. procedure restoreUnusedState(var state: pointer);virtual;
  251. {$ifdef newra}
  252. {$ifdef ra_debug}
  253. procedure writegraph;
  254. {$endif}
  255. procedure add_move_instruction(instr:Taicpu);
  256. procedure prepare_colouring;
  257. procedure epilogue_colouring;
  258. procedure colour_registers;
  259. {$endif newra}
  260. protected
  261. cpu_registers:byte;
  262. {$ifdef newra}
  263. igraph:Tinterferencegraph;
  264. degree:array[0..255] of byte;
  265. alias:array[Tsuperregister] of Tsuperregister;
  266. simplifyworklist,freezeworklist,spillworklist:string;
  267. coalescednodes:string;
  268. selectstack:string;
  269. movelist:array[Tsuperregister] of Pmovelist;
  270. worklist_moves,active_moves,frozen_moves,
  271. coalesced_moves,constrained_moves:Tlinkedlist;
  272. {$endif}
  273. { the following two contain the common (generic) code for all }
  274. { get- and ungetregisterxxx functions/procedures }
  275. function getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  276. var unusedregs:Tregisterset; var countunusedregs: byte): tregister;
  277. function getregistergenint(list:Taasmoutput;subreg:Tsubregister;
  278. const lowreg,highreg:Tsuperregister;
  279. var fusedinproc,fusedbyproc,unusedregs:Tsupregset;
  280. var countunusedregs:byte):Tregister;
  281. procedure ungetregistergen(list: taasmoutput; const r: tregister;
  282. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  283. procedure ungetregistergenint(list:taasmoutput;const r:Tregister;
  284. const usableregs:Tsupregset;
  285. var unusedregs:Tsupregset;
  286. var countunusedregs:byte);
  287. {$ifdef TEMPREGDEBUG}
  288. reg_user : regvar_ptreearray;
  289. reg_releaser : regvar_ptreearray;
  290. {$endif TEMPREGDEBUG}
  291. {$ifdef TEMPREGDEBUG}
  292. procedure testregisters;
  293. {$endif TEMPREGDEBUGx}
  294. {$ifdef newra}
  295. procedure add_edge(u,v:Tsuperregister);
  296. procedure add_edges_used(u:Tsuperregister);
  297. procedure add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  298. function move_related(n:Tsuperregister):boolean;
  299. procedure make_work_list;
  300. procedure enable_moves(n:Tsuperregister);
  301. procedure decrement_degree(m:Tsuperregister);
  302. procedure simplify;
  303. function get_alias(n:Tsuperregister):Tsuperregister;
  304. procedure add_worklist(u:Tsuperregister);
  305. function adjacent_ok(u,v:Tsuperregister):boolean;
  306. function conservative(u,v:Tsuperregister):boolean;
  307. procedure combine(u,v:Tsuperregister);
  308. procedure coalesce;
  309. procedure freeze_moves(u:Tsuperregister);
  310. procedure freeze;
  311. procedure select_spill;
  312. procedure assign_colours;
  313. {$endif}
  314. end;
  315. const
  316. {# This value is used in tsaved. If the array value is equal
  317. to this, then this means that this register is not used.
  318. }
  319. reg_not_saved = $7fffffff;
  320. var
  321. {# This is the class instance used to access the register allocator class }
  322. rg: trgobj;
  323. { trerefence handling }
  324. {# Clear to zero a treference }
  325. procedure reference_reset(var ref : treference);
  326. procedure reference_reset_old(var ref : treference);
  327. {# Clear to zero a treference, and set is base address
  328. to base register.
  329. }
  330. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  331. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  332. procedure reference_release(list: taasmoutput; const ref : treference);
  333. { This routine verifies if two references are the same, and
  334. if so, returns TRUE, otherwise returns false.
  335. }
  336. function references_equal(sref : treference;dref : treference) : boolean;
  337. { tlocation handling }
  338. procedure location_reset(var l : tlocation;lt:TCGLoc;lsize:TCGSize);
  339. procedure location_release(list: taasmoutput; const l : tlocation);
  340. procedure location_freetemp(list: taasmoutput; const l : tlocation);
  341. procedure location_copy(var destloc,sourceloc : tlocation);
  342. procedure location_swap(var destloc,sourceloc : tlocation);
  343. type
  344. psavedstate = ^tsavedstate;
  345. tsavedstate = record
  346. unusedregsint,usableregsint : Tsupregset;
  347. unusedregsaddr,usableregsaddr : Tsupregset;
  348. unusedregsfpu,usableregsfpu : tregisterset;
  349. unusedregsmm,usableregsmm : tregisterset;
  350. countunusedregsint,
  351. countunusedregsaddr,
  352. countunusedregsfpu,
  353. countunusedregsmm : byte;
  354. countusableregsint,
  355. countusableregsfpu,
  356. countusableregsmm : byte;
  357. { contains the registers which are really used by the proc itself }
  358. usedbyproc,
  359. usedinproc : tregisterset;
  360. reg_pushes : regvar_longintarray;
  361. is_reg_var : regvar_booleanarray;
  362. is_reg_var_int : Tsupregset;
  363. regvar_loaded: regvar_booleanarray;
  364. regvar_loaded_int: Tsupregset;
  365. {$ifdef TEMPREGDEBUG}
  366. reg_user : regvar_ptreearray;
  367. reg_releaser : regvar_ptreearray;
  368. {$endif TEMPREGDEBUG}
  369. end;
  370. punusedstate = ^tunusedstate;
  371. tunusedstate = record
  372. unusedregsint : Tsupregset;
  373. unusedregsaddr : Tsupregset;
  374. unusedregsfpu : tregisterset;
  375. unusedregsmm : tregisterset;
  376. countunusedregsint,
  377. countunusedregsaddr,
  378. countunusedregsfpu,
  379. countunusedregsmm : byte;
  380. end;
  381. implementation
  382. uses
  383. systems,
  384. globals,verbose,
  385. cgobj,tgobj,regvars;
  386. constructor Trgobj.create(Acpu_registers:byte);
  387. begin
  388. usedinproc := [];
  389. usedbyproc:=[];
  390. t_times := 0;
  391. resetusableregisters;
  392. lastintreg:=0;
  393. maxintreg:=first_imreg;
  394. cpu_registers:=Acpu_registers;
  395. {$ifdef TEMPREGDEBUG}
  396. fillchar(reg_user,sizeof(reg_user),0);
  397. fillchar(reg_releaser,sizeof(reg_releaser),0);
  398. {$endif TEMPREGDEBUG}
  399. {$ifdef newra}
  400. fillchar(igraph,sizeof(igraph),0);
  401. fillchar(degree,sizeof(degree),0);
  402. fillchar(movelist,sizeof(movelist),0);
  403. worklist_moves:=Tlinkedlist.create;
  404. {$endif}
  405. end;
  406. function trgobj.getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  407. var unusedregs: tregisterset; var countunusedregs: byte): tregister;
  408. var
  409. i: Toldregister;
  410. r: Tregister;
  411. begin
  412. for i:=lowreg to highreg do
  413. begin
  414. if i in unusedregs then
  415. begin
  416. exclude(unusedregs,i);
  417. include(usedinproc,i);
  418. include(usedbyproc,i);
  419. dec(countunusedregs);
  420. r.enum:=i;
  421. list.concat(tai_regalloc.alloc(r));
  422. result := r;
  423. exit;
  424. end;
  425. end;
  426. internalerror(10);
  427. end;
  428. function Trgobj.getregistergenint(list:Taasmoutput;
  429. subreg:Tsubregister;
  430. const lowreg,highreg:Tsuperregister;
  431. var fusedinproc,fusedbyproc,unusedregs:Tsupregset;
  432. var countunusedregs:byte):Tregister;
  433. var i:Tsuperregister;
  434. r:Tregister;
  435. begin
  436. if not (lastintreg in [lowreg..highreg]) then
  437. lastintreg:=lowreg;
  438. i:=lastintreg;
  439. repeat
  440. if i=highreg then
  441. i:=lowreg
  442. else
  443. inc(i);
  444. if i in unusedregs then
  445. begin
  446. exclude(unusedregs,i);
  447. include(fusedinproc,i);
  448. include(fusedbyproc,i);
  449. dec(countunusedregs);
  450. r.enum:=R_INTREGISTER;
  451. r.number:=i shl 8 or subreg;
  452. list.concat(Tai_regalloc.alloc(r));
  453. result:=r;
  454. lastintreg:=i;
  455. if i>maxintreg then
  456. maxintreg:=i;
  457. {$ifdef newra}
  458. add_edges_used(i);
  459. {$endif}
  460. exit;
  461. end;
  462. until i=lastintreg;
  463. internalerror(10);
  464. end;
  465. procedure trgobj.ungetregistergen(list: taasmoutput; const r: tregister;
  466. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  467. begin
  468. if r.enum>lastreg then
  469. internalerror(2003010801);
  470. { takes much time }
  471. if not(r.enum in usableregs) then
  472. exit;
  473. {$ifdef TEMPREGDEBUG}
  474. if (r.enum in unusedregs) then
  475. {$ifdef EXTTEMPREGDEBUG}
  476. begin
  477. Comment(V_Debug,'register freed twice '+std_reg2str[r.enum]);
  478. testregisters32;
  479. exit;
  480. end
  481. {$else EXTTEMPREGDEBUG}
  482. exit
  483. {$endif EXTTEMPREGDEBUG}
  484. else
  485. {$endif TEMPREGDEBUG}
  486. inc(countunusedregs);
  487. include(unusedregs,r.enum);
  488. list.concat(tai_regalloc.dealloc(r));
  489. end;
  490. procedure trgobj.ungetregistergenint(list:taasmoutput;const r:Tregister;
  491. const usableregs:Tsupregset;
  492. var unusedregs:Tsupregset;
  493. var countunusedregs:byte);
  494. var supreg:Tsuperregister;
  495. begin
  496. if r.enum<=lastreg then
  497. internalerror(2003010803);
  498. supreg:=r.number shr 8;
  499. { takes much time }
  500. {$ifndef newra}
  501. if not(supreg in usableregs) then
  502. exit;
  503. {$endif}
  504. {$ifdef TEMPREGDEBUG}
  505. if (supreg in unusedregs) then
  506. {$ifdef EXTTEMPREGDEBUG}
  507. begin
  508. comment(v_debug,'register freed twice '+supreg_name(supreg));
  509. testregisters32;
  510. exit;
  511. end
  512. {$else EXTTEMPREGDEBUG}
  513. exit
  514. {$endif EXTTEMPREGDEBUG}
  515. else
  516. {$endif TEMPREGDEBUG}
  517. inc(countunusedregs);
  518. include(unusedregs,supreg);
  519. list.concat(tai_regalloc.dealloc(r));
  520. {$ifdef newra}
  521. add_edges_used(supreg);
  522. {$endif newra}
  523. end;
  524. function trgobj.getregisterint(list:taasmoutput;size:Tcgsize):Tregister;
  525. var subreg:Tsubregister;
  526. begin
  527. if countunusedregsint=0 then
  528. internalerror(10);
  529. {$ifdef TEMPREGDEBUG}
  530. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  531. internalerror(10);
  532. {$endif TEMPREGDEBUG}
  533. {$ifdef EXTTEMPREGDEBUG}
  534. if curptree^^.usableregs-countunusedregsint>curptree^^.reallyusedregs then
  535. curptree^^.reallyusedregs:=curptree^^.usableregs-countunusedregsint;
  536. {$endif EXTTEMPREGDEBUG}
  537. subreg:=cgsize2subreg(size);
  538. result:=getregistergenint(list,
  539. subreg,
  540. {$ifdef newra}
  541. first_imreg,
  542. last_imreg,
  543. {$else}
  544. first_supreg,
  545. last_supreg,
  546. {$endif}
  547. usedintbyproc,
  548. usedintinproc,
  549. unusedregsint,
  550. countunusedregsint);
  551. {$ifdef TEMPREGDEBUG}
  552. reg_user[result]:=curptree^;
  553. testregisters32;
  554. {$endif TEMPREGDEBUG}
  555. end;
  556. procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
  557. begin
  558. ungetregistergenint(list,r,usableregsint,unusedregsint,
  559. countunusedregsint);
  560. {$ifdef TEMPREGDEBUG}
  561. reg_releaser[r]:=curptree^;
  562. testregisters32;
  563. {$endif TEMPREGDEBUG}
  564. end;
  565. { tries to allocate the passed register, if possible }
  566. function trgobj.getexplicitregisterint(list:Taasmoutput;r:Tnewregister):Tregister;
  567. var r2:Tregister;
  568. begin
  569. if (r shr 8) in unusedregsint then
  570. begin
  571. dec(countunusedregsint);
  572. {$ifdef TEMPREGDEBUG}
  573. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  574. internalerror(10);
  575. reg_user[r shr 8]:=curptree^;
  576. {$endif TEMPREGDEBUG}
  577. exclude(unusedregsint,r shr 8);
  578. include(usedintinproc,r shr 8);
  579. include(usedintbyproc,r shr 8);
  580. r2.enum:=R_INTREGISTER;
  581. r2.number:=r;
  582. list.concat(tai_regalloc.alloc(r2));
  583. {$ifdef TEMPREGDEBUG}
  584. testregisters32;
  585. {$endif TEMPREGDEBUG}
  586. end
  587. else
  588. internalerror(200301103);
  589. getexplicitregisterint:=r2;
  590. end;
  591. { tries to allocate the passed register, if possible }
  592. function trgobj.getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  593. var r2:Tregister;
  594. begin
  595. if r in unusedregsfpu then
  596. begin
  597. dec(countunusedregsfpu);
  598. {$ifdef TEMPREGDEBUG}
  599. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  600. internalerror(10);
  601. reg_user[r]:=curptree^;
  602. {$endif TEMPREGDEBUG}
  603. exclude(unusedregsfpu,r);
  604. include(usedinproc,r);
  605. include(usedbyproc,r);
  606. r2.enum:=r;
  607. list.concat(tai_regalloc.alloc(r2));
  608. getexplicitregisterfpu:=r2;
  609. {$ifdef TEMPREGDEBUG}
  610. testregisters32;
  611. {$endif TEMPREGDEBUG}
  612. end
  613. else
  614. getexplicitregisterfpu:=getregisterfpu(list);
  615. end;
  616. function trgobj.getregisterfpu(list: taasmoutput) : tregister;
  617. begin
  618. if countunusedregsfpu=0 then
  619. internalerror(10);
  620. result := getregistergen(list,firstsavefpureg,lastsavefpureg,
  621. unusedregsfpu,countunusedregsfpu);
  622. end;
  623. procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister);
  624. begin
  625. ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
  626. countunusedregsfpu);
  627. end;
  628. function trgobj.getregistermm(list: taasmoutput) : tregister;
  629. begin
  630. if countunusedregsmm=0 then
  631. internalerror(10);
  632. result := getregistergen(list,firstsavemmreg,lastsavemmreg,
  633. unusedregsmm,countunusedregsmm);
  634. end;
  635. procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
  636. begin
  637. ungetregistergen(list,r,usableregsmm,unusedregsmm,
  638. countunusedregsmm);
  639. end;
  640. function trgobj.getaddressregister(list:Taasmoutput): tregister;
  641. begin
  642. {An address register is OS_INT per definition.}
  643. result := getregisterint(list,OS_INT);
  644. end;
  645. procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
  646. begin
  647. ungetregisterint(list,r);
  648. end;
  649. function trgobj.isaddressregister(reg: tregister): boolean;
  650. begin
  651. result := true;
  652. end;
  653. procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
  654. begin
  655. if r.enum=R_NO then
  656. exit;
  657. if r.enum>lastreg then
  658. internalerror(200301081);
  659. if r.enum in intregs then
  660. ungetregisterint(list,r)
  661. else if r.enum in fpuregs then
  662. ungetregisterfpu(list,r)
  663. else if r.enum in mmregs then
  664. ungetregistermm(list,r)
  665. else if r.enum in addrregs then
  666. ungetaddressregister(list,r)
  667. else internalerror(2002070602);
  668. end;
  669. procedure Trgobj.cleartempgen;
  670. {$ifdef newra}
  671. var i:Tsuperregister;
  672. {$endif newra}
  673. begin
  674. countunusedregsint:=countusableregsint;
  675. countunusedregsfpu:=countusableregsfpu;
  676. countunusedregsmm:=countusableregsmm;
  677. lastintreg:=0;
  678. maxintreg:=first_imreg;
  679. {$ifdef newra}
  680. unusedregsint:=[0..255];
  681. {$else}
  682. unusedregsint:=usableregsint;
  683. {$endif}
  684. unusedregsfpu:=usableregsfpu;
  685. unusedregsmm:=usableregsmm;
  686. {$ifdef newra}
  687. for i:=low(Tsuperregister) to high(Tsuperregister) do
  688. begin
  689. if igraph.adjlist[i]<>nil then
  690. dispose(igraph.adjlist[i]);
  691. if movelist[i]<>nil then
  692. dispose(movelist[i]);
  693. end;
  694. fillchar(movelist,sizeof(movelist),0);
  695. fillchar(igraph,sizeof(igraph),0);
  696. fillchar(degree,sizeof(degree),0);
  697. worklist_moves.clear;
  698. {$endif}
  699. end;
  700. procedure trgobj.ungetreference(list : taasmoutput; const ref : treference);
  701. begin
  702. if ref.base.number<>NR_NO then
  703. ungetregisterint(list,ref.base);
  704. if ref.index.number<>NR_NO then
  705. ungetregisterint(list,ref.index);
  706. end;
  707. procedure trgobj.saveintregvars(list:Taasmoutput;const s:Tsupregset);
  708. var r:Tsuperregister;
  709. begin
  710. if not(cs_regalloc in aktglobalswitches) then
  711. exit;
  712. for r:=firstsaveintreg to lastsaveintreg do
  713. if (r in is_reg_var_int) and
  714. (r in s) then
  715. store_regvar_int(list,r);
  716. end;
  717. procedure trgobj.saveotherregvars(list: taasmoutput; const s: tregisterset);
  718. var
  719. r: Tregister;
  720. begin
  721. if not(cs_regalloc in aktglobalswitches) then
  722. exit;
  723. if firstsavefpureg <> R_NO then
  724. for r.enum := firstsavefpureg to lastsavefpureg do
  725. if is_reg_var[r.enum] and
  726. (r.enum in s) then
  727. store_regvar(list,r);
  728. if firstsavemmreg <> R_NO then
  729. for r.enum := firstsavemmreg to lastsavemmreg do
  730. if is_reg_var[r.enum] and
  731. (r.enum in s) then
  732. store_regvar(list,r);
  733. end;
  734. procedure trgobj.saveusedintregisters(list:Taasmoutput;
  735. var saved:Tpushedsavedint;
  736. const s:Tsupregset);
  737. var r:Tsuperregister;
  738. r2:Tregister;
  739. hr : treference;
  740. begin
  741. usedintinproc:=usedintinproc+s;
  742. for r:=firstsaveintreg to lastsaveintreg do
  743. begin
  744. saved[r].ofs:=reg_not_saved;
  745. { if the register is used by the calling subroutine and if }
  746. { it's not a regvar (those are handled separately) }
  747. if not (r in is_reg_var_int) and
  748. (r in s) and
  749. { and is present in use }
  750. not(r in unusedregsint) then
  751. begin
  752. { then save it }
  753. tg.GetTemp(list,sizeof(aword),tt_persistant,hr);
  754. saved[r].ofs:=hr.offset;
  755. r2.enum:=R_INTREGISTER;
  756. r2.number:=r shl 8 or R_SUBWHOLE;
  757. cg.a_load_reg_ref(list,OS_INT,r2,hr);
  758. cg.a_reg_dealloc(list,r2);
  759. include(unusedregsint,r);
  760. inc(countunusedregsint);
  761. end;
  762. end;
  763. {$ifdef TEMPREGDEBUG}
  764. testregisters32;
  765. {$endif TEMPREGDEBUG}
  766. end;
  767. procedure trgobj.saveusedotherregisters(list: taasmoutput;
  768. var saved : tpushedsaved; const s: tregisterset);
  769. var
  770. r : tregister;
  771. hr : treference;
  772. begin
  773. usedinproc:=usedinproc + s;
  774. { don't try to save the fpu registers if not desired (e.g. for }
  775. { the 80x86) }
  776. if firstsavefpureg <> R_NO then
  777. for r.enum:=firstsavefpureg to lastsavefpureg do
  778. begin
  779. saved[r.enum].ofs:=reg_not_saved;
  780. { if the register is used by the calling subroutine and if }
  781. { it's not a regvar (those are handled separately) }
  782. if not is_reg_var[r.enum] and
  783. (r.enum in s) and
  784. { and is present in use }
  785. not(r.enum in unusedregsfpu) then
  786. begin
  787. { then save it }
  788. tg.GetTemp(list,extended_size,tt_persistant,hr);
  789. saved[r.enum].ofs:=hr.offset;
  790. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  791. cg.a_reg_dealloc(list,r);
  792. include(unusedregsfpu,r.enum);
  793. inc(countunusedregsfpu);
  794. end;
  795. end;
  796. { don't save the vector registers if there's no support for them }
  797. if firstsavemmreg <> R_NO then
  798. for r.enum:=firstsavemmreg to lastsavemmreg do
  799. begin
  800. saved[r.enum].ofs:=reg_not_saved;
  801. { if the register is in use and if it's not a regvar (those }
  802. { are handled separately), save it }
  803. if not is_reg_var[r.enum] and
  804. (r.enum in s) and
  805. { and is present in use }
  806. not(r.enum in unusedregsmm) then
  807. begin
  808. { then save it }
  809. tg.GetTemp(list,mmreg_size,tt_persistant,hr);
  810. saved[r.enum].ofs:=hr.offset;
  811. cg.a_loadmm_reg_ref(list,r,hr);
  812. cg.a_reg_dealloc(list,r);
  813. include(unusedregsmm,r.enum);
  814. inc(countunusedregsmm);
  815. end;
  816. end;
  817. {$ifdef TEMPREGDEBUG}
  818. testregisters32;
  819. {$endif TEMPREGDEBUG}
  820. end;
  821. procedure trgobj.restoreusedintregisters(list:Taasmoutput;
  822. const saved:Tpushedsavedint);
  823. var r:Tsuperregister;
  824. r2:Tregister;
  825. hr:Treference;
  826. begin
  827. for r:=lastsaveintreg downto firstsaveintreg do
  828. begin
  829. if saved[r].ofs <> reg_not_saved then
  830. begin
  831. r2.enum:=R_INTREGISTER;
  832. r2.number:=NR_FRAME_POINTER_REG;
  833. reference_reset_base(hr,r2,saved[r].ofs);
  834. r2.enum:=R_INTREGISTER;
  835. r2.number:=r shl 8 or R_SUBWHOLE;
  836. cg.a_reg_alloc(list,r2);
  837. cg.a_load_ref_reg(list,OS_INT,hr,r2);
  838. if not (r in unusedregsint) then
  839. { internalerror(10)
  840. in n386cal we always save/restore the reg *state*
  841. using save/restoreunusedstate -> the current state
  842. may not be real (JM) }
  843. else
  844. begin
  845. dec(countunusedregsint);
  846. exclude(unusedregsint,r);
  847. end;
  848. tg.UnGetTemp(list,hr);
  849. end;
  850. end;
  851. {$ifdef TEMPREGDEBUG}
  852. testregisters32;
  853. {$endif TEMPREGDEBUG}
  854. end;
  855. procedure trgobj.restoreusedotherregisters(list : taasmoutput;
  856. const saved : tpushedsaved);
  857. var
  858. r,r2 : tregister;
  859. hr : treference;
  860. begin
  861. if firstsavemmreg <> R_NO then
  862. for r.enum:=lastsavemmreg downto firstsavemmreg do
  863. begin
  864. if saved[r.enum].ofs <> reg_not_saved then
  865. begin
  866. r2.enum:=R_INTREGISTER;
  867. r2.number:=NR_FRAME_POINTER_REG;
  868. reference_reset_base(hr,r2,saved[r.enum].ofs);
  869. cg.a_reg_alloc(list,r);
  870. cg.a_loadmm_ref_reg(list,hr,r);
  871. if not (r.enum in unusedregsmm) then
  872. { internalerror(10)
  873. in n386cal we always save/restore the reg *state*
  874. using save/restoreunusedstate -> the current state
  875. may not be real (JM) }
  876. else
  877. begin
  878. dec(countunusedregsmm);
  879. exclude(unusedregsmm,r.enum);
  880. end;
  881. tg.UnGetTemp(list,hr);
  882. end;
  883. end;
  884. if firstsavefpureg <> R_NO then
  885. for r.enum:=lastsavefpureg downto firstsavefpureg do
  886. begin
  887. if saved[r.enum].ofs <> reg_not_saved then
  888. begin
  889. r2.enum:=R_INTREGISTER;
  890. r2.number:=NR_FRAME_POINTER_REG;
  891. reference_reset_base(hr,r2,saved[r.enum].ofs);
  892. cg.a_reg_alloc(list,r);
  893. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  894. if not (r.enum in unusedregsfpu) then
  895. { internalerror(10)
  896. in n386cal we always save/restore the reg *state*
  897. using save/restoreunusedstate -> the current state
  898. may not be real (JM) }
  899. else
  900. begin
  901. dec(countunusedregsfpu);
  902. exclude(unusedregsfpu,r.enum);
  903. end;
  904. tg.UnGetTemp(list,hr);
  905. end;
  906. end;
  907. {$ifdef TEMPREGDEBUG}
  908. testregisters32;
  909. {$endif TEMPREGDEBUG}
  910. end;
  911. procedure trgobj.incrementintregisterpushed(const s:Tsupregset);
  912. var regi:Tsuperregister;
  913. begin
  914. for regi:=firstsaveintreg to lastsaveintreg do
  915. begin
  916. if (regi in s) then
  917. inc(reg_pushes_int[regi],t_times*2);
  918. end;
  919. end;
  920. procedure trgobj.incrementotherregisterpushed(const s:Tregisterset);
  921. var
  922. regi : Toldregister;
  923. begin
  924. if firstsavefpureg <> R_NO then
  925. for regi:=firstsavefpureg to lastsavefpureg do
  926. begin
  927. if (regi in s) then
  928. inc(reg_pushes[regi],t_times*2);
  929. end;
  930. if firstsavemmreg <> R_NO then
  931. for regi:=firstsavemmreg to lastsavemmreg do
  932. begin
  933. if (regi in s) then
  934. inc(reg_pushes[regi],t_times*2);
  935. end;
  936. end;
  937. procedure trgobj.clearregistercount;
  938. begin
  939. fillchar(reg_pushes,sizeof(reg_pushes),0);
  940. fillchar(is_reg_var,sizeof(is_reg_var),false);
  941. is_reg_var_int:=[];
  942. fillchar(regvar_loaded,sizeof(regvar_loaded),false);
  943. regvar_loaded_int:=[];
  944. end;
  945. procedure trgobj.resetusableregisters;
  946. begin
  947. { initialize fields with constant values from cpubase }
  948. countusableregsint := cpubase.c_countusableregsint;
  949. countusableregsfpu := cpubase.c_countusableregsfpu;
  950. countusableregsmm := cpubase.c_countusableregsmm;
  951. usableregsint := cpubase.usableregsint;
  952. usableregsfpu := cpubase.usableregsfpu;
  953. usableregsmm := cpubase.usableregsmm;
  954. clearregistercount;
  955. end;
  956. procedure trgobj.makeregvarint(reg:Tnewregister);
  957. var supreg:Tsuperregister;
  958. begin
  959. supreg:=reg shr 8;
  960. dec(countusableregsint);
  961. dec(countunusedregsint);
  962. exclude(usableregsint,reg);
  963. exclude(unusedregsint,reg);
  964. include(is_reg_var_int,supreg);
  965. end;
  966. procedure trgobj.makeregvarother(reg: tregister);
  967. begin
  968. if reg.enum>lastreg then
  969. internalerror(200301081);
  970. if reg.enum in intregs then
  971. internalerror(200301151)
  972. else if reg.enum in fpuregs then
  973. begin
  974. dec(countusableregsfpu);
  975. dec(countunusedregsfpu);
  976. exclude(usableregsfpu,reg.enum);
  977. exclude(unusedregsfpu,reg.enum);
  978. end
  979. else if reg.enum in mmregs then
  980. begin
  981. dec(countusableregsmm);
  982. dec(countunusedregsmm);
  983. exclude(usableregsmm,reg.enum);
  984. exclude(unusedregsmm,reg.enum);
  985. end;
  986. is_reg_var[reg.enum]:=true;
  987. end;
  988. {$ifdef TEMPREGDEBUG}
  989. procedure trgobj.testregisters;
  990. var
  991. r: tregister;
  992. test : byte;
  993. begin
  994. test:=0;
  995. for r := firstsaveintreg to lastsaveintreg do
  996. inc(test,ord(r in unusedregsint));
  997. if test<>countunusedregsint then
  998. internalerror(10);
  999. end;
  1000. {$endif TEMPREGDEBUG}
  1001. procedure trgobj.saveStateForInline(var state: pointer);
  1002. begin
  1003. new(psavedstate(state));
  1004. psavedstate(state)^.unusedregsint := unusedregsint;
  1005. psavedstate(state)^.usableregsint := usableregsint;
  1006. psavedstate(state)^.unusedregsfpu := unusedregsfpu;
  1007. psavedstate(state)^.usableregsfpu := usableregsfpu;
  1008. psavedstate(state)^.unusedregsmm := unusedregsmm;
  1009. psavedstate(state)^.usableregsmm := usableregsmm;
  1010. psavedstate(state)^.countunusedregsint := countunusedregsint;
  1011. psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  1012. psavedstate(state)^.countunusedregsmm := countunusedregsmm;
  1013. psavedstate(state)^.countusableregsint := countusableregsint;
  1014. psavedstate(state)^.countusableregsfpu := countusableregsfpu;
  1015. psavedstate(state)^.countusableregsmm := countusableregsmm;
  1016. psavedstate(state)^.usedinproc := usedinproc;
  1017. psavedstate(state)^.usedbyproc := usedbyproc;
  1018. psavedstate(state)^.reg_pushes := reg_pushes;
  1019. psavedstate(state)^.is_reg_var := is_reg_var;
  1020. psavedstate(state)^.is_reg_var_int := is_reg_var_int;
  1021. psavedstate(state)^.regvar_loaded := regvar_loaded;
  1022. psavedstate(state)^.regvar_loaded_int := regvar_loaded_int;
  1023. {$ifdef TEMPREGDEBUG}
  1024. psavedstate(state)^.reg_user := reg_user;
  1025. psavedstate(state)^.reg_releaser := reg_releaser;
  1026. {$endif TEMPREGDEBUG}
  1027. end;
  1028. procedure trgobj.restoreStateAfterInline(var state: pointer);
  1029. begin
  1030. unusedregsint := psavedstate(state)^.unusedregsint;
  1031. usableregsint := psavedstate(state)^.usableregsint;
  1032. unusedregsfpu := psavedstate(state)^.unusedregsfpu;
  1033. usableregsfpu := psavedstate(state)^.usableregsfpu;
  1034. unusedregsmm := psavedstate(state)^.unusedregsmm;
  1035. usableregsmm := psavedstate(state)^.usableregsmm;
  1036. countunusedregsint := psavedstate(state)^.countunusedregsint;
  1037. countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
  1038. countunusedregsmm := psavedstate(state)^.countunusedregsmm;
  1039. countusableregsint := psavedstate(state)^.countusableregsint;
  1040. countusableregsfpu := psavedstate(state)^.countusableregsfpu;
  1041. countusableregsmm := psavedstate(state)^.countusableregsmm;
  1042. usedinproc := psavedstate(state)^.usedinproc;
  1043. usedbyproc := psavedstate(state)^.usedbyproc;
  1044. reg_pushes := psavedstate(state)^.reg_pushes;
  1045. is_reg_var := psavedstate(state)^.is_reg_var;
  1046. is_reg_var_int := psavedstate(state)^.is_reg_var_int;
  1047. regvar_loaded := psavedstate(state)^.regvar_loaded;
  1048. regvar_loaded_int := psavedstate(state)^.regvar_loaded_int;
  1049. {$ifdef TEMPREGDEBUG}
  1050. reg_user := psavedstate(state)^.reg_user;
  1051. reg_releaser := psavedstate(state)^.reg_releaser;
  1052. {$endif TEMPREGDEBUG}
  1053. dispose(psavedstate(state));
  1054. state := nil;
  1055. end;
  1056. procedure trgobj.saveUnusedState(var state: pointer);
  1057. begin
  1058. new(punusedstate(state));
  1059. punusedstate(state)^.unusedregsint := unusedregsint;
  1060. punusedstate(state)^.unusedregsfpu := unusedregsfpu;
  1061. punusedstate(state)^.unusedregsmm := unusedregsmm;
  1062. punusedstate(state)^.countunusedregsint := countunusedregsint;
  1063. punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  1064. punusedstate(state)^.countunusedregsmm := countunusedregsmm;
  1065. end;
  1066. procedure trgobj.restoreUnusedState(var state: pointer);
  1067. begin
  1068. unusedregsint := punusedstate(state)^.unusedregsint;
  1069. unusedregsfpu := punusedstate(state)^.unusedregsfpu;
  1070. unusedregsmm := punusedstate(state)^.unusedregsmm;
  1071. countunusedregsint := punusedstate(state)^.countunusedregsint;
  1072. countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
  1073. countunusedregsmm := punusedstate(state)^.countunusedregsmm;
  1074. dispose(punusedstate(state));
  1075. state := nil;
  1076. end;
  1077. {$ifdef newra}
  1078. procedure Trgobj.add_edge(u,v:Tsuperregister);
  1079. {This procedure will add an edge to the virtual interference graph.}
  1080. procedure addadj(u,v:Tsuperregister);
  1081. begin
  1082. if igraph.adjlist[u]=nil then
  1083. begin
  1084. getmem(igraph.adjlist[u],16);
  1085. igraph.adjlist[u]^:='';
  1086. end
  1087. else if (length(igraph.adjlist[u]^) and 15)=15 then
  1088. reallocmem(igraph.adjlist[u],length(igraph.adjlist[u]^)+16);
  1089. igraph.adjlist[u]^:=igraph.adjlist[u]^+char(v);
  1090. end;
  1091. begin
  1092. if (u<>v) and not(v in igraph.bitmap[u]) then
  1093. begin
  1094. include(igraph.bitmap[u],v);
  1095. include(igraph.bitmap[v],u);
  1096. {Precoloured nodes are not stored in the interference graph.}
  1097. if not(u in [first_supreg..last_supreg]) then
  1098. begin
  1099. addadj(u,v);
  1100. inc(degree[u]);
  1101. end;
  1102. if not(v in [first_supreg..last_supreg]) then
  1103. begin
  1104. addadj(v,u);
  1105. inc(degree[v]);
  1106. end;
  1107. end;
  1108. end;
  1109. procedure Trgobj.add_edges_used(u:Tsuperregister);
  1110. var i:Tsuperregister;
  1111. begin
  1112. for i:=1 to 255 do
  1113. if not(i in unusedregsint) then
  1114. add_edge(u,i);
  1115. end;
  1116. {$ifdef ra_debug}
  1117. procedure Trgobj.writegraph;
  1118. {This procedure writes out the current interference graph in the
  1119. register allocator.}
  1120. var f:text;
  1121. i,j:Tsuperregister;
  1122. begin
  1123. assign(f,'igraph'+char(48+random(10))+char(48+random(10)));
  1124. rewrite(f);
  1125. writeln(f,'Interference graph');
  1126. writeln(f);
  1127. write(f,' ');
  1128. for i:=0 to 15 do
  1129. for j:=0 to 15 do
  1130. write(f,hexstr(i,1));
  1131. writeln(f);
  1132. write(f,' ');
  1133. for i:=0 to 15 do
  1134. write(f,'0123456789ABCDEF');
  1135. writeln(f);
  1136. for i:=0 to 255 do
  1137. begin
  1138. write(f,hexstr(i,2):4);
  1139. for j:=0 to 255 do
  1140. if j in igraph.bitmap[i] then
  1141. write(f,'*')
  1142. else
  1143. write(f,'-');
  1144. writeln(f);
  1145. end;
  1146. close(f);
  1147. end;
  1148. {$endif}
  1149. procedure Trgobj.add_to_movelist(u:Tsuperregister;data:Tlinkedlistitem);
  1150. begin
  1151. if movelist[u]=nil then
  1152. begin
  1153. getmem(movelist[u],64);
  1154. movelist[u]^.count:=0;
  1155. end
  1156. else if (movelist[u]^.count and 15)=15 then
  1157. reallocmem(movelist[u],(movelist[u]^.count+1)*4+64);
  1158. movelist[u]^.data[movelist[u]^.count]:=data;
  1159. inc(movelist[u]^.count);
  1160. end;
  1161. procedure Trgobj.add_move_instruction(instr:Taicpu);
  1162. {This procedure notifies a certain as a move instruction so the
  1163. register allocator can try to eliminate it.}
  1164. var i:Tmoveins;
  1165. ssupreg,dsupreg:Tsuperregister;
  1166. begin
  1167. i:=Tmoveins.create;
  1168. i.moveset:=ms_worklist_moves;
  1169. i.instruction:=instr;
  1170. worklist_moves.insert(i);
  1171. ssupreg:=instr.oper[0].reg.number shr 8;
  1172. add_to_movelist(ssupreg,i);
  1173. dsupreg:=instr.oper[1].reg.number shr 8;
  1174. add_to_movelist(dsupreg,i);
  1175. end;
  1176. function Trgobj.move_related(n:Tsuperregister):boolean;
  1177. var i:cardinal;
  1178. begin
  1179. move_related:=false;
  1180. if movelist[n]<>nil then
  1181. begin
  1182. for i:=0 to movelist[n]^.count-1 do
  1183. if Tmoveins(movelist[n]^.data[i]).moveset in
  1184. [ms_worklist_moves,ms_active_moves] then
  1185. begin
  1186. move_related:=true;
  1187. break;
  1188. end;
  1189. end;
  1190. end;
  1191. procedure Trgobj.make_work_list;
  1192. var n:Tsuperregister;
  1193. begin
  1194. for n:=first_imreg to maxintreg do
  1195. if degree[n]>cpu_registers then
  1196. spillworklist:=spillworklist+char(n)
  1197. else if move_related(n) then
  1198. freezeworklist:=freezeworklist+char(n)
  1199. else
  1200. simplifyworklist:=simplifyworklist+char(n);
  1201. end;
  1202. procedure Trgobj.prepare_colouring;
  1203. begin
  1204. make_work_list;
  1205. active_moves:=Tlinkedlist.create;
  1206. frozen_moves:=Tlinkedlist.create;
  1207. coalesced_moves:=Tlinkedlist.create;
  1208. constrained_moves:=Tlinkedlist.create;
  1209. fillchar(alias,sizeof(alias),0);
  1210. coalescednodes:='';
  1211. selectstack:='';
  1212. end;
  1213. procedure Trgobj.enable_moves(n:Tsuperregister);
  1214. var m:Tlinkedlistitem;
  1215. i:cardinal;
  1216. begin
  1217. if movelist[n]<>nil then
  1218. for i:=0 to movelist[n]^.count-1 do
  1219. begin
  1220. m:=movelist[n]^.data[i];
  1221. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  1222. begin
  1223. if Tmoveins(m).moveset=ms_active_moves then
  1224. begin
  1225. {Move m from the set active_moves to the set worklist_moves.}
  1226. active_moves.remove(m);
  1227. Tmoveins(m).moveset:=ms_worklist_moves;
  1228. worklist_moves.concat(m);
  1229. end;
  1230. end;
  1231. end;
  1232. end;
  1233. procedure Trgobj.decrement_degree(m:Tsuperregister);
  1234. var adj:Pstring;
  1235. d:byte;
  1236. i:byte;
  1237. n:char;
  1238. begin
  1239. d:=degree[m];
  1240. dec(degree[m]);
  1241. if d=cpu_registers then
  1242. begin
  1243. {Enable moves for m.}
  1244. enable_moves(m);
  1245. {Enable moves for adjacent.}
  1246. adj:=igraph.adjlist[m];
  1247. if adj<>nil then
  1248. for i:=1 to length(adj^) do
  1249. begin
  1250. n:=adj^[i];
  1251. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  1252. enable_moves(Tsuperregister(n));
  1253. end;
  1254. {In case the node is in the spillworklist, delete it.}
  1255. delete(spillworklist,pos(char(m),spillworklist),1);
  1256. if move_related(m) then
  1257. freezeworklist:=freezeworklist+char(m)
  1258. else
  1259. simplifyworklist:=simplifyworklist+char(m);
  1260. end;
  1261. end;
  1262. procedure Trgobj.simplify;
  1263. var adj:Pstring;
  1264. i:byte;
  1265. m:char;
  1266. n:Tsuperregister;
  1267. begin
  1268. {We need to take a random element out of the simplifyworklist. We take
  1269. the last element. Dirty code!}
  1270. n:=Tsuperregister(simplifyworklist[byte(simplifyworklist[0])]);
  1271. dec(simplifyworklist[0]);
  1272. {Push it on the selectstack.}
  1273. selectstack:=selectstack+char(n);
  1274. adj:=igraph.adjlist[n];
  1275. if adj<>nil then
  1276. for i:=1 to length(adj^) do
  1277. begin
  1278. m:=adj^[i];
  1279. if (pos(m,selectstack) or pos(m,coalescednodes))=0 then
  1280. decrement_degree(Tsuperregister(m));
  1281. end;
  1282. end;
  1283. function Trgobj.get_alias(n:Tsuperregister):Tsuperregister;
  1284. begin
  1285. while pos(char(n),coalescednodes)<>0 do
  1286. n:=alias[n];
  1287. get_alias:=n;
  1288. end;
  1289. procedure Trgobj.add_worklist(u:Tsuperregister);
  1290. begin
  1291. if not(u in [first_supreg..last_supreg]) and not move_related(u) and
  1292. (degree[u]<cpu_registers) then
  1293. begin
  1294. delete(freezeworklist,pos(char(u),freezeworklist),1);
  1295. simplifyworklist:=simplifyworklist+char(u);
  1296. end;
  1297. end;
  1298. function Trgobj.adjacent_ok(u,v:Tsuperregister):boolean;
  1299. {Check wether u and v should be coalesced. u is precoloured.}
  1300. function ok(t,r:Tsuperregister):boolean;
  1301. begin
  1302. ok:=(degree[t]<cpu_registers) or
  1303. (t in [first_supreg..last_supreg]) or
  1304. (r in igraph.bitmap[t]);
  1305. end;
  1306. var adj:Pstring;
  1307. i:byte;
  1308. t:char;
  1309. begin
  1310. adjacent_ok:=true;
  1311. adj:=igraph.adjlist[v];
  1312. if adj<>nil then
  1313. for i:=1 to length(adj^) do
  1314. begin
  1315. t:=adj^[i];
  1316. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  1317. if not ok(Tsuperregister(t),u) then
  1318. begin
  1319. adjacent_ok:=false;
  1320. break;
  1321. end;
  1322. end;
  1323. end;
  1324. function Trgobj.conservative(u,v:Tsuperregister):boolean;
  1325. var adj:Pstring;
  1326. done:set of char; {To prevent that we count nodes twice.}
  1327. i,k:byte;
  1328. n:char;
  1329. begin
  1330. k:=0;
  1331. done:=[];
  1332. adj:=igraph.adjlist[u];
  1333. if adj<>nil then
  1334. for i:=1 to length(adj^) do
  1335. begin
  1336. n:=adj^[i];
  1337. if (pos(n,selectstack) or pos(n,coalescednodes))=0 then
  1338. begin
  1339. include(done,n);
  1340. if degree[Tsuperregister(n)]>=cpu_registers then
  1341. inc(k);
  1342. end;
  1343. end;
  1344. adj:=igraph.adjlist[v];
  1345. if adj<>nil then
  1346. for i:=1 to length(adj^) do
  1347. begin
  1348. n:=adj^[i];
  1349. if ((pos(n,selectstack) or pos(n,coalescednodes))=0) and
  1350. not (n in done) and
  1351. (degree[Tsuperregister(n)]>=cpu_registers) then
  1352. inc(k);
  1353. end;
  1354. conservative:=(k<cpu_registers);
  1355. end;
  1356. procedure Trgobj.combine(u,v:Tsuperregister);
  1357. var add:boolean;
  1358. adj:Pstring;
  1359. i,p:byte;
  1360. n,o:cardinal;
  1361. t:char;
  1362. begin
  1363. p:=pos(char(v),freezeworklist);
  1364. if p<>0 then
  1365. delete(freezeworklist,p,1)
  1366. else
  1367. delete(spillworklist,pos(char(v),spillworklist),1);
  1368. coalescednodes:=coalescednodes+char(v);
  1369. alias[v]:=u;
  1370. {Combine both movelists. Since the movelists are sets, only add
  1371. elements that are not already present.}
  1372. for n:=0 to movelist[v]^.count-1 do
  1373. begin
  1374. add:=true;
  1375. for o:=0 to movelist[u]^.count-1 do
  1376. if movelist[u]^.data[o]=movelist[v]^.data[n] then
  1377. begin
  1378. add:=false;
  1379. break;
  1380. end;
  1381. if add then
  1382. add_to_movelist(u,movelist[v]^.data[n]);
  1383. end;
  1384. enable_moves(v);
  1385. adj:=igraph.adjlist[v];
  1386. if adj<>nil then
  1387. for i:=1 to length(adj^) do
  1388. begin
  1389. t:=adj^[i];
  1390. if (pos(t,selectstack) or pos(t,coalescednodes))=0 then
  1391. begin
  1392. add_edge(Tsuperregister(t),u);
  1393. decrement_degree(Tsuperregister(t));
  1394. end;
  1395. end;
  1396. p:=pos(char(u),freezeworklist);
  1397. if (degree[u]>=cpu_registers) and (p<>0) then
  1398. begin
  1399. delete(freezeworklist,p,1);
  1400. spillworklist:=spillworklist+char(u);
  1401. end;
  1402. end;
  1403. procedure Trgobj.coalesce;
  1404. var m:Tmoveins;
  1405. x,y,u,v:Tsuperregister;
  1406. begin
  1407. m:=Tmoveins(worklist_moves.getfirst);
  1408. x:=get_alias(m.instruction.oper[0].reg.number shr 8);
  1409. y:=get_alias(m.instruction.oper[1].reg.number shr 8);
  1410. if y in [first_supreg..last_supreg] then
  1411. begin
  1412. u:=y;
  1413. v:=x;
  1414. end
  1415. else
  1416. begin
  1417. u:=x;
  1418. v:=y;
  1419. end;
  1420. if (u=v) then
  1421. begin
  1422. m.moveset:=ms_coalesced_moves; {Already coalesced.}
  1423. coalesced_moves.insert(m);
  1424. add_worklist(u);
  1425. end
  1426. {Do u and v interfere? In that case the move is constrained. Two
  1427. precoloured nodes interfere allways. If v is precoloured, by the above
  1428. code u is precoloured, thus interference...}
  1429. else if (v in [first_supreg..last_supreg]) or (u in igraph.bitmap[v]) then
  1430. begin
  1431. m.moveset:=ms_constrained_moves; {Cannot coalesce yet...}
  1432. constrained_moves.insert(m);
  1433. add_worklist(u);
  1434. add_worklist(v);
  1435. end
  1436. {Next test: is it possible and a good idea to coalesce??}
  1437. else if ((u in [first_supreg..last_supreg]) and adjacent_ok(u,v)) or
  1438. (not(u in [first_supreg..last_supreg]) and conservative(u,v)) then
  1439. begin
  1440. m.moveset:=ms_coalesced_moves; {Move coalesced!}
  1441. coalesced_moves.insert(m);
  1442. combine(u,v);
  1443. add_worklist(u);
  1444. end
  1445. else
  1446. begin
  1447. m.moveset:=ms_active_moves;
  1448. active_moves.insert(m);
  1449. end;
  1450. end;
  1451. procedure Trgobj.freeze_moves(u:Tsuperregister);
  1452. var i:cardinal;
  1453. m:Tlinkedlistitem;
  1454. v,x,y:Tsuperregister;
  1455. begin
  1456. for i:=0 to movelist[u]^.count-1 do
  1457. begin
  1458. m:=movelist[u]^.data[i];
  1459. if Tmoveins(m).moveset in [ms_worklist_moves,ms_active_moves] then
  1460. begin
  1461. x:=Tmoveins(m).instruction.oper[0].reg.number shr 8;
  1462. y:=Tmoveins(m).instruction.oper[1].reg.number shr 8;
  1463. if get_alias(y)=get_alias(u) then
  1464. v:=get_alias(x)
  1465. else
  1466. v:=get_alias(y);
  1467. {Move m from active_moves/worklist_moves to frozen_moves.}
  1468. if Tmoveins(m).moveset=ms_active_moves then
  1469. active_moves.remove(m)
  1470. else
  1471. worklist_moves.remove(m);
  1472. Tmoveins(m).moveset:=ms_frozen_moves;
  1473. frozen_moves.insert(m);
  1474. if not(move_related(v)) and (degree[v]<cpu_registers) then
  1475. begin
  1476. delete(freezeworklist,pos(char(v),freezeworklist),1);
  1477. simplifyworklist:=simplifyworklist+char(v);
  1478. end;
  1479. end;
  1480. end;
  1481. end;
  1482. procedure Trgobj.freeze;
  1483. var n:Tsuperregister;
  1484. begin
  1485. {We need to take a random element out of the freezeworklist. We take
  1486. the last element. Dirty code!}
  1487. n:=Tsuperregister(freezeworklist[byte(freezeworklist[0])]);
  1488. dec(freezeworklist[0]);
  1489. {Add it to the simplifyworklist.}
  1490. simplifyworklist:=simplifyworklist+char(n);
  1491. freeze_moves(n);
  1492. end;
  1493. procedure Trgobj.select_spill;
  1494. var n:char;
  1495. begin
  1496. {This code is WAY too naive. We need not to select just a register, but
  1497. the register that is used the least...}
  1498. n:=spillworklist[byte(spillworklist[0])];
  1499. dec(spillworklist[0]);
  1500. simplifyworklist:=simplifyworklist+n;
  1501. freeze_moves(Tsuperregister(n));
  1502. end;
  1503. procedure Trgobj.assign_colours;
  1504. {Assign_colours assigns the actual colours to the registers.}
  1505. var adj:Pstring;
  1506. i,j,k:byte;
  1507. n,a:Tsuperregister;
  1508. adj_colours,colourednodes:set of Tsuperregister;
  1509. w:char;
  1510. begin
  1511. spillednodes:='';
  1512. {Colour the cpu registers...}
  1513. colourednodes:=[first_supreg..last_supreg];
  1514. for i:=first_supreg to last_supreg do
  1515. colour[i]:=i;
  1516. {Now colour the imaginary registers on the select-stack.}
  1517. for i:=length(selectstack) downto 1 do
  1518. begin
  1519. n:=Tsuperregister(selectstack[i]);
  1520. {Create a list of colours that we cannot assign to n.}
  1521. adj_colours:=[];
  1522. adj:=igraph.adjlist[n];
  1523. if adj<>nil then
  1524. for j:=1 to length(adj^) do
  1525. begin
  1526. w:=adj^[j];
  1527. a:=get_alias(Tsuperregister(w));
  1528. if a in colourednodes then
  1529. include(adj_colours,colour[a]);
  1530. end;
  1531. {Assume a spill by default...}
  1532. spillednodes:=spillednodes+char(n);
  1533. {Search for a colour not in this list.}
  1534. for k:=1 to cpu_registers do
  1535. if not(k in adj_colours) then
  1536. begin
  1537. colour[n]:=k;
  1538. dec(spillednodes[0]); {Colour found: no spill.}
  1539. include(colourednodes,n);
  1540. break;
  1541. end;
  1542. end;
  1543. {Finally colour the nodes that were coalesced.}
  1544. for i:=1 to length(coalescednodes) do
  1545. begin
  1546. n:=Tsuperregister(coalescednodes[i]);
  1547. colour[n]:=colour[get_alias(n)];
  1548. end;
  1549. for i:=first_imreg to maxintreg do
  1550. writeln(i:4,' ',colour[i]:4)
  1551. end;
  1552. procedure Trgobj.colour_registers;
  1553. begin
  1554. repeat
  1555. if length(simplifyworklist)<>0 then
  1556. simplify
  1557. else if not(worklist_moves.empty) then
  1558. coalesce
  1559. else if length(freezeworklist)<>0 then
  1560. freeze
  1561. else if length(spillworklist)<>0 then
  1562. select_spill;
  1563. until (length(simplifyworklist) or
  1564. byte(not(worklist_moves.empty)) or
  1565. length(freezeworklist) or
  1566. length(spillworklist)
  1567. )=0;
  1568. assign_colours;
  1569. end;
  1570. procedure Trgobj.epilogue_colouring;
  1571. begin
  1572. active_moves.destroy;
  1573. active_moves:=nil;
  1574. frozen_moves.destroy;
  1575. frozen_moves:=nil;
  1576. coalesced_moves.destroy;
  1577. coalesced_moves:=nil;
  1578. constrained_moves.destroy;
  1579. constrained_moves:=nil;
  1580. end;
  1581. {$endif newra}
  1582. {****************************************************************************
  1583. TReference
  1584. ****************************************************************************}
  1585. procedure reference_reset(var ref : treference);
  1586. begin
  1587. FillChar(ref,sizeof(treference),0);
  1588. ref.base.enum:=R_INTREGISTER;
  1589. ref.index.enum:=R_INTREGISTER;
  1590. {$ifdef i386}
  1591. ref.segment.enum:=R_INTREGISTER;
  1592. {$endif}
  1593. end;
  1594. procedure reference_reset_old(var ref : treference);
  1595. begin
  1596. FillChar(ref,sizeof(treference),0);
  1597. end;
  1598. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  1599. begin
  1600. reference_reset(ref);
  1601. ref.base:=base;
  1602. ref.offset:=offset;
  1603. end;
  1604. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  1605. begin
  1606. reference_reset(ref);
  1607. ref.symbol:=sym;
  1608. ref.offset:=offset;
  1609. end;
  1610. procedure reference_release(list: taasmoutput; const ref : treference);
  1611. begin
  1612. rg.ungetreference(list,ref);
  1613. end;
  1614. function references_equal(sref : treference;dref : treference):boolean;
  1615. begin
  1616. references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
  1617. end;
  1618. { on most processors , this routine does nothing, overriden currently }
  1619. { only by 80x86 processor. }
  1620. function trgobj.makeregsize(reg: tregister; size: tcgsize): tregister;
  1621. begin
  1622. makeregsize := reg;
  1623. end;
  1624. {****************************************************************************
  1625. TLocation
  1626. ****************************************************************************}
  1627. procedure location_reset(var l : tlocation;lt:TCGLoc;lsize:TCGSize);
  1628. begin
  1629. FillChar(l,sizeof(tlocation),0);
  1630. l.loc:=lt;
  1631. l.size:=lsize;
  1632. case l.loc of
  1633. LOC_REGISTER,LOC_CREGISTER:
  1634. begin
  1635. l.register.enum:=R_INTREGISTER;
  1636. l.registerhigh.enum:=R_INTREGISTER;
  1637. end;
  1638. LOC_REFERENCE,LOC_CREFERENCE:
  1639. begin
  1640. l.reference.base.enum:=R_INTREGISTER;
  1641. l.reference.index.enum:=R_INTREGISTER;
  1642. {$ifdef i386}
  1643. l.reference.segment.enum:=R_INTREGISTER;
  1644. {$endif}
  1645. end;
  1646. end;
  1647. end;
  1648. procedure location_release(list: taasmoutput; const l : tlocation);
  1649. begin
  1650. case l.loc of
  1651. LOC_REGISTER,LOC_CREGISTER :
  1652. begin
  1653. rg.ungetregisterint(list,l.register);
  1654. if l.size in [OS_64,OS_S64] then
  1655. rg.ungetregisterint(list,l.registerhigh);
  1656. end;
  1657. LOC_CREFERENCE,LOC_REFERENCE :
  1658. rg.ungetreference(list, l.reference);
  1659. end;
  1660. end;
  1661. procedure location_freetemp(list:taasmoutput; const l : tlocation);
  1662. begin
  1663. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1664. tg.ungetiftemp(list,l.reference);
  1665. end;
  1666. procedure location_copy(var destloc,sourceloc : tlocation);
  1667. begin
  1668. destloc:=sourceloc;
  1669. end;
  1670. procedure location_swap(var destloc,sourceloc : tlocation);
  1671. var
  1672. swapl : tlocation;
  1673. begin
  1674. swapl := destloc;
  1675. destloc := sourceloc;
  1676. sourceloc := swapl;
  1677. end;
  1678. initialization
  1679. ;
  1680. finalization
  1681. rg.free;
  1682. end.
  1683. {
  1684. $Log$
  1685. Revision 1.37 2003-04-22 23:50:23 peter
  1686. * firstpass uses expectloc
  1687. * checks if there are differences between the expectloc and
  1688. location.loc from secondpass in EXTDEBUG
  1689. Revision 1.36 2003/04/22 10:09:35 daniel
  1690. + Implemented the actual register allocator
  1691. + Scratch registers unavailable when new register allocator used
  1692. + maybe_save/maybe_restore unavailable when new register allocator used
  1693. Revision 1.35 2003/04/21 19:16:49 peter
  1694. * count address regs separate
  1695. Revision 1.34 2003/04/17 16:48:21 daniel
  1696. * Added some code to keep track of move instructions in register
  1697. allocator
  1698. Revision 1.33 2003/04/17 07:50:24 daniel
  1699. * Some work on interference graph construction
  1700. Revision 1.32 2003/03/28 19:16:57 peter
  1701. * generic constructor working for i386
  1702. * remove fixed self register
  1703. * esi added as address register for i386
  1704. Revision 1.31 2003/03/11 21:46:24 jonas
  1705. * lots of new regallocator fixes, both in generic and ppc-specific code
  1706. (ppc compiler still can't compile the linux system unit though)
  1707. Revision 1.30 2003/03/09 21:18:59 olle
  1708. + added cutils to the uses clause
  1709. Revision 1.29 2003/03/08 20:36:41 daniel
  1710. + Added newra version of Ti386shlshrnode
  1711. + Added interference graph construction code
  1712. Revision 1.28 2003/03/08 13:59:16 daniel
  1713. * Work to handle new register notation in ag386nsm
  1714. + Added newra version of Ti386moddivnode
  1715. Revision 1.27 2003/03/08 10:53:48 daniel
  1716. * Created newra version of secondmul in n386add.pas
  1717. Revision 1.26 2003/03/08 08:59:07 daniel
  1718. + $define newra will enable new register allocator
  1719. + getregisterint will return imaginary registers with $newra
  1720. + -sr switch added, will skip register allocation so you can see
  1721. the direct output of the code generator before register allocation
  1722. Revision 1.25 2003/02/26 20:50:45 daniel
  1723. * Fixed ungetreference
  1724. Revision 1.24 2003/02/19 22:39:56 daniel
  1725. * Fixed a few issues
  1726. Revision 1.23 2003/02/19 22:00:14 daniel
  1727. * Code generator converted to new register notation
  1728. - Horribily outdated todo.txt removed
  1729. Revision 1.22 2003/02/02 19:25:54 carl
  1730. * Several bugfixes for m68k target (register alloc., opcode emission)
  1731. + VIS target
  1732. + Generic add more complete (still not verified)
  1733. Revision 1.21 2003/01/08 18:43:57 daniel
  1734. * Tregister changed into a record
  1735. Revision 1.20 2002/10/05 12:43:28 carl
  1736. * fixes for Delphi 6 compilation
  1737. (warning : Some features do not work under Delphi)
  1738. Revision 1.19 2002/08/23 16:14:49 peter
  1739. * tempgen cleanup
  1740. * tt_noreuse temp type added that will be used in genentrycode
  1741. Revision 1.18 2002/08/17 22:09:47 florian
  1742. * result type handling in tcgcal.pass_2 overhauled
  1743. * better tnode.dowrite
  1744. * some ppc stuff fixed
  1745. Revision 1.17 2002/08/17 09:23:42 florian
  1746. * first part of procinfo rewrite
  1747. Revision 1.16 2002/08/06 20:55:23 florian
  1748. * first part of ppc calling conventions fix
  1749. Revision 1.15 2002/08/05 18:27:48 carl
  1750. + more more more documentation
  1751. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  1752. Revision 1.14 2002/08/04 19:06:41 carl
  1753. + added generic exception support (still does not work!)
  1754. + more documentation
  1755. Revision 1.13 2002/07/07 09:52:32 florian
  1756. * powerpc target fixed, very simple units can be compiled
  1757. * some basic stuff for better callparanode handling, far from being finished
  1758. Revision 1.12 2002/07/01 18:46:26 peter
  1759. * internal linker
  1760. * reorganized aasm layer
  1761. Revision 1.11 2002/05/18 13:34:17 peter
  1762. * readded missing revisions
  1763. Revision 1.10 2002/05/16 19:46:44 carl
  1764. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1765. + try to fix temp allocation (still in ifdef)
  1766. + generic constructor calls
  1767. + start of tassembler / tmodulebase class cleanup
  1768. Revision 1.8 2002/04/21 15:23:03 carl
  1769. + makeregsize
  1770. + changeregsize is now a local routine
  1771. Revision 1.7 2002/04/20 21:32:25 carl
  1772. + generic FPC_CHECKPOINTER
  1773. + first parameter offset in stack now portable
  1774. * rename some constants
  1775. + move some cpu stuff to other units
  1776. - remove unused constents
  1777. * fix stacksize for some targets
  1778. * fix generic size problems which depend now on EXTEND_SIZE constant
  1779. Revision 1.6 2002/04/15 19:03:31 carl
  1780. + reg2str -> std_reg2str()
  1781. Revision 1.5 2002/04/06 18:13:01 jonas
  1782. * several powerpc-related additions and fixes
  1783. Revision 1.4 2002/04/04 19:06:04 peter
  1784. * removed unused units
  1785. * use tlocation.size in cg.a_*loc*() routines
  1786. Revision 1.3 2002/04/02 17:11:29 peter
  1787. * tlocation,treference update
  1788. * LOC_CONSTANT added for better constant handling
  1789. * secondadd splitted in multiple routines
  1790. * location_force_reg added for loading a location to a register
  1791. of a specified size
  1792. * secondassignment parses now first the right and then the left node
  1793. (this is compatible with Kylix). This saves a lot of push/pop especially
  1794. with string operations
  1795. * adapted some routines to use the new cg methods
  1796. Revision 1.2 2002/04/01 19:24:25 jonas
  1797. * fixed different parameter name in interface and implementation
  1798. declaration of a method (only 1.0.x detected this)
  1799. Revision 1.1 2002/03/31 20:26:36 jonas
  1800. + a_loadfpu_* and a_loadmm_* methods in tcg
  1801. * register allocation is now handled by a class and is mostly processor
  1802. independent (+rgobj.pas and i386/rgcpu.pas)
  1803. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1804. * some small improvements and fixes to the optimizer
  1805. * some register allocation fixes
  1806. * some fpuvaroffset fixes in the unary minus node
  1807. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1808. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1809. also better optimizable)
  1810. * fixed and optimized register saving/restoring for new/dispose nodes
  1811. * LOC_FPU locations now also require their "register" field to be set to
  1812. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1813. - list field removed of the tnode class because it's not used currently
  1814. and can cause hard-to-find bugs
  1815. }