rgobj.pas 36 KB

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