rgobj.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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. unit rgobj;
  25. interface
  26. uses
  27. cpubase,
  28. cpuinfo,
  29. aasmbase,aasmtai,aasmcpu,
  30. cclasses,globtype,cginfo,cgbase,node
  31. {$ifdef delphi}
  32. ,dmisc
  33. {$endif}
  34. ;
  35. type
  36. regvar_longintarray = array[firstreg..lastreg] of longint;
  37. regvar_booleanarray = array[firstreg..lastreg] of boolean;
  38. regvar_ptreearray = array[firstreg..lastreg] of tnode;
  39. tpushedsavedloc = record
  40. case byte of
  41. 0: (pushed: boolean);
  42. 1: (ofs: longint);
  43. end;
  44. tpushedsaved = array[firstreg..lastreg] of tpushedsavedloc;
  45. {#
  46. This class implements the abstract register allocator
  47. It is used by the code generator to allocate and free
  48. registers which might be valid across nodes. It also
  49. contains utility routines related to registers.
  50. Some of the methods in this class should be overriden
  51. by cpu-specific implementations.
  52. }
  53. trgobj = class
  54. { The "usableregsxxx" contain all registers of type "xxx" that }
  55. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  56. { contain all registers of type "xxx" that aren't currenly }
  57. { allocated }
  58. unusedregsint,usableregsint : tregisterset;
  59. unusedregsfpu,usableregsfpu : tregisterset;
  60. unusedregsmm,usableregsmm : tregisterset;
  61. { these counters contain the number of elements in the }
  62. { unusedregsxxx/usableregsxxx sets }
  63. countunusedregsint,
  64. countunusedregsfpu,
  65. countunusedregsmm : byte;
  66. countusableregsint,
  67. countusableregsfpu,
  68. countusableregsmm : byte;
  69. { Contains the registers which are really used by the proc itself.
  70. It doesn't take care of registers used by called procedures
  71. }
  72. usedbyproc,
  73. usedinproc : tregisterset;
  74. reg_pushes : regvar_longintarray;
  75. is_reg_var : regvar_booleanarray;
  76. regvar_loaded: regvar_booleanarray;
  77. { tries to hold the amount of times which the current tree is processed }
  78. t_times: longint;
  79. constructor create;
  80. {# Allocate a general purpose register
  81. An internalerror will be generated if there
  82. is no more free registers which can be allocated
  83. }
  84. function getregisterint(list: taasmoutput) : tregister; virtual;
  85. {# Free a general purpose register
  86. @param(r register to free)
  87. }
  88. procedure ungetregisterint(list: taasmoutput; r : tregister); virtual;
  89. {# Allocate a floating point register
  90. An internalerror will be generated if there
  91. is no more free registers which can be allocated
  92. }
  93. function getregisterfpu(list: taasmoutput) : tregister; virtual;
  94. {# Free a floating point register
  95. @param(r register to free)
  96. }
  97. procedure ungetregisterfpu(list: taasmoutput; r : tregister); virtual;
  98. function getregistermm(list: taasmoutput) : tregister; virtual;
  99. procedure ungetregistermm(list: taasmoutput; r : tregister); virtual;
  100. {# Allocate an address register.
  101. Address registers are the only registers which can
  102. be used as a base register in references (treference).
  103. On most cpu's this is the same as a general purpose
  104. register.
  105. An internalerror will be generated if there
  106. is no more free registers which can be allocated
  107. }
  108. function getaddressregister(list: taasmoutput): tregister; virtual;
  109. procedure ungetaddressregister(list: taasmoutput; r: tregister); virtual;
  110. {# Verify if the specified register is an address or
  111. general purpose register. Returns TRUE if @var(reg)
  112. is an adress register.
  113. This routine should only be used to check on
  114. general purpose or address register. It will
  115. not work on multimedia or floating point
  116. registers
  117. @param(reg register to verify)
  118. }
  119. function isaddressregister(reg: tregister): boolean; virtual;
  120. {# Tries to allocate the passed register, if possible
  121. @param(r specific register to allocate)
  122. }
  123. function getexplicitregisterint(list: taasmoutput; r : Toldregister) : tregister;virtual;
  124. {# Tries to allocate the passed fpu register, if possible
  125. @param(r specific register to allocate)
  126. }
  127. function getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  128. {# Deallocate any kind of register }
  129. procedure ungetregister(list: taasmoutput; r : tregister); virtual;
  130. {# Deallocate all registers which are allocated
  131. in the specified reference. On most systems,
  132. this will free the base and index registers
  133. of the specified reference.
  134. @param(ref reference which must have its registers freed)
  135. }
  136. procedure ungetreference(list: taasmoutput; const ref : treference); virtual;
  137. {# Reset the register allocator information (usable registers etc) }
  138. procedure cleartempgen;virtual;
  139. {# Convert a register to a specified register size, and return that register size }
  140. function makeregsize(reg: tregister; size: tcgsize): tregister; virtual;
  141. {# saves register variables (restoring happens automatically) }
  142. procedure saveregvars(list: taasmoutput; const s: tregisterset);
  143. {# Saves in temporary references (allocated via the temp. allocator)
  144. the registers defined in @var(s). The registers are only saved
  145. if they are currently in use, otherwise they are left as is.
  146. On processors which have instructions which manipulate the stack,
  147. this routine should be overriden for performance reasons.
  148. @param(list) List to add the instruction to
  149. @param(saved) Array of saved register information
  150. @param(s) Registers which might require saving
  151. }
  152. procedure saveusedregisters(list: taasmoutput;
  153. var saved : tpushedsaved;const s: tregisterset);virtual;
  154. {# Restores the registers which were saved with a call
  155. to @var(saveusedregisters).
  156. On processors which have instructions which manipulate the stack,
  157. this routine should be overriden for performance reasons.
  158. }
  159. procedure restoreusedregisters(list: taasmoutput;
  160. const saved : tpushedsaved);virtual;
  161. { used when deciding which registers to use for regvars }
  162. procedure incrementregisterpushed(const s: tregisterset);
  163. procedure clearregistercount;
  164. procedure resetusableregisters;virtual;
  165. procedure makeregvar(reg: tregister);
  166. procedure saveStateForInline(var state: pointer);
  167. procedure restoreStateAfterInline(var state: pointer);
  168. procedure saveUnusedState(var state: pointer);
  169. procedure restoreUnusedState(var state: pointer);
  170. protected
  171. { the following two contain the common (generic) code for all }
  172. { get- and ungetregisterxxx functions/procedures }
  173. function getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  174. var unusedregs: tregisterset; var countunusedregs: byte): tregister;
  175. procedure ungetregistergen(list: taasmoutput; const r: tregister;
  176. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  177. {$ifdef TEMPREGDEBUG}
  178. reg_user : regvar_ptreearray;
  179. reg_releaser : regvar_ptreearray;
  180. {$endif TEMPREGDEBUG}
  181. {$ifdef TEMPREGDEBUG}
  182. procedure testregisters;
  183. {$endif TEMPREGDEBUGx}
  184. end;
  185. const
  186. {# This value is used in tsaved. If the array value is equal
  187. to this, then this means that this register is not used.
  188. }
  189. reg_not_saved = $7fffffff;
  190. var
  191. {# This is the class instance used to access the register allocator class }
  192. rg: trgobj;
  193. { trerefence handling }
  194. {# Clear to zero a treference }
  195. procedure reference_reset(var ref : treference);
  196. {# Clear to zero a treference, and set is base address
  197. to base register.
  198. }
  199. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  200. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  201. procedure reference_release(list: taasmoutput; const ref : treference);
  202. { This routine verifies if two references are the same, and
  203. if so, returns TRUE, otherwise returns false.
  204. }
  205. function references_equal(sref : treference;dref : treference) : boolean;
  206. { tlocation handling }
  207. procedure location_reset(var l : tlocation;lt:TLoc;lsize:TCGSize);
  208. procedure location_release(list: taasmoutput; const l : tlocation);
  209. procedure location_freetemp(list: taasmoutput; const l : tlocation);
  210. procedure location_copy(var destloc,sourceloc : tlocation);
  211. procedure location_swap(var destloc,sourceloc : tlocation);
  212. implementation
  213. uses
  214. systems,
  215. globals,verbose,
  216. cgobj,tgobj,regvars;
  217. type
  218. psavedstate = ^tsavedstate;
  219. tsavedstate = record
  220. unusedregsint,usableregsint : tregisterset;
  221. unusedregsfpu,usableregsfpu : tregisterset;
  222. unusedregsmm,usableregsmm : tregisterset;
  223. countunusedregsint,
  224. countunusedregsfpu,
  225. countunusedregsmm : byte;
  226. countusableregsint,
  227. countusableregsfpu,
  228. countusableregsmm : byte;
  229. { contains the registers which are really used by the proc itself }
  230. usedbyproc,
  231. usedinproc : tregisterset;
  232. reg_pushes : regvar_longintarray;
  233. is_reg_var : regvar_booleanarray;
  234. regvar_loaded: regvar_booleanarray;
  235. {$ifdef TEMPREGDEBUG}
  236. reg_user : regvar_ptreearray;
  237. reg_releaser : regvar_ptreearray;
  238. {$endif TEMPREGDEBUG}
  239. end;
  240. punusedstate = ^tunusedstate;
  241. tunusedstate = record
  242. unusedregsint : tregisterset;
  243. unusedregsfpu : tregisterset;
  244. unusedregsmm : tregisterset;
  245. countunusedregsint,
  246. countunusedregsfpu,
  247. countunusedregsmm : byte;
  248. end;
  249. constructor trgobj.create;
  250. begin
  251. usedinproc := [];
  252. usedbyproc:=[];
  253. t_times := 0;
  254. resetusableregisters;
  255. {$ifdef TEMPREGDEBUG}
  256. fillchar(reg_user,sizeof(reg_user),0);
  257. fillchar(reg_releaser,sizeof(reg_releaser),0);
  258. {$endif TEMPREGDEBUG}
  259. end;
  260. function trgobj.getregistergen(list: taasmoutput; const lowreg, highreg: Toldregister;
  261. var unusedregs: tregisterset; var countunusedregs: byte): tregister;
  262. var
  263. i: Toldregister;
  264. r: Tregister;
  265. begin
  266. for i:=lowreg to highreg do
  267. begin
  268. if i in unusedregs then
  269. begin
  270. exclude(unusedregs,i);
  271. include(usedinproc,i);
  272. include(usedbyproc,i);
  273. dec(countunusedregs);
  274. r.enum:=i;
  275. list.concat(tai_regalloc.alloc(r));
  276. result := r;
  277. exit;
  278. end;
  279. end;
  280. internalerror(10);
  281. end;
  282. procedure trgobj.ungetregistergen(list: taasmoutput; const r: tregister;
  283. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  284. begin
  285. if r.enum>lastreg then
  286. internalerror(2003010801);
  287. { takes much time }
  288. if not(r.enum in usableregs) then
  289. exit;
  290. {$ifdef TEMPREGDEBUG}
  291. if (r.enum in unusedregs) then
  292. {$ifdef EXTTEMPREGDEBUG}
  293. begin
  294. Comment(V_Debug,'register freed twice '+std_reg2str[r.enum]);
  295. testregisters32;
  296. exit;
  297. end
  298. {$else EXTTEMPREGDEBUG}
  299. exit
  300. {$endif EXTTEMPREGDEBUG}
  301. else
  302. {$endif TEMPREGDEBUG}
  303. inc(countunusedregs);
  304. include(unusedregs,r.enum);
  305. list.concat(tai_regalloc.dealloc(r));
  306. end;
  307. function trgobj.getregisterint(list : taasmoutput) : tregister;
  308. begin
  309. if countunusedregsint=0 then
  310. internalerror(10);
  311. {$ifdef TEMPREGDEBUG}
  312. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  313. internalerror(10);
  314. {$endif TEMPREGDEBUG}
  315. {$ifdef EXTTEMPREGDEBUG}
  316. if curptree^^.usableregs-countunusedregsint>curptree^^.reallyusedregs then
  317. curptree^^.reallyusedregs:=curptree^^.usableregs-countunusedregsint;
  318. {$endif EXTTEMPREGDEBUG}
  319. result := getregistergen(list,firstsaveintreg,lastsaveintreg,
  320. unusedregsint,countunusedregsint);
  321. {$ifdef TEMPREGDEBUG}
  322. reg_user[result]:=curptree^;
  323. testregisters32;
  324. {$endif TEMPREGDEBUG}
  325. end;
  326. procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
  327. begin
  328. ungetregistergen(list,r,usableregsint,unusedregsint,
  329. countunusedregsint);
  330. {$ifdef TEMPREGDEBUG}
  331. reg_releaser[r]:=curptree^;
  332. testregisters32;
  333. {$endif TEMPREGDEBUG}
  334. end;
  335. { tries to allocate the passed register, if possible }
  336. function trgobj.getexplicitregisterint(list : taasmoutput; r : Toldregister) : tregister;
  337. var r2:Tregister;
  338. begin
  339. if r in unusedregsint then
  340. begin
  341. dec(countunusedregsint);
  342. {$ifdef TEMPREGDEBUG}
  343. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  344. internalerror(10);
  345. reg_user[r]:=curptree^;
  346. {$endif TEMPREGDEBUG}
  347. exclude(unusedregsint,r);
  348. include(usedinproc,r);
  349. include(usedbyproc,r);
  350. r2.enum:=r;
  351. list.concat(tai_regalloc.alloc(r2));
  352. getexplicitregisterint:=r2;
  353. {$ifdef TEMPREGDEBUG}
  354. testregisters32;
  355. {$endif TEMPREGDEBUG}
  356. end
  357. else
  358. getexplicitregisterint:=getregisterint(list);
  359. end;
  360. { tries to allocate the passed register, if possible }
  361. function trgobj.getexplicitregisterfpu(list : taasmoutput; r : Toldregister) : tregister;
  362. var r2:Tregister;
  363. begin
  364. if r in unusedregsfpu then
  365. begin
  366. dec(countunusedregsfpu);
  367. {$ifdef TEMPREGDEBUG}
  368. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  369. internalerror(10);
  370. reg_user[r]:=curptree^;
  371. {$endif TEMPREGDEBUG}
  372. exclude(unusedregsint,r);
  373. include(usedinproc,r);
  374. include(usedbyproc,r);
  375. r2.enum:=r;
  376. list.concat(tai_regalloc.alloc(r2));
  377. getexplicitregisterfpu:=r2;
  378. {$ifdef TEMPREGDEBUG}
  379. testregisters32;
  380. {$endif TEMPREGDEBUG}
  381. end
  382. else
  383. getexplicitregisterfpu:=getregisterfpu(list);
  384. end;
  385. function trgobj.getregisterfpu(list: taasmoutput) : tregister;
  386. begin
  387. if countunusedregsfpu=0 then
  388. internalerror(10);
  389. result := getregistergen(list,firstsavefpureg,lastsavefpureg,
  390. unusedregsfpu,countunusedregsfpu);
  391. end;
  392. procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister);
  393. begin
  394. ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
  395. countunusedregsfpu);
  396. end;
  397. function trgobj.getregistermm(list: taasmoutput) : tregister;
  398. begin
  399. if countunusedregsmm=0 then
  400. internalerror(10);
  401. result := getregistergen(list,firstsavemmreg,lastsavemmreg,
  402. unusedregsmm,countunusedregsmm);
  403. end;
  404. procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
  405. begin
  406. ungetregistergen(list,r,usableregsmm,unusedregsmm,
  407. countunusedregsmm);
  408. end;
  409. function trgobj.getaddressregister(list: taasmoutput): tregister;
  410. begin
  411. result := getregisterint(list);
  412. end;
  413. procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
  414. begin
  415. ungetregisterint(list,r);
  416. end;
  417. function trgobj.isaddressregister(reg: tregister): boolean;
  418. begin
  419. result := true;
  420. end;
  421. procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
  422. begin
  423. if r.enum=R_NO then
  424. exit;
  425. if r.enum>lastreg then
  426. internalerror(200301081);
  427. if r.enum in intregs then
  428. ungetregisterint(list,r)
  429. else if r.enum in fpuregs then
  430. ungetregisterfpu(list,r)
  431. else if r.enum in mmregs then
  432. ungetregistermm(list,r)
  433. else internalerror(2002070602);
  434. end;
  435. procedure trgobj.cleartempgen;
  436. begin
  437. countunusedregsint:=countusableregsint;
  438. countunusedregsfpu:=countusableregsfpu;
  439. countunusedregsmm:=countusableregsmm;
  440. unusedregsint:=usableregsint;
  441. unusedregsfpu:=usableregsfpu;
  442. unusedregsmm:=usableregsmm;
  443. end;
  444. procedure trgobj.ungetreference(list : taasmoutput; const ref : treference);
  445. begin
  446. ungetregister(list,ref.base);
  447. ungetregister(list,ref.index);
  448. end;
  449. procedure trgobj.saveregvars(list: taasmoutput; const s: tregisterset);
  450. var
  451. r: Tregister;
  452. begin
  453. if not(cs_regalloc in aktglobalswitches) then
  454. exit;
  455. for r.enum := firstsaveintreg to lastsaveintreg do
  456. if is_reg_var[r.enum] and
  457. (r.enum in s) then
  458. store_regvar(list,r);
  459. if firstsavefpureg <> R_NO then
  460. for r.enum := firstsavefpureg to lastsavefpureg do
  461. if is_reg_var[r.enum] and
  462. (r.enum in s) then
  463. store_regvar(list,r);
  464. if firstsavemmreg <> R_NO then
  465. for r.enum := firstsavemmreg to lastsavemmreg do
  466. if is_reg_var[r.enum] and
  467. (r.enum in s) then
  468. store_regvar(list,r);
  469. end;
  470. procedure trgobj.saveusedregisters(list: taasmoutput;
  471. var saved : tpushedsaved; const s: tregisterset);
  472. var
  473. r : tregister;
  474. hr : treference;
  475. begin
  476. usedinproc:=usedinproc + s;
  477. for r.enum:=firstsaveintreg to lastsaveintreg do
  478. begin
  479. saved[r.enum].ofs:=reg_not_saved;
  480. { if the register is used by the calling subroutine and if }
  481. { it's not a regvar (those are handled separately) }
  482. if not is_reg_var[r.enum] and
  483. (r.enum in s) and
  484. { and is present in use }
  485. not(r.enum in unusedregsint) then
  486. begin
  487. { then save it }
  488. tg.GetTemp(list,sizeof(aword),tt_persistant,hr);
  489. saved[r.enum].ofs:=hr.offset;
  490. cg.a_load_reg_ref(list,OS_INT,r,hr);
  491. cg.a_reg_dealloc(list,r);
  492. include(unusedregsint,r.enum);
  493. inc(countunusedregsint);
  494. end;
  495. end;
  496. { don't try to save the fpu registers if not desired (e.g. for }
  497. { the 80x86) }
  498. if firstsavefpureg <> R_NO then
  499. for r.enum:=firstsavefpureg to lastsavefpureg do
  500. begin
  501. saved[r.enum].ofs:=reg_not_saved;
  502. { if the register is used by the calling subroutine and if }
  503. { it's not a regvar (those are handled separately) }
  504. if not is_reg_var[r.enum] and
  505. (r.enum in s) and
  506. { and is present in use }
  507. not(r.enum in unusedregsfpu) then
  508. begin
  509. { then save it }
  510. tg.GetTemp(list,extended_size,tt_persistant,hr);
  511. saved[r.enum].ofs:=hr.offset;
  512. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  513. cg.a_reg_dealloc(list,r);
  514. include(unusedregsfpu,r.enum);
  515. inc(countunusedregsfpu);
  516. end;
  517. end;
  518. { don't save the vector registers if there's no support for them }
  519. if firstsavemmreg <> R_NO then
  520. for r.enum:=firstsavemmreg to lastsavemmreg do
  521. begin
  522. saved[r.enum].ofs:=reg_not_saved;
  523. { if the register is in use and if it's not a regvar (those }
  524. { are handled separately), save it }
  525. if not is_reg_var[r.enum] and
  526. (r.enum in s) and
  527. { and is present in use }
  528. not(r.enum in unusedregsmm) then
  529. begin
  530. { then save it }
  531. tg.GetTemp(list,mmreg_size,tt_persistant,hr);
  532. saved[r.enum].ofs:=hr.offset;
  533. cg.a_loadmm_reg_ref(list,r,hr);
  534. cg.a_reg_dealloc(list,r);
  535. include(unusedregsmm,r.enum);
  536. inc(countunusedregsmm);
  537. end;
  538. end;
  539. {$ifdef TEMPREGDEBUG}
  540. testregisters32;
  541. {$endif TEMPREGDEBUG}
  542. end;
  543. procedure trgobj.restoreusedregisters(list : taasmoutput;
  544. const saved : tpushedsaved);
  545. var
  546. r,r2 : tregister;
  547. hr : treference;
  548. begin
  549. if firstsavemmreg <> R_NO then
  550. for r.enum:=lastsavemmreg downto firstsavemmreg do
  551. begin
  552. if saved[r.enum].ofs <> reg_not_saved then
  553. begin
  554. r2.enum:=FRAME_POINTER_REG;
  555. reference_reset_base(hr,r2,saved[r.enum].ofs);
  556. cg.a_reg_alloc(list,r);
  557. cg.a_loadmm_ref_reg(list,hr,r);
  558. if not (r.enum in unusedregsmm) then
  559. { internalerror(10)
  560. in n386cal we always save/restore the reg *state*
  561. using save/restoreunusedstate -> the current state
  562. may not be real (JM) }
  563. else
  564. begin
  565. dec(countunusedregsmm);
  566. exclude(unusedregsmm,r.enum);
  567. end;
  568. tg.UnGetTemp(list,hr);
  569. end;
  570. end;
  571. if firstsavefpureg <> R_NO then
  572. for r.enum:=lastsavefpureg downto firstsavefpureg do
  573. begin
  574. if saved[r.enum].ofs <> reg_not_saved then
  575. begin
  576. r2.enum:=FRAME_POINTER_REG;
  577. reference_reset_base(hr,r2,saved[r.enum].ofs);
  578. cg.a_reg_alloc(list,r);
  579. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  580. if not (r.enum in unusedregsfpu) then
  581. { internalerror(10)
  582. in n386cal we always save/restore the reg *state*
  583. using save/restoreunusedstate -> the current state
  584. may not be real (JM) }
  585. else
  586. begin
  587. dec(countunusedregsfpu);
  588. exclude(unusedregsfpu,r.enum);
  589. end;
  590. tg.UnGetTemp(list,hr);
  591. end;
  592. end;
  593. for r.enum:=lastsaveintreg downto firstsaveintreg do
  594. begin
  595. if saved[r.enum].ofs <> reg_not_saved then
  596. begin
  597. r2.enum:=FRAME_POINTER_REG;
  598. reference_reset_base(hr,r2,saved[r.enum].ofs);
  599. cg.a_reg_alloc(list,r);
  600. cg.a_load_ref_reg(list,OS_INT,hr,r);
  601. if not (r.enum in unusedregsint) then
  602. { internalerror(10)
  603. in n386cal we always save/restore the reg *state*
  604. using save/restoreunusedstate -> the current state
  605. may not be real (JM) }
  606. else
  607. begin
  608. dec(countunusedregsint);
  609. exclude(unusedregsint,r.enum);
  610. end;
  611. tg.UnGetTemp(list,hr);
  612. end;
  613. end;
  614. {$ifdef TEMPREGDEBUG}
  615. testregisters32;
  616. {$endif TEMPREGDEBUG}
  617. end;
  618. procedure trgobj.incrementregisterpushed(const s: tregisterset);
  619. var
  620. regi : Toldregister;
  621. begin
  622. for regi:=firstsaveintreg to lastsaveintreg do
  623. begin
  624. if (regi in s) then
  625. inc(reg_pushes[regi],t_times*2);
  626. end;
  627. if firstsavefpureg <> R_NO then
  628. for regi:=firstsavefpureg to lastsavefpureg do
  629. begin
  630. if (regi in s) then
  631. inc(reg_pushes[regi],t_times*2);
  632. end;
  633. if firstsavemmreg <> R_NO then
  634. for regi:=firstsavemmreg to lastsavemmreg do
  635. begin
  636. if (regi in s) then
  637. inc(reg_pushes[regi],t_times*2);
  638. end;
  639. end;
  640. procedure trgobj.clearregistercount;
  641. begin
  642. fillchar(reg_pushes,sizeof(reg_pushes),0);
  643. fillchar(is_reg_var,sizeof(is_reg_var),false);
  644. fillchar(regvar_loaded,sizeof(regvar_loaded),false);
  645. end;
  646. procedure trgobj.resetusableregisters;
  647. begin
  648. { initialize fields with constant values from cpubase }
  649. countusableregsint := cpubase.c_countusableregsint;
  650. countusableregsfpu := cpubase.c_countusableregsfpu;
  651. countusableregsmm := cpubase.c_countusableregsmm;
  652. usableregsint := cpubase.usableregsint;
  653. usableregsfpu := cpubase.usableregsfpu;
  654. usableregsmm := cpubase.usableregsmm;
  655. clearregistercount;
  656. end;
  657. procedure trgobj.makeregvar(reg: tregister);
  658. begin
  659. if reg.enum>lastreg then
  660. internalerror(200301081);
  661. if reg.enum in intregs then
  662. begin
  663. dec(countusableregsint);
  664. dec(countunusedregsint);
  665. exclude(usableregsint,reg.enum);
  666. exclude(unusedregsint,reg.enum);
  667. end
  668. else if reg.enum in fpuregs then
  669. begin
  670. dec(countusableregsfpu);
  671. dec(countunusedregsfpu);
  672. exclude(usableregsfpu,reg.enum);
  673. exclude(unusedregsfpu,reg.enum);
  674. end
  675. else if reg.enum in mmregs then
  676. begin
  677. dec(countusableregsmm);
  678. dec(countunusedregsmm);
  679. exclude(usableregsmm,reg.enum);
  680. exclude(unusedregsmm,reg.enum);
  681. end;
  682. is_reg_var[reg.enum]:=true;
  683. end;
  684. {$ifdef TEMPREGDEBUG}
  685. procedure trgobj.testregisters;
  686. var
  687. r: tregister;
  688. test : byte;
  689. begin
  690. test:=0;
  691. for r := firstsaveintreg to lastsaveintreg do
  692. inc(test,ord(r in unusedregsint));
  693. if test<>countunusedregsint then
  694. internalerror(10);
  695. end;
  696. {$endif TEMPREGDEBUG}
  697. procedure trgobj.saveStateForInline(var state: pointer);
  698. begin
  699. new(psavedstate(state));
  700. psavedstate(state)^.unusedregsint := unusedregsint;
  701. psavedstate(state)^.usableregsint := usableregsint;
  702. psavedstate(state)^.unusedregsfpu := unusedregsfpu;
  703. psavedstate(state)^.usableregsfpu := usableregsfpu;
  704. psavedstate(state)^.unusedregsmm := unusedregsmm;
  705. psavedstate(state)^.usableregsmm := usableregsmm;
  706. psavedstate(state)^.countunusedregsint := countunusedregsint;
  707. psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  708. psavedstate(state)^.countunusedregsmm := countunusedregsmm;
  709. psavedstate(state)^.countusableregsint := countusableregsint;
  710. psavedstate(state)^.countusableregsfpu := countusableregsfpu;
  711. psavedstate(state)^.countusableregsmm := countusableregsmm;
  712. psavedstate(state)^.usedinproc := usedinproc;
  713. psavedstate(state)^.usedbyproc := usedbyproc;
  714. psavedstate(state)^.reg_pushes := reg_pushes;
  715. psavedstate(state)^.is_reg_var := is_reg_var;
  716. psavedstate(state)^.regvar_loaded := regvar_loaded;
  717. {$ifdef TEMPREGDEBUG}
  718. psavedstate(state)^.reg_user := reg_user;
  719. psavedstate(state)^.reg_releaser := reg_releaser;
  720. {$endif TEMPREGDEBUG}
  721. end;
  722. procedure trgobj.restoreStateAfterInline(var state: pointer);
  723. begin
  724. unusedregsint := psavedstate(state)^.unusedregsint;
  725. usableregsint := psavedstate(state)^.usableregsint;
  726. unusedregsfpu := psavedstate(state)^.unusedregsfpu;
  727. usableregsfpu := psavedstate(state)^.usableregsfpu;
  728. unusedregsmm := psavedstate(state)^.unusedregsmm;
  729. usableregsmm := psavedstate(state)^.usableregsmm;
  730. countunusedregsint := psavedstate(state)^.countunusedregsint;
  731. countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
  732. countunusedregsmm := psavedstate(state)^.countunusedregsmm;
  733. countusableregsint := psavedstate(state)^.countusableregsint;
  734. countusableregsfpu := psavedstate(state)^.countusableregsfpu;
  735. countusableregsmm := psavedstate(state)^.countusableregsmm;
  736. usedinproc := psavedstate(state)^.usedinproc;
  737. usedbyproc := psavedstate(state)^.usedbyproc;
  738. reg_pushes := psavedstate(state)^.reg_pushes;
  739. is_reg_var := psavedstate(state)^.is_reg_var;
  740. regvar_loaded := psavedstate(state)^.regvar_loaded;
  741. {$ifdef TEMPREGDEBUG}
  742. reg_user := psavedstate(state)^.reg_user;
  743. reg_releaser := psavedstate(state)^.reg_releaser;
  744. {$endif TEMPREGDEBUG}
  745. dispose(psavedstate(state));
  746. state := nil;
  747. end;
  748. procedure trgobj.saveUnusedState(var state: pointer);
  749. begin
  750. new(punusedstate(state));
  751. punusedstate(state)^.unusedregsint := unusedregsint;
  752. punusedstate(state)^.unusedregsfpu := unusedregsfpu;
  753. punusedstate(state)^.unusedregsmm := unusedregsmm;
  754. punusedstate(state)^.countunusedregsint := countunusedregsint;
  755. punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  756. punusedstate(state)^.countunusedregsmm := countunusedregsmm;
  757. end;
  758. procedure trgobj.restoreUnusedState(var state: pointer);
  759. begin
  760. unusedregsint := punusedstate(state)^.unusedregsint;
  761. unusedregsfpu := punusedstate(state)^.unusedregsfpu;
  762. unusedregsmm := punusedstate(state)^.unusedregsmm;
  763. countunusedregsint := punusedstate(state)^.countunusedregsint;
  764. countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
  765. countunusedregsmm := punusedstate(state)^.countunusedregsmm;
  766. dispose(punusedstate(state));
  767. state := nil;
  768. end;
  769. {****************************************************************************
  770. TReference
  771. ****************************************************************************}
  772. procedure reference_reset(var ref : treference);
  773. begin
  774. FillChar(ref,sizeof(treference),0);
  775. end;
  776. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  777. begin
  778. FillChar(ref,sizeof(treference),0);
  779. ref.base:=base;
  780. ref.offset:=offset;
  781. end;
  782. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  783. begin
  784. FillChar(ref,sizeof(treference),0);
  785. ref.symbol:=sym;
  786. ref.offset:=offset;
  787. end;
  788. procedure reference_release(list: taasmoutput; const ref : treference);
  789. begin
  790. rg.ungetreference(list,ref);
  791. end;
  792. function references_equal(sref : treference;dref : treference):boolean;
  793. begin
  794. references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
  795. end;
  796. { on most processors , this routine does nothing, overriden currently }
  797. { only by 80x86 processor. }
  798. function trgobj.makeregsize(reg: tregister; size: tcgsize): tregister;
  799. begin
  800. makeregsize := reg;
  801. end;
  802. {****************************************************************************
  803. TLocation
  804. ****************************************************************************}
  805. procedure location_reset(var l : tlocation;lt:TLoc;lsize:TCGSize);
  806. begin
  807. FillChar(l,sizeof(tlocation),0);
  808. l.loc:=lt;
  809. l.size:=lsize;
  810. end;
  811. procedure location_release(list: taasmoutput; const l : tlocation);
  812. begin
  813. case l.loc of
  814. LOC_REGISTER,LOC_CREGISTER :
  815. begin
  816. rg.ungetregisterint(list,l.register);
  817. if l.size in [OS_64,OS_S64] then
  818. rg.ungetregisterint(list,l.registerhigh);
  819. end;
  820. LOC_CREFERENCE,LOC_REFERENCE :
  821. rg.ungetreference(list, l.reference);
  822. end;
  823. end;
  824. procedure location_freetemp(list:taasmoutput; const l : tlocation);
  825. begin
  826. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  827. tg.ungetiftemp(list,l.reference);
  828. end;
  829. procedure location_copy(var destloc,sourceloc : tlocation);
  830. begin
  831. destloc:=sourceloc;
  832. end;
  833. procedure location_swap(var destloc,sourceloc : tlocation);
  834. var
  835. swapl : tlocation;
  836. begin
  837. swapl := destloc;
  838. destloc := sourceloc;
  839. sourceloc := swapl;
  840. end;
  841. initialization
  842. ;
  843. finalization
  844. rg.free;
  845. end.
  846. {
  847. $Log$
  848. Revision 1.21 2003-01-08 18:43:57 daniel
  849. * Tregister changed into a record
  850. Revision 1.20 2002/10/05 12:43:28 carl
  851. * fixes for Delphi 6 compilation
  852. (warning : Some features do not work under Delphi)
  853. Revision 1.19 2002/08/23 16:14:49 peter
  854. * tempgen cleanup
  855. * tt_noreuse temp type added that will be used in genentrycode
  856. Revision 1.18 2002/08/17 22:09:47 florian
  857. * result type handling in tcgcal.pass_2 overhauled
  858. * better tnode.dowrite
  859. * some ppc stuff fixed
  860. Revision 1.17 2002/08/17 09:23:42 florian
  861. * first part of procinfo rewrite
  862. Revision 1.16 2002/08/06 20:55:23 florian
  863. * first part of ppc calling conventions fix
  864. Revision 1.15 2002/08/05 18:27:48 carl
  865. + more more more documentation
  866. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  867. Revision 1.14 2002/08/04 19:06:41 carl
  868. + added generic exception support (still does not work!)
  869. + more documentation
  870. Revision 1.13 2002/07/07 09:52:32 florian
  871. * powerpc target fixed, very simple units can be compiled
  872. * some basic stuff for better callparanode handling, far from being finished
  873. Revision 1.12 2002/07/01 18:46:26 peter
  874. * internal linker
  875. * reorganized aasm layer
  876. Revision 1.11 2002/05/18 13:34:17 peter
  877. * readded missing revisions
  878. Revision 1.10 2002/05/16 19:46:44 carl
  879. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  880. + try to fix temp allocation (still in ifdef)
  881. + generic constructor calls
  882. + start of tassembler / tmodulebase class cleanup
  883. Revision 1.8 2002/04/21 15:23:03 carl
  884. + makeregsize
  885. + changeregsize is now a local routine
  886. Revision 1.7 2002/04/20 21:32:25 carl
  887. + generic FPC_CHECKPOINTER
  888. + first parameter offset in stack now portable
  889. * rename some constants
  890. + move some cpu stuff to other units
  891. - remove unused constents
  892. * fix stacksize for some targets
  893. * fix generic size problems which depend now on EXTEND_SIZE constant
  894. Revision 1.6 2002/04/15 19:03:31 carl
  895. + reg2str -> std_reg2str()
  896. Revision 1.5 2002/04/06 18:13:01 jonas
  897. * several powerpc-related additions and fixes
  898. Revision 1.4 2002/04/04 19:06:04 peter
  899. * removed unused units
  900. * use tlocation.size in cg.a_*loc*() routines
  901. Revision 1.3 2002/04/02 17:11:29 peter
  902. * tlocation,treference update
  903. * LOC_CONSTANT added for better constant handling
  904. * secondadd splitted in multiple routines
  905. * location_force_reg added for loading a location to a register
  906. of a specified size
  907. * secondassignment parses now first the right and then the left node
  908. (this is compatible with Kylix). This saves a lot of push/pop especially
  909. with string operations
  910. * adapted some routines to use the new cg methods
  911. Revision 1.2 2002/04/01 19:24:25 jonas
  912. * fixed different parameter name in interface and implementation
  913. declaration of a method (only 1.0.x detected this)
  914. Revision 1.1 2002/03/31 20:26:36 jonas
  915. + a_loadfpu_* and a_loadmm_* methods in tcg
  916. * register allocation is now handled by a class and is mostly processor
  917. independent (+rgobj.pas and i386/rgcpu.pas)
  918. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  919. * some small improvements and fixes to the optimizer
  920. * some register allocation fixes
  921. * some fpuvaroffset fixes in the unary minus node
  922. * push/popusedregisters is now called rg.save/restoreusedregisters and
  923. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  924. also better optimizable)
  925. * fixed and optimized register saving/restoring for new/dispose nodes
  926. * LOC_FPU locations now also require their "register" field to be set to
  927. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  928. - list field removed of the tnode class because it's not used currently
  929. and can cause hard-to-find bugs
  930. }