rgobj.pas 37 KB

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