rgobj.pas 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  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 processor
  33. has a limited amount of registers. Therefore we must reduce the amount of
  34. registers until there are less enough to fit into the processors registers.
  35. Registers can interfere or not interfere. If two imaginary registers interfere
  36. they cannot be placed into the same psysical register. Reduction of registers
  37. is done by:
  38. - "coalescing" Two registers that do not interfere are combined
  39. into one register.
  40. - "spilling" A register is changed into a memory location and the generated
  41. code is modified to use the memory location instead of the register.
  42. Register allocation is a graph colouring problem. Each register is a colour, and
  43. if two registers interfere there is a connection between them in the graph.
  44. In addition to the imaginary registers in the code generator, the psysical
  45. CPU registers are also present in this graph. This allows us to make
  46. interferences between imaginary registers and cpu registers. This is very
  47. usefull for describing archtectural constrains, like for example that
  48. the div instruction modifies edx, so variables that are in use at that time
  49. cannot be stored into edx. This can be modelled by making edx interfere
  50. with those variables.
  51. *******************************************************************************}
  52. unit rgobj;
  53. interface
  54. uses
  55. cutils, cpubase,
  56. cpuinfo,
  57. aasmbase,aasmtai,aasmcpu,
  58. cclasses,globtype,cginfo,cgbase,node
  59. {$ifdef delphi}
  60. ,dmisc
  61. {$endif}
  62. ;
  63. type
  64. regvar_longintarray = array[firstreg..lastreg] of longint;
  65. regvarint_longintarray = array[first_supreg..last_supreg] of longint;
  66. regvar_booleanarray = array[firstreg..lastreg] of boolean;
  67. regvar_ptreearray = array[firstreg..lastreg] of tnode;
  68. tpushedsavedloc = record
  69. case byte of
  70. 0: (pushed: boolean);
  71. 1: (ofs: longint);
  72. end;
  73. tpushedsaved = array[firstreg..lastreg] of tpushedsavedloc;
  74. Tpushedsavedint = array[first_supreg..last_supreg] of Tpushedsavedloc;
  75. Tinterferencebitmap=array[Tsuperregister] of set of Tsuperregister;
  76. Tinterferenceadjlist=array[Tsuperregister] of Pstring;
  77. Tinterferencegraph=record
  78. bitmap:Tinterferencebitmap;
  79. adjlist:Tinterferenceadjlist;
  80. end;
  81. Pinterferencegraph=^Tinterferencegraph;
  82. {#
  83. This class implements the abstract register allocator
  84. It is used by the code generator to allocate and free
  85. registers which might be valid across nodes. It also
  86. contains utility routines related to registers.
  87. Some of the methods in this class should be overriden
  88. by cpu-specific implementations.
  89. }
  90. trgobj = class
  91. { The "usableregsxxx" contain all registers of type "xxx" that }
  92. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  93. { contain all registers of type "xxx" that aren't currenly }
  94. { allocated }
  95. lastintreg:Tsuperregister;
  96. unusedregsint,usableregsint:Tsupregset;
  97. unusedregsfpu,usableregsfpu : tregisterset;
  98. unusedregsmm,usableregsmm : tregisterset;
  99. { these counters contain the number of elements in the }
  100. { unusedregsxxx/usableregsxxx sets }
  101. countunusedregsint,
  102. countunusedregsfpu,
  103. countunusedregsmm : byte;
  104. countusableregsint,
  105. countusableregsfpu,
  106. countusableregsmm : byte;
  107. { Contains the registers which are really used by the proc itself.
  108. It doesn't take care of registers used by called procedures
  109. }
  110. usedbyproc,
  111. usedinproc : tregisterset;
  112. usedintbyproc,usedintinproc:Tsupregset;
  113. reg_pushes : regvar_longintarray;
  114. reg_pushes_int : regvarint_longintarray;
  115. is_reg_var : regvar_booleanarray;
  116. is_reg_var_int:Tsupregset;
  117. regvar_loaded: regvar_booleanarray;
  118. regvar_loaded_int: Tsupregset;
  119. { tries to hold the amount of times which the current tree is processed }
  120. t_times: longint;
  121. constructor create;
  122. {# Allocate a general purpose register
  123. An internalerror will be generated if there
  124. is no more free registers which can be allocated
  125. }
  126. function getregisterint(list:Taasmoutput;size:Tcgsize):Tregister;virtual;
  127. {# Free a general purpose register
  128. @param(r register to free)
  129. }
  130. procedure ungetregisterint(list: taasmoutput; r : tregister); virtual;
  131. {# Allocate a floating point register
  132. An internalerror will be generated if there
  133. is no more free registers which can be allocated
  134. }
  135. function getregisterfpu(list: taasmoutput) : tregister; virtual;
  136. {# Free a floating point register
  137. @param(r register to free)
  138. }
  139. procedure ungetregisterfpu(list: taasmoutput; r : tregister); virtual;
  140. function getregistermm(list: taasmoutput) : tregister; virtual;
  141. procedure ungetregistermm(list: taasmoutput; r : tregister); virtual;
  142. {# Allocate an address register.
  143. Address registers are the only registers which can
  144. be used as a base register in references (treference).
  145. On most cpu's this is the same as a general purpose
  146. register.
  147. An internalerror will be generated if there
  148. is no more free registers which can be allocated
  149. }
  150. function getaddressregister(list:Taasmoutput):Tregister;virtual;
  151. procedure ungetaddressregister(list: taasmoutput; r: tregister); virtual;
  152. {# Verify if the specified register is an address or
  153. general purpose register. Returns TRUE if @var(reg)
  154. is an adress register.
  155. This routine should only be used to check on
  156. general purpose or address register. It will
  157. not work on multimedia or floating point
  158. registers
  159. @param(reg register to verify)
  160. }
  161. function isaddressregister(reg: tregister): boolean; virtual;
  162. {# Tries to allocate the passed register, if possible
  163. @param(r specific register to allocate)
  164. }
  165. function getexplicitregisterint(list:Taasmoutput;r:Tnewregister):Tregister;virtual;
  166. {# Tries to allocate the passed fpu register, if possible
  167. @param(r specific register to allocate)
  168. }
  169. function getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  170. {# Deallocate any kind of register }
  171. procedure ungetregister(list: taasmoutput; r : tregister); virtual;
  172. {# Deallocate all registers which are allocated
  173. in the specified reference. On most systems,
  174. this will free the base and index registers
  175. of the specified reference.
  176. @param(ref reference which must have its registers freed)
  177. }
  178. procedure ungetreference(list: taasmoutput; const ref : treference); virtual;
  179. {# Reset the register allocator information (usable registers etc) }
  180. procedure cleartempgen;virtual;
  181. {# Convert a register to a specified register size, and return that register size }
  182. function makeregsize(reg: tregister; size: tcgsize): tregister; virtual;
  183. {# saves register variables (restoring happens automatically) }
  184. procedure saveintregvars(list:Taasmoutput;const s:Tsupregset);
  185. procedure saveotherregvars(list:Taasmoutput;const s:Tregisterset);
  186. {# Saves in temporary references (allocated via the temp. allocator)
  187. the registers defined in @var(s). The registers are only saved
  188. if they are currently in use, otherwise they are left as is.
  189. On processors which have instructions which manipulate the stack,
  190. this routine should be overriden for performance reasons.
  191. @param(list) List to add the instruction to
  192. @param(saved) Array of saved register information
  193. @param(s) Registers which might require saving
  194. }
  195. procedure saveusedintregisters(list:Taasmoutput;
  196. var saved:Tpushedsavedint;
  197. const s:Tsupregset);virtual;
  198. procedure saveusedotherregisters(list:Taasmoutput;
  199. var saved:Tpushedsaved;
  200. const s:Tregisterset);virtual;
  201. {# Restores the registers which were saved with a call
  202. to @var(saveusedregisters).
  203. On processors which have instructions which manipulate the stack,
  204. this routine should be overriden for performance reasons.
  205. }
  206. procedure restoreusedintregisters(list:Taasmoutput;
  207. const saved:Tpushedsavedint);virtual;
  208. procedure restoreusedotherregisters(list:Taasmoutput;
  209. const saved:Tpushedsaved);virtual;
  210. { used when deciding which registers to use for regvars }
  211. procedure incrementintregisterpushed(const s:Tsupregset);
  212. procedure incrementotherregisterpushed(const s: tregisterset);
  213. procedure clearregistercount;
  214. procedure resetusableregisters;virtual;
  215. procedure makeregvarint(reg:Tnewregister);
  216. procedure makeregvarother(reg:Tregister);
  217. procedure saveStateForInline(var state: pointer);virtual;
  218. procedure restoreStateAfterInline(var state: pointer);virtual;
  219. procedure saveUnusedState(var state: pointer);virtual;
  220. procedure restoreUnusedState(var state: pointer);virtual;
  221. protected
  222. {$ifdef newra}
  223. igraph:Tinterferencegraph;
  224. {$endif}
  225. { the following two contain the common (generic) code for all }
  226. { get- and ungetregisterxxx functions/procedures }
  227. function getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  228. var unusedregs:Tregisterset; var countunusedregs: byte): tregister;
  229. function getregistergenint(list:Taasmoutput;subreg:Tsubregister;
  230. const lowreg,highreg:Tsuperregister;
  231. var fusedinproc,fusedbyproc,unusedregs:Tsupregset;
  232. var countunusedregs:byte):Tregister;
  233. procedure ungetregistergen(list: taasmoutput; const r: tregister;
  234. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  235. procedure ungetregistergenint(list:taasmoutput;const r:Tregister;
  236. const usableregs:Tsupregset;
  237. var unusedregs:Tsupregset;
  238. var countunusedregs:byte);
  239. {$ifdef TEMPREGDEBUG}
  240. reg_user : regvar_ptreearray;
  241. reg_releaser : regvar_ptreearray;
  242. {$endif TEMPREGDEBUG}
  243. {$ifdef TEMPREGDEBUG}
  244. procedure testregisters;
  245. {$endif TEMPREGDEBUGx}
  246. {$ifdef newra}
  247. procedure add_edge(u,v:Tsuperregister);
  248. procedure add_edges_used(u:Tsuperregister);
  249. {$endif}
  250. end;
  251. const
  252. {# This value is used in tsaved. If the array value is equal
  253. to this, then this means that this register is not used.
  254. }
  255. reg_not_saved = $7fffffff;
  256. var
  257. {# This is the class instance used to access the register allocator class }
  258. rg: trgobj;
  259. { trerefence handling }
  260. {# Clear to zero a treference }
  261. procedure reference_reset(var ref : treference);
  262. procedure reference_reset_old(var ref : treference);
  263. {# Clear to zero a treference, and set is base address
  264. to base register.
  265. }
  266. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  267. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  268. procedure reference_release(list: taasmoutput; const ref : treference);
  269. { This routine verifies if two references are the same, and
  270. if so, returns TRUE, otherwise returns false.
  271. }
  272. function references_equal(sref : treference;dref : treference) : boolean;
  273. { tlocation handling }
  274. procedure location_reset(var l : tlocation;lt:TLoc;lsize:TCGSize);
  275. procedure location_release(list: taasmoutput; const l : tlocation);
  276. procedure location_freetemp(list: taasmoutput; const l : tlocation);
  277. procedure location_copy(var destloc,sourceloc : tlocation);
  278. procedure location_swap(var destloc,sourceloc : tlocation);
  279. type
  280. psavedstate = ^tsavedstate;
  281. tsavedstate = record
  282. unusedregsint,usableregsint : Tsupregset;
  283. unusedregsaddr,usableregsaddr : Tsupregset;
  284. unusedregsfpu,usableregsfpu : tregisterset;
  285. unusedregsmm,usableregsmm : tregisterset;
  286. countunusedregsint,
  287. countunusedregsaddr,
  288. countunusedregsfpu,
  289. countunusedregsmm : byte;
  290. countusableregsint,
  291. countusableregsfpu,
  292. countusableregsmm : byte;
  293. { contains the registers which are really used by the proc itself }
  294. usedbyproc,
  295. usedinproc : tregisterset;
  296. reg_pushes : regvar_longintarray;
  297. is_reg_var : regvar_booleanarray;
  298. is_reg_var_int : Tsupregset;
  299. regvar_loaded: regvar_booleanarray;
  300. regvar_loaded_int: Tsupregset;
  301. {$ifdef TEMPREGDEBUG}
  302. reg_user : regvar_ptreearray;
  303. reg_releaser : regvar_ptreearray;
  304. {$endif TEMPREGDEBUG}
  305. end;
  306. punusedstate = ^tunusedstate;
  307. tunusedstate = record
  308. unusedregsint : Tsupregset;
  309. unusedregsaddr : Tsupregset;
  310. unusedregsfpu : tregisterset;
  311. unusedregsmm : tregisterset;
  312. countunusedregsint,
  313. countunusedregsaddr,
  314. countunusedregsfpu,
  315. countunusedregsmm : byte;
  316. end;
  317. implementation
  318. uses
  319. systems,
  320. globals,verbose,
  321. cgobj,tgobj,regvars;
  322. constructor trgobj.create;
  323. begin
  324. usedinproc := [];
  325. usedbyproc:=[];
  326. t_times := 0;
  327. resetusableregisters;
  328. lastintreg:=0;
  329. {$ifdef TEMPREGDEBUG}
  330. fillchar(reg_user,sizeof(reg_user),0);
  331. fillchar(reg_releaser,sizeof(reg_releaser),0);
  332. {$endif TEMPREGDEBUG}
  333. {$ifdef newra}
  334. fillchar(igraph,sizeof(igraph),0);
  335. {$endif}
  336. end;
  337. function trgobj.getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  338. var unusedregs: tregisterset; var countunusedregs: byte): tregister;
  339. var
  340. i: Toldregister;
  341. r: Tregister;
  342. begin
  343. for i:=lowreg to highreg do
  344. begin
  345. if i in unusedregs then
  346. begin
  347. exclude(unusedregs,i);
  348. include(usedinproc,i);
  349. include(usedbyproc,i);
  350. dec(countunusedregs);
  351. r.enum:=i;
  352. list.concat(tai_regalloc.alloc(r));
  353. result := r;
  354. exit;
  355. end;
  356. end;
  357. internalerror(10);
  358. end;
  359. function Trgobj.getregistergenint(list:Taasmoutput;
  360. subreg:Tsubregister;
  361. const lowreg,highreg:Tsuperregister;
  362. var fusedinproc,fusedbyproc,unusedregs:Tsupregset;
  363. var countunusedregs:byte):Tregister;
  364. var i:Tsuperregister;
  365. r:Tregister;
  366. begin
  367. if not (lastintreg in [lowreg..highreg]) then
  368. lastintreg:=lowreg;
  369. i:=lastintreg;
  370. repeat
  371. if i=highreg then
  372. i:=lowreg
  373. else
  374. inc(i);
  375. if i in unusedregs then
  376. begin
  377. exclude(unusedregs,i);
  378. include(fusedinproc,i);
  379. include(fusedbyproc,i);
  380. dec(countunusedregs);
  381. r.enum:=R_INTREGISTER;
  382. r.number:=i shl 8 or subreg;
  383. list.concat(Tai_regalloc.alloc(r));
  384. result:=r;
  385. lastintreg:=i;
  386. {$ifdef newra}
  387. add_edges_used(i);
  388. {$endif}
  389. exit;
  390. end;
  391. until i=lastintreg;
  392. internalerror(10);
  393. end;
  394. procedure trgobj.ungetregistergen(list: taasmoutput; const r: tregister;
  395. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  396. begin
  397. if r.enum>lastreg then
  398. internalerror(2003010801);
  399. { takes much time }
  400. if not(r.enum in usableregs) then
  401. exit;
  402. {$ifdef TEMPREGDEBUG}
  403. if (r.enum in unusedregs) then
  404. {$ifdef EXTTEMPREGDEBUG}
  405. begin
  406. Comment(V_Debug,'register freed twice '+std_reg2str[r.enum]);
  407. testregisters32;
  408. exit;
  409. end
  410. {$else EXTTEMPREGDEBUG}
  411. exit
  412. {$endif EXTTEMPREGDEBUG}
  413. else
  414. {$endif TEMPREGDEBUG}
  415. inc(countunusedregs);
  416. include(unusedregs,r.enum);
  417. list.concat(tai_regalloc.dealloc(r));
  418. end;
  419. procedure trgobj.ungetregistergenint(list:taasmoutput;const r:Tregister;
  420. const usableregs:Tsupregset;
  421. var unusedregs:Tsupregset;
  422. var countunusedregs:byte);
  423. var supreg:Tsuperregister;
  424. begin
  425. if r.enum<=lastreg then
  426. internalerror(2003010803);
  427. supreg:=r.number shr 8;
  428. { takes much time }
  429. {$ifndef newra}
  430. if not(supreg in usableregs) then
  431. exit;
  432. {$endif}
  433. {$ifdef TEMPREGDEBUG}
  434. if (supreg in unusedregs) then
  435. {$ifdef EXTTEMPREGDEBUG}
  436. begin
  437. comment(v_debug,'register freed twice '+supreg_name(supreg));
  438. testregisters32;
  439. exit;
  440. end
  441. {$else EXTTEMPREGDEBUG}
  442. exit
  443. {$endif EXTTEMPREGDEBUG}
  444. else
  445. {$endif TEMPREGDEBUG}
  446. inc(countunusedregs);
  447. include(unusedregs,supreg);
  448. list.concat(tai_regalloc.dealloc(r));
  449. end;
  450. function trgobj.getregisterint(list:taasmoutput;size:Tcgsize):Tregister;
  451. var subreg:Tsubregister;
  452. begin
  453. if countunusedregsint=0 then
  454. internalerror(10);
  455. {$ifdef TEMPREGDEBUG}
  456. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  457. internalerror(10);
  458. {$endif TEMPREGDEBUG}
  459. {$ifdef EXTTEMPREGDEBUG}
  460. if curptree^^.usableregs-countunusedregsint>curptree^^.reallyusedregs then
  461. curptree^^.reallyusedregs:=curptree^^.usableregs-countunusedregsint;
  462. {$endif EXTTEMPREGDEBUG}
  463. subreg:=cgsize2subreg(size);
  464. result:=getregistergenint(list,
  465. subreg,
  466. {$ifdef newra}
  467. first_imreg,
  468. last_imreg,
  469. {$else}
  470. first_supreg,
  471. last_supreg,
  472. {$endif}
  473. usedintbyproc,
  474. usedintinproc,
  475. unusedregsint,
  476. countunusedregsint);
  477. {$ifdef TEMPREGDEBUG}
  478. reg_user[result]:=curptree^;
  479. testregisters32;
  480. {$endif TEMPREGDEBUG}
  481. end;
  482. procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
  483. begin
  484. ungetregistergenint(list,r,usableregsint,unusedregsint,
  485. countunusedregsint);
  486. {$ifdef TEMPREGDEBUG}
  487. reg_releaser[r]:=curptree^;
  488. testregisters32;
  489. {$endif TEMPREGDEBUG}
  490. end;
  491. { tries to allocate the passed register, if possible }
  492. function trgobj.getexplicitregisterint(list:Taasmoutput;r:Tnewregister):Tregister;
  493. var r2:Tregister;
  494. begin
  495. if (r shr 8) in unusedregsint then
  496. begin
  497. dec(countunusedregsint);
  498. {$ifdef TEMPREGDEBUG}
  499. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  500. internalerror(10);
  501. reg_user[r shr 8]:=curptree^;
  502. {$endif TEMPREGDEBUG}
  503. exclude(unusedregsint,r shr 8);
  504. include(usedintinproc,r shr 8);
  505. include(usedintbyproc,r shr 8);
  506. r2.enum:=R_INTREGISTER;
  507. r2.number:=r;
  508. list.concat(tai_regalloc.alloc(r2));
  509. getexplicitregisterint:=r2;
  510. {$ifdef TEMPREGDEBUG}
  511. testregisters32;
  512. {$endif TEMPREGDEBUG}
  513. end
  514. else
  515. { getexplicitregisterint:=getregisterint(list,r and $ff);}
  516. {$ifndef i386}
  517. // not very cleanm I know :/ The self pointer is allocated a lot
  518. // more than necessary (in tcgselfnode.pass_2), but a lot of those
  519. // allocations are necessary for the optimizer.
  520. // The i386 doesn't care, probably because esi isn't a normal
  521. // allocatable register (JM)
  522. if (r <> NR_SELF_POINTER_REG) then
  523. {$endif i386}
  524. internalerror(200301103);
  525. end;
  526. { tries to allocate the passed register, if possible }
  527. function trgobj.getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  528. var r2:Tregister;
  529. begin
  530. if r in unusedregsfpu then
  531. begin
  532. dec(countunusedregsfpu);
  533. {$ifdef TEMPREGDEBUG}
  534. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  535. internalerror(10);
  536. reg_user[r]:=curptree^;
  537. {$endif TEMPREGDEBUG}
  538. exclude(unusedregsfpu,r);
  539. include(usedinproc,r);
  540. include(usedbyproc,r);
  541. r2.enum:=r;
  542. list.concat(tai_regalloc.alloc(r2));
  543. getexplicitregisterfpu:=r2;
  544. {$ifdef TEMPREGDEBUG}
  545. testregisters32;
  546. {$endif TEMPREGDEBUG}
  547. end
  548. else
  549. getexplicitregisterfpu:=getregisterfpu(list);
  550. end;
  551. function trgobj.getregisterfpu(list: taasmoutput) : tregister;
  552. begin
  553. if countunusedregsfpu=0 then
  554. internalerror(10);
  555. result := getregistergen(list,firstsavefpureg,lastsavefpureg,
  556. unusedregsfpu,countunusedregsfpu);
  557. end;
  558. procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister);
  559. begin
  560. ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
  561. countunusedregsfpu);
  562. end;
  563. function trgobj.getregistermm(list: taasmoutput) : tregister;
  564. begin
  565. if countunusedregsmm=0 then
  566. internalerror(10);
  567. result := getregistergen(list,firstsavemmreg,lastsavemmreg,
  568. unusedregsmm,countunusedregsmm);
  569. end;
  570. procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
  571. begin
  572. ungetregistergen(list,r,usableregsmm,unusedregsmm,
  573. countunusedregsmm);
  574. end;
  575. function trgobj.getaddressregister(list:Taasmoutput): tregister;
  576. begin
  577. {An address register is OS_INT per definition.}
  578. result := getregisterint(list,OS_INT);
  579. end;
  580. procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
  581. begin
  582. ungetregisterint(list,r);
  583. end;
  584. function trgobj.isaddressregister(reg: tregister): boolean;
  585. begin
  586. result := true;
  587. end;
  588. procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
  589. begin
  590. if r.enum=R_NO then
  591. exit;
  592. if r.enum>lastreg then
  593. internalerror(200301081);
  594. if r.enum in intregs then
  595. ungetregisterint(list,r)
  596. else if r.enum in fpuregs then
  597. ungetregisterfpu(list,r)
  598. else if r.enum in mmregs then
  599. ungetregistermm(list,r)
  600. else if r.enum in addrregs then
  601. ungetaddressregister(list,r)
  602. else internalerror(2002070602);
  603. end;
  604. procedure Trgobj.cleartempgen;
  605. var i:Tsuperregister;
  606. begin
  607. countunusedregsint:=countusableregsint;
  608. countunusedregsfpu:=countusableregsfpu;
  609. countunusedregsmm:=countusableregsmm;
  610. {$ifdef newra}
  611. unusedregsint:=[0..255];
  612. {$else}
  613. unusedregsint:=usableregsint;
  614. {$endif}
  615. unusedregsfpu:=usableregsfpu;
  616. unusedregsmm:=usableregsmm;
  617. {$ifdef newra}
  618. for i:=low(Tsuperregister) to high(Tsuperregister) do
  619. if igraph.adjlist[i]<>nil then
  620. dispose(igraph.adjlist[i]);
  621. fillchar(igraph,sizeof(igraph),0);
  622. {$endif}
  623. end;
  624. procedure trgobj.ungetreference(list : taasmoutput; const ref : treference);
  625. begin
  626. if ref.base.number<>NR_NO then
  627. ungetregisterint(list,ref.base);
  628. if ref.index.number<>NR_NO then
  629. ungetregisterint(list,ref.index);
  630. end;
  631. procedure trgobj.saveintregvars(list:Taasmoutput;const s:Tsupregset);
  632. var r:Tsuperregister;
  633. begin
  634. if not(cs_regalloc in aktglobalswitches) then
  635. exit;
  636. for r:=firstsaveintreg to lastsaveintreg do
  637. if (r in is_reg_var_int) and
  638. (r in s) then
  639. store_regvar_int(list,r);
  640. end;
  641. procedure trgobj.saveotherregvars(list: taasmoutput; const s: tregisterset);
  642. var
  643. r: Tregister;
  644. begin
  645. if not(cs_regalloc in aktglobalswitches) then
  646. exit;
  647. if firstsavefpureg <> R_NO then
  648. for r.enum := firstsavefpureg to lastsavefpureg do
  649. if is_reg_var[r.enum] and
  650. (r.enum in s) then
  651. store_regvar(list,r);
  652. if firstsavemmreg <> R_NO then
  653. for r.enum := firstsavemmreg to lastsavemmreg do
  654. if is_reg_var[r.enum] and
  655. (r.enum in s) then
  656. store_regvar(list,r);
  657. end;
  658. procedure trgobj.saveusedintregisters(list:Taasmoutput;
  659. var saved:Tpushedsavedint;
  660. const s:Tsupregset);
  661. var r:Tsuperregister;
  662. r2:Tregister;
  663. hr : treference;
  664. begin
  665. usedintinproc:=usedintinproc+s;
  666. for r:=firstsaveintreg to lastsaveintreg do
  667. begin
  668. saved[r].ofs:=reg_not_saved;
  669. { if the register is used by the calling subroutine and if }
  670. { it's not a regvar (those are handled separately) }
  671. if not (r in is_reg_var_int) and
  672. (r in s) and
  673. { and is present in use }
  674. not(r in unusedregsint) then
  675. begin
  676. { then save it }
  677. tg.GetTemp(list,sizeof(aword),tt_persistant,hr);
  678. saved[r].ofs:=hr.offset;
  679. r2.enum:=R_INTREGISTER;
  680. r2.number:=r shl 8 or R_SUBWHOLE;
  681. cg.a_load_reg_ref(list,OS_INT,r2,hr);
  682. cg.a_reg_dealloc(list,r2);
  683. include(unusedregsint,r);
  684. inc(countunusedregsint);
  685. end;
  686. end;
  687. {$ifdef TEMPREGDEBUG}
  688. testregisters32;
  689. {$endif TEMPREGDEBUG}
  690. end;
  691. procedure trgobj.saveusedotherregisters(list: taasmoutput;
  692. var saved : tpushedsaved; const s: tregisterset);
  693. var
  694. r : tregister;
  695. hr : treference;
  696. begin
  697. usedinproc:=usedinproc + s;
  698. { don't try to save the fpu registers if not desired (e.g. for }
  699. { the 80x86) }
  700. if firstsavefpureg <> R_NO then
  701. for r.enum:=firstsavefpureg to lastsavefpureg do
  702. begin
  703. saved[r.enum].ofs:=reg_not_saved;
  704. { if the register is used by the calling subroutine and if }
  705. { it's not a regvar (those are handled separately) }
  706. if not is_reg_var[r.enum] and
  707. (r.enum in s) and
  708. { and is present in use }
  709. not(r.enum in unusedregsfpu) then
  710. begin
  711. { then save it }
  712. tg.GetTemp(list,extended_size,tt_persistant,hr);
  713. saved[r.enum].ofs:=hr.offset;
  714. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  715. cg.a_reg_dealloc(list,r);
  716. include(unusedregsfpu,r.enum);
  717. inc(countunusedregsfpu);
  718. end;
  719. end;
  720. { don't save the vector registers if there's no support for them }
  721. if firstsavemmreg <> R_NO then
  722. for r.enum:=firstsavemmreg to lastsavemmreg do
  723. begin
  724. saved[r.enum].ofs:=reg_not_saved;
  725. { if the register is in use and if it's not a regvar (those }
  726. { are handled separately), save it }
  727. if not is_reg_var[r.enum] and
  728. (r.enum in s) and
  729. { and is present in use }
  730. not(r.enum in unusedregsmm) then
  731. begin
  732. { then save it }
  733. tg.GetTemp(list,mmreg_size,tt_persistant,hr);
  734. saved[r.enum].ofs:=hr.offset;
  735. cg.a_loadmm_reg_ref(list,r,hr);
  736. cg.a_reg_dealloc(list,r);
  737. include(unusedregsmm,r.enum);
  738. inc(countunusedregsmm);
  739. end;
  740. end;
  741. {$ifdef TEMPREGDEBUG}
  742. testregisters32;
  743. {$endif TEMPREGDEBUG}
  744. end;
  745. procedure trgobj.restoreusedintregisters(list:Taasmoutput;
  746. const saved:Tpushedsavedint);
  747. var r:Tsuperregister;
  748. r2:Tregister;
  749. hr:Treference;
  750. begin
  751. for r:=lastsaveintreg downto firstsaveintreg do
  752. begin
  753. if saved[r].ofs <> reg_not_saved then
  754. begin
  755. r2.enum:=R_INTREGISTER;
  756. r2.number:=NR_FRAME_POINTER_REG;
  757. reference_reset_base(hr,r2,saved[r].ofs);
  758. r2.enum:=R_INTREGISTER;
  759. r2.number:=r shl 8 or R_SUBWHOLE;
  760. cg.a_reg_alloc(list,r2);
  761. cg.a_load_ref_reg(list,OS_INT,hr,r2);
  762. if not (r in unusedregsint) then
  763. { internalerror(10)
  764. in n386cal we always save/restore the reg *state*
  765. using save/restoreunusedstate -> the current state
  766. may not be real (JM) }
  767. else
  768. begin
  769. dec(countunusedregsint);
  770. exclude(unusedregsint,r);
  771. end;
  772. tg.UnGetTemp(list,hr);
  773. end;
  774. end;
  775. {$ifdef TEMPREGDEBUG}
  776. testregisters32;
  777. {$endif TEMPREGDEBUG}
  778. end;
  779. procedure trgobj.restoreusedotherregisters(list : taasmoutput;
  780. const saved : tpushedsaved);
  781. var
  782. r,r2 : tregister;
  783. hr : treference;
  784. begin
  785. if firstsavemmreg <> R_NO then
  786. for r.enum:=lastsavemmreg downto firstsavemmreg do
  787. begin
  788. if saved[r.enum].ofs <> reg_not_saved then
  789. begin
  790. r2.enum:=R_INTREGISTER;
  791. r2.number:=NR_FRAME_POINTER_REG;
  792. reference_reset_base(hr,r2,saved[r.enum].ofs);
  793. cg.a_reg_alloc(list,r);
  794. cg.a_loadmm_ref_reg(list,hr,r);
  795. if not (r.enum in unusedregsmm) then
  796. { internalerror(10)
  797. in n386cal we always save/restore the reg *state*
  798. using save/restoreunusedstate -> the current state
  799. may not be real (JM) }
  800. else
  801. begin
  802. dec(countunusedregsmm);
  803. exclude(unusedregsmm,r.enum);
  804. end;
  805. tg.UnGetTemp(list,hr);
  806. end;
  807. end;
  808. if firstsavefpureg <> R_NO then
  809. for r.enum:=lastsavefpureg downto firstsavefpureg do
  810. begin
  811. if saved[r.enum].ofs <> reg_not_saved then
  812. begin
  813. r2.enum:=R_INTREGISTER;
  814. r2.number:=NR_FRAME_POINTER_REG;
  815. reference_reset_base(hr,r2,saved[r.enum].ofs);
  816. cg.a_reg_alloc(list,r);
  817. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  818. if not (r.enum in unusedregsfpu) then
  819. { internalerror(10)
  820. in n386cal we always save/restore the reg *state*
  821. using save/restoreunusedstate -> the current state
  822. may not be real (JM) }
  823. else
  824. begin
  825. dec(countunusedregsfpu);
  826. exclude(unusedregsfpu,r.enum);
  827. end;
  828. tg.UnGetTemp(list,hr);
  829. end;
  830. end;
  831. {$ifdef TEMPREGDEBUG}
  832. testregisters32;
  833. {$endif TEMPREGDEBUG}
  834. end;
  835. procedure trgobj.incrementintregisterpushed(const s:Tsupregset);
  836. var regi:Tsuperregister;
  837. begin
  838. for regi:=firstsaveintreg to lastsaveintreg do
  839. begin
  840. if (regi in s) then
  841. inc(reg_pushes_int[regi],t_times*2);
  842. end;
  843. end;
  844. procedure trgobj.incrementotherregisterpushed(const s:Tregisterset);
  845. var
  846. regi : Toldregister;
  847. begin
  848. if firstsavefpureg <> R_NO then
  849. for regi:=firstsavefpureg to lastsavefpureg do
  850. begin
  851. if (regi in s) then
  852. inc(reg_pushes[regi],t_times*2);
  853. end;
  854. if firstsavemmreg <> R_NO then
  855. for regi:=firstsavemmreg to lastsavemmreg do
  856. begin
  857. if (regi in s) then
  858. inc(reg_pushes[regi],t_times*2);
  859. end;
  860. end;
  861. procedure trgobj.clearregistercount;
  862. begin
  863. fillchar(reg_pushes,sizeof(reg_pushes),0);
  864. fillchar(is_reg_var,sizeof(is_reg_var),false);
  865. is_reg_var_int:=[];
  866. fillchar(regvar_loaded,sizeof(regvar_loaded),false);
  867. regvar_loaded_int:=[];
  868. end;
  869. procedure trgobj.resetusableregisters;
  870. begin
  871. { initialize fields with constant values from cpubase }
  872. countusableregsint := cpubase.c_countusableregsint;
  873. countusableregsfpu := cpubase.c_countusableregsfpu;
  874. countusableregsmm := cpubase.c_countusableregsmm;
  875. usableregsint := cpubase.usableregsint;
  876. usableregsfpu := cpubase.usableregsfpu;
  877. usableregsmm := cpubase.usableregsmm;
  878. clearregistercount;
  879. end;
  880. procedure trgobj.makeregvarint(reg:Tnewregister);
  881. var supreg:Tsuperregister;
  882. begin
  883. supreg:=reg shr 8;
  884. dec(countusableregsint);
  885. dec(countunusedregsint);
  886. exclude(usableregsint,reg);
  887. exclude(unusedregsint,reg);
  888. include(is_reg_var_int,supreg);
  889. end;
  890. procedure trgobj.makeregvarother(reg: tregister);
  891. begin
  892. if reg.enum>lastreg then
  893. internalerror(200301081);
  894. if reg.enum in intregs then
  895. internalerror(200301151)
  896. else if reg.enum in fpuregs then
  897. begin
  898. dec(countusableregsfpu);
  899. dec(countunusedregsfpu);
  900. exclude(usableregsfpu,reg.enum);
  901. exclude(unusedregsfpu,reg.enum);
  902. end
  903. else if reg.enum in mmregs then
  904. begin
  905. dec(countusableregsmm);
  906. dec(countunusedregsmm);
  907. exclude(usableregsmm,reg.enum);
  908. exclude(unusedregsmm,reg.enum);
  909. end;
  910. is_reg_var[reg.enum]:=true;
  911. end;
  912. {$ifdef TEMPREGDEBUG}
  913. procedure trgobj.testregisters;
  914. var
  915. r: tregister;
  916. test : byte;
  917. begin
  918. test:=0;
  919. for r := firstsaveintreg to lastsaveintreg do
  920. inc(test,ord(r in unusedregsint));
  921. if test<>countunusedregsint then
  922. internalerror(10);
  923. end;
  924. {$endif TEMPREGDEBUG}
  925. procedure trgobj.saveStateForInline(var state: pointer);
  926. begin
  927. new(psavedstate(state));
  928. psavedstate(state)^.unusedregsint := unusedregsint;
  929. psavedstate(state)^.usableregsint := usableregsint;
  930. psavedstate(state)^.unusedregsfpu := unusedregsfpu;
  931. psavedstate(state)^.usableregsfpu := usableregsfpu;
  932. psavedstate(state)^.unusedregsmm := unusedregsmm;
  933. psavedstate(state)^.usableregsmm := usableregsmm;
  934. psavedstate(state)^.countunusedregsint := countunusedregsint;
  935. psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  936. psavedstate(state)^.countunusedregsmm := countunusedregsmm;
  937. psavedstate(state)^.countusableregsint := countusableregsint;
  938. psavedstate(state)^.countusableregsfpu := countusableregsfpu;
  939. psavedstate(state)^.countusableregsmm := countusableregsmm;
  940. psavedstate(state)^.usedinproc := usedinproc;
  941. psavedstate(state)^.usedbyproc := usedbyproc;
  942. psavedstate(state)^.reg_pushes := reg_pushes;
  943. psavedstate(state)^.is_reg_var := is_reg_var;
  944. psavedstate(state)^.is_reg_var_int := is_reg_var_int;
  945. psavedstate(state)^.regvar_loaded := regvar_loaded;
  946. psavedstate(state)^.regvar_loaded_int := regvar_loaded_int;
  947. {$ifdef TEMPREGDEBUG}
  948. psavedstate(state)^.reg_user := reg_user;
  949. psavedstate(state)^.reg_releaser := reg_releaser;
  950. {$endif TEMPREGDEBUG}
  951. end;
  952. procedure trgobj.restoreStateAfterInline(var state: pointer);
  953. begin
  954. unusedregsint := psavedstate(state)^.unusedregsint;
  955. usableregsint := psavedstate(state)^.usableregsint;
  956. unusedregsfpu := psavedstate(state)^.unusedregsfpu;
  957. usableregsfpu := psavedstate(state)^.usableregsfpu;
  958. unusedregsmm := psavedstate(state)^.unusedregsmm;
  959. usableregsmm := psavedstate(state)^.usableregsmm;
  960. countunusedregsint := psavedstate(state)^.countunusedregsint;
  961. countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
  962. countunusedregsmm := psavedstate(state)^.countunusedregsmm;
  963. countusableregsint := psavedstate(state)^.countusableregsint;
  964. countusableregsfpu := psavedstate(state)^.countusableregsfpu;
  965. countusableregsmm := psavedstate(state)^.countusableregsmm;
  966. usedinproc := psavedstate(state)^.usedinproc;
  967. usedbyproc := psavedstate(state)^.usedbyproc;
  968. reg_pushes := psavedstate(state)^.reg_pushes;
  969. is_reg_var := psavedstate(state)^.is_reg_var;
  970. is_reg_var_int := psavedstate(state)^.is_reg_var_int;
  971. regvar_loaded := psavedstate(state)^.regvar_loaded;
  972. regvar_loaded_int := psavedstate(state)^.regvar_loaded_int;
  973. {$ifdef TEMPREGDEBUG}
  974. reg_user := psavedstate(state)^.reg_user;
  975. reg_releaser := psavedstate(state)^.reg_releaser;
  976. {$endif TEMPREGDEBUG}
  977. dispose(psavedstate(state));
  978. state := nil;
  979. end;
  980. procedure trgobj.saveUnusedState(var state: pointer);
  981. begin
  982. new(punusedstate(state));
  983. punusedstate(state)^.unusedregsint := unusedregsint;
  984. punusedstate(state)^.unusedregsfpu := unusedregsfpu;
  985. punusedstate(state)^.unusedregsmm := unusedregsmm;
  986. punusedstate(state)^.countunusedregsint := countunusedregsint;
  987. punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  988. punusedstate(state)^.countunusedregsmm := countunusedregsmm;
  989. end;
  990. procedure trgobj.restoreUnusedState(var state: pointer);
  991. begin
  992. unusedregsint := punusedstate(state)^.unusedregsint;
  993. unusedregsfpu := punusedstate(state)^.unusedregsfpu;
  994. unusedregsmm := punusedstate(state)^.unusedregsmm;
  995. countunusedregsint := punusedstate(state)^.countunusedregsint;
  996. countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
  997. countunusedregsmm := punusedstate(state)^.countunusedregsmm;
  998. dispose(punusedstate(state));
  999. state := nil;
  1000. end;
  1001. {$ifdef newra}
  1002. procedure Trgobj.add_edge(u,v:Tsuperregister);
  1003. {This procedure will add an edge to the virtual interference graph.}
  1004. procedure addadj(u,v:Tsuperregister);
  1005. begin
  1006. if igraph.adjlist[u]=nil then
  1007. begin
  1008. getmem(igraph.adjlist[u],16);
  1009. igraph.adjlist[u]^:='';
  1010. end
  1011. else if (length(igraph.adjlist[u]^) and 15)=15 then
  1012. reallocmem(igraph.adjlist[u],length(igraph.adjlist[u]^)+16);
  1013. igraph.adjlist[u]^:=igraph.adjlist[u]^+char(v);
  1014. end;
  1015. begin
  1016. if (u<>v) and not(v in igraph.bitmap[u]) then
  1017. begin
  1018. include(igraph.bitmap[u],v);
  1019. include(igraph.bitmap[v],u);
  1020. {Precoloured nodes are not stored in the interference graph.}
  1021. if not(u in [first_supreg..last_supreg]) then
  1022. addadj(u,v);
  1023. if not(v in [first_supreg..last_supreg]) then
  1024. addadj(v,u);
  1025. end;
  1026. end;
  1027. procedure Trgobj.add_edges_used(u:Tsuperregister);
  1028. var i:Tsuperregister;
  1029. begin
  1030. for i:=1 to 255 do
  1031. if not(i in unusedregsint) then
  1032. add_edge(u,i);
  1033. end;
  1034. {$endif}
  1035. {****************************************************************************
  1036. TReference
  1037. ****************************************************************************}
  1038. procedure reference_reset(var ref : treference);
  1039. begin
  1040. FillChar(ref,sizeof(treference),0);
  1041. ref.base.enum:=R_INTREGISTER;
  1042. ref.index.enum:=R_INTREGISTER;
  1043. {$ifdef i386}
  1044. ref.segment.enum:=R_INTREGISTER;
  1045. {$endif}
  1046. end;
  1047. procedure reference_reset_old(var ref : treference);
  1048. begin
  1049. FillChar(ref,sizeof(treference),0);
  1050. end;
  1051. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  1052. begin
  1053. reference_reset(ref);
  1054. ref.base:=base;
  1055. ref.offset:=offset;
  1056. end;
  1057. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  1058. begin
  1059. reference_reset(ref);
  1060. ref.symbol:=sym;
  1061. ref.offset:=offset;
  1062. end;
  1063. procedure reference_release(list: taasmoutput; const ref : treference);
  1064. begin
  1065. rg.ungetreference(list,ref);
  1066. end;
  1067. function references_equal(sref : treference;dref : treference):boolean;
  1068. begin
  1069. references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
  1070. end;
  1071. { on most processors , this routine does nothing, overriden currently }
  1072. { only by 80x86 processor. }
  1073. function trgobj.makeregsize(reg: tregister; size: tcgsize): tregister;
  1074. begin
  1075. makeregsize := reg;
  1076. end;
  1077. {****************************************************************************
  1078. TLocation
  1079. ****************************************************************************}
  1080. procedure location_reset(var l : tlocation;lt:TLoc;lsize:TCGSize);
  1081. begin
  1082. FillChar(l,sizeof(tlocation),0);
  1083. l.loc:=lt;
  1084. l.size:=lsize;
  1085. case l.loc of
  1086. LOC_REGISTER,LOC_CREGISTER:
  1087. begin
  1088. l.register.enum:=R_INTREGISTER;
  1089. l.registerhigh.enum:=R_INTREGISTER;
  1090. end;
  1091. LOC_REFERENCE,LOC_CREFERENCE:
  1092. begin
  1093. l.reference.base.enum:=R_INTREGISTER;
  1094. l.reference.index.enum:=R_INTREGISTER;
  1095. {$ifdef i386}
  1096. l.reference.segment.enum:=R_INTREGISTER;
  1097. {$endif}
  1098. end;
  1099. end;
  1100. end;
  1101. procedure location_release(list: taasmoutput; const l : tlocation);
  1102. begin
  1103. case l.loc of
  1104. LOC_REGISTER,LOC_CREGISTER :
  1105. begin
  1106. rg.ungetregisterint(list,l.register);
  1107. if l.size in [OS_64,OS_S64] then
  1108. rg.ungetregisterint(list,l.registerhigh);
  1109. end;
  1110. LOC_CREFERENCE,LOC_REFERENCE :
  1111. rg.ungetreference(list, l.reference);
  1112. end;
  1113. end;
  1114. procedure location_freetemp(list:taasmoutput; const l : tlocation);
  1115. begin
  1116. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  1117. tg.ungetiftemp(list,l.reference);
  1118. end;
  1119. procedure location_copy(var destloc,sourceloc : tlocation);
  1120. begin
  1121. destloc:=sourceloc;
  1122. end;
  1123. procedure location_swap(var destloc,sourceloc : tlocation);
  1124. var
  1125. swapl : tlocation;
  1126. begin
  1127. swapl := destloc;
  1128. destloc := sourceloc;
  1129. sourceloc := swapl;
  1130. end;
  1131. initialization
  1132. ;
  1133. finalization
  1134. rg.free;
  1135. end.
  1136. {
  1137. $Log$
  1138. Revision 1.31 2003-03-11 21:46:24 jonas
  1139. * lots of new regallocator fixes, both in generic and ppc-specific code
  1140. (ppc compiler still can't compile the linux system unit though)
  1141. Revision 1.30 2003/03/09 21:18:59 olle
  1142. + added cutils to the uses clause
  1143. Revision 1.29 2003/03/08 20:36:41 daniel
  1144. + Added newra version of Ti386shlshrnode
  1145. + Added interference graph construction code
  1146. Revision 1.28 2003/03/08 13:59:16 daniel
  1147. * Work to handle new register notation in ag386nsm
  1148. + Added newra version of Ti386moddivnode
  1149. Revision 1.27 2003/03/08 10:53:48 daniel
  1150. * Created newra version of secondmul in n386add.pas
  1151. Revision 1.26 2003/03/08 08:59:07 daniel
  1152. + $define newra will enable new register allocator
  1153. + getregisterint will return imaginary registers with $newra
  1154. + -sr switch added, will skip register allocation so you can see
  1155. the direct output of the code generator before register allocation
  1156. Revision 1.25 2003/02/26 20:50:45 daniel
  1157. * Fixed ungetreference
  1158. Revision 1.24 2003/02/19 22:39:56 daniel
  1159. * Fixed a few issues
  1160. Revision 1.23 2003/02/19 22:00:14 daniel
  1161. * Code generator converted to new register notation
  1162. - Horribily outdated todo.txt removed
  1163. Revision 1.22 2003/02/02 19:25:54 carl
  1164. * Several bugfixes for m68k target (register alloc., opcode emission)
  1165. + VIS target
  1166. + Generic add more complete (still not verified)
  1167. Revision 1.21 2003/01/08 18:43:57 daniel
  1168. * Tregister changed into a record
  1169. Revision 1.20 2002/10/05 12:43:28 carl
  1170. * fixes for Delphi 6 compilation
  1171. (warning : Some features do not work under Delphi)
  1172. Revision 1.19 2002/08/23 16:14:49 peter
  1173. * tempgen cleanup
  1174. * tt_noreuse temp type added that will be used in genentrycode
  1175. Revision 1.18 2002/08/17 22:09:47 florian
  1176. * result type handling in tcgcal.pass_2 overhauled
  1177. * better tnode.dowrite
  1178. * some ppc stuff fixed
  1179. Revision 1.17 2002/08/17 09:23:42 florian
  1180. * first part of procinfo rewrite
  1181. Revision 1.16 2002/08/06 20:55:23 florian
  1182. * first part of ppc calling conventions fix
  1183. Revision 1.15 2002/08/05 18:27:48 carl
  1184. + more more more documentation
  1185. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  1186. Revision 1.14 2002/08/04 19:06:41 carl
  1187. + added generic exception support (still does not work!)
  1188. + more documentation
  1189. Revision 1.13 2002/07/07 09:52:32 florian
  1190. * powerpc target fixed, very simple units can be compiled
  1191. * some basic stuff for better callparanode handling, far from being finished
  1192. Revision 1.12 2002/07/01 18:46:26 peter
  1193. * internal linker
  1194. * reorganized aasm layer
  1195. Revision 1.11 2002/05/18 13:34:17 peter
  1196. * readded missing revisions
  1197. Revision 1.10 2002/05/16 19:46:44 carl
  1198. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1199. + try to fix temp allocation (still in ifdef)
  1200. + generic constructor calls
  1201. + start of tassembler / tmodulebase class cleanup
  1202. Revision 1.8 2002/04/21 15:23:03 carl
  1203. + makeregsize
  1204. + changeregsize is now a local routine
  1205. Revision 1.7 2002/04/20 21:32:25 carl
  1206. + generic FPC_CHECKPOINTER
  1207. + first parameter offset in stack now portable
  1208. * rename some constants
  1209. + move some cpu stuff to other units
  1210. - remove unused constents
  1211. * fix stacksize for some targets
  1212. * fix generic size problems which depend now on EXTEND_SIZE constant
  1213. Revision 1.6 2002/04/15 19:03:31 carl
  1214. + reg2str -> std_reg2str()
  1215. Revision 1.5 2002/04/06 18:13:01 jonas
  1216. * several powerpc-related additions and fixes
  1217. Revision 1.4 2002/04/04 19:06:04 peter
  1218. * removed unused units
  1219. * use tlocation.size in cg.a_*loc*() routines
  1220. Revision 1.3 2002/04/02 17:11:29 peter
  1221. * tlocation,treference update
  1222. * LOC_CONSTANT added for better constant handling
  1223. * secondadd splitted in multiple routines
  1224. * location_force_reg added for loading a location to a register
  1225. of a specified size
  1226. * secondassignment parses now first the right and then the left node
  1227. (this is compatible with Kylix). This saves a lot of push/pop especially
  1228. with string operations
  1229. * adapted some routines to use the new cg methods
  1230. Revision 1.2 2002/04/01 19:24:25 jonas
  1231. * fixed different parameter name in interface and implementation
  1232. declaration of a method (only 1.0.x detected this)
  1233. Revision 1.1 2002/03/31 20:26:36 jonas
  1234. + a_loadfpu_* and a_loadmm_* methods in tcg
  1235. * register allocation is now handled by a class and is mostly processor
  1236. independent (+rgobj.pas and i386/rgcpu.pas)
  1237. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  1238. * some small improvements and fixes to the optimizer
  1239. * some register allocation fixes
  1240. * some fpuvaroffset fixes in the unary minus node
  1241. * push/popusedregisters is now called rg.save/restoreusedregisters and
  1242. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  1243. also better optimizable)
  1244. * fixed and optimized register saving/restoring for new/dispose nodes
  1245. * LOC_FPU locations now also require their "register" field to be set to
  1246. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  1247. - list field removed of the tnode class because it's not used currently
  1248. and can cause hard-to-find bugs
  1249. }