rgobj.pas 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  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 : tregister) : 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 : tregister) : 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: tregister;
  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: tregister;
  261. var unusedregs: tregisterset; var countunusedregs: byte): tregister;
  262. var
  263. i: tregister;
  264. begin
  265. for i:=lowreg to highreg do
  266. begin
  267. if i in unusedregs then
  268. begin
  269. exclude(unusedregs,i);
  270. include(usedinproc,i);
  271. include(usedbyproc,i);
  272. dec(countunusedregs);
  273. list.concat(tai_regalloc.alloc(i));
  274. result := i;
  275. exit;
  276. end;
  277. end;
  278. internalerror(10);
  279. end;
  280. procedure trgobj.ungetregistergen(list: taasmoutput; const r: tregister;
  281. const usableregs: tregisterset; var unusedregs: tregisterset; var countunusedregs: byte);
  282. begin
  283. { takes much time }
  284. if not(r in usableregs) then
  285. exit;
  286. {$ifdef TEMPREGDEBUG}
  287. if (r in unusedregs) then
  288. {$ifdef EXTTEMPREGDEBUG}
  289. begin
  290. Comment(V_Debug,'register freed twice '+std_reg2str[r]);
  291. testregisters32;
  292. exit;
  293. end
  294. {$else EXTTEMPREGDEBUG}
  295. exit
  296. {$endif EXTTEMPREGDEBUG}
  297. else
  298. {$endif TEMPREGDEBUG}
  299. inc(countunusedregs);
  300. include(unusedregs,r);
  301. list.concat(tai_regalloc.dealloc(r));
  302. end;
  303. function trgobj.getregisterint(list : taasmoutput) : tregister;
  304. begin
  305. if countunusedregsint=0 then
  306. internalerror(10);
  307. {$ifdef TEMPREGDEBUG}
  308. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  309. internalerror(10);
  310. {$endif TEMPREGDEBUG}
  311. {$ifdef EXTTEMPREGDEBUG}
  312. if curptree^^.usableregs-countunusedregsint>curptree^^.reallyusedregs then
  313. curptree^^.reallyusedregs:=curptree^^.usableregs-countunusedregsint;
  314. {$endif EXTTEMPREGDEBUG}
  315. result := getregistergen(list,firstsaveintreg,lastsaveintreg,
  316. unusedregsint,countunusedregsint);
  317. {$ifdef TEMPREGDEBUG}
  318. reg_user[result]:=curptree^;
  319. testregisters32;
  320. {$endif TEMPREGDEBUG}
  321. end;
  322. procedure trgobj.ungetregisterint(list : taasmoutput; r : tregister);
  323. begin
  324. ungetregistergen(list,r,usableregsint,unusedregsint,
  325. countunusedregsint);
  326. {$ifdef TEMPREGDEBUG}
  327. reg_releaser[r]:=curptree^;
  328. testregisters32;
  329. {$endif TEMPREGDEBUG}
  330. end;
  331. { tries to allocate the passed register, if possible }
  332. function trgobj.getexplicitregisterint(list : taasmoutput; r : tregister) : tregister;
  333. begin
  334. if r in unusedregsint then
  335. begin
  336. dec(countunusedregsint);
  337. {$ifdef TEMPREGDEBUG}
  338. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  339. internalerror(10);
  340. reg_user[r]:=curptree^;
  341. {$endif TEMPREGDEBUG}
  342. exclude(unusedregsint,r);
  343. include(usedinproc,r);
  344. include(usedbyproc,r);
  345. list.concat(tai_regalloc.alloc(r));
  346. getexplicitregisterint:=r;
  347. {$ifdef TEMPREGDEBUG}
  348. testregisters32;
  349. {$endif TEMPREGDEBUG}
  350. end
  351. else
  352. getexplicitregisterint:=getregisterint(list);
  353. end;
  354. { tries to allocate the passed register, if possible }
  355. function trgobj.getexplicitregisterfpu(list : taasmoutput; r : tregister) : tregister;
  356. begin
  357. if r in unusedregsfpu then
  358. begin
  359. dec(countunusedregsfpu);
  360. {$ifdef TEMPREGDEBUG}
  361. if curptree^^.usableregs-countunusedregsint>curptree^^.registers32 then
  362. internalerror(10);
  363. reg_user[r]:=curptree^;
  364. {$endif TEMPREGDEBUG}
  365. exclude(unusedregsint,r);
  366. include(usedinproc,r);
  367. include(usedbyproc,r);
  368. list.concat(tai_regalloc.alloc(r));
  369. getexplicitregisterfpu:=r;
  370. {$ifdef TEMPREGDEBUG}
  371. testregisters32;
  372. {$endif TEMPREGDEBUG}
  373. end
  374. else
  375. getexplicitregisterfpu:=getregisterfpu(list);
  376. end;
  377. function trgobj.getregisterfpu(list: taasmoutput) : tregister;
  378. begin
  379. if countunusedregsfpu=0 then
  380. internalerror(10);
  381. result := getregistergen(list,firstsavefpureg,lastsavefpureg,
  382. unusedregsfpu,countunusedregsfpu);
  383. end;
  384. procedure trgobj.ungetregisterfpu(list : taasmoutput; r : tregister);
  385. begin
  386. ungetregistergen(list,r,usableregsfpu,unusedregsfpu,
  387. countunusedregsfpu);
  388. end;
  389. function trgobj.getregistermm(list: taasmoutput) : tregister;
  390. begin
  391. if countunusedregsmm=0 then
  392. internalerror(10);
  393. result := getregistergen(list,firstsavemmreg,lastsavemmreg,
  394. unusedregsmm,countunusedregsmm);
  395. end;
  396. procedure trgobj.ungetregistermm(list: taasmoutput; r: tregister);
  397. begin
  398. ungetregistergen(list,r,usableregsmm,unusedregsmm,
  399. countunusedregsmm);
  400. end;
  401. function trgobj.getaddressregister(list: taasmoutput): tregister;
  402. begin
  403. result := getregisterint(list);
  404. end;
  405. procedure trgobj.ungetaddressregister(list: taasmoutput; r: tregister);
  406. begin
  407. ungetregisterint(list,r);
  408. end;
  409. function trgobj.isaddressregister(reg: tregister): boolean;
  410. begin
  411. result := true;
  412. end;
  413. procedure trgobj.ungetregister(list: taasmoutput; r : tregister);
  414. begin
  415. if r=R_NO then
  416. exit;
  417. if r in intregs then
  418. ungetregisterint(list,r)
  419. else if r in fpuregs then
  420. ungetregisterfpu(list,r)
  421. else if r in mmregs then
  422. ungetregistermm(list,r)
  423. else internalerror(2002070602);
  424. end;
  425. procedure trgobj.cleartempgen;
  426. begin
  427. countunusedregsint:=countusableregsint;
  428. countunusedregsfpu:=countusableregsfpu;
  429. countunusedregsmm:=countusableregsmm;
  430. unusedregsint:=usableregsint;
  431. unusedregsfpu:=usableregsfpu;
  432. unusedregsmm:=usableregsmm;
  433. end;
  434. procedure trgobj.ungetreference(list : taasmoutput; const ref : treference);
  435. begin
  436. ungetregister(list,ref.base);
  437. ungetregister(list,ref.index);
  438. end;
  439. procedure trgobj.saveregvars(list: taasmoutput; const s: tregisterset);
  440. var
  441. r: tregister;
  442. begin
  443. if not(cs_regalloc in aktglobalswitches) then
  444. exit;
  445. for r := firstsaveintreg to lastsaveintreg do
  446. if is_reg_var[r] and
  447. (r in s) then
  448. store_regvar(list,r);
  449. if firstsavefpureg <> R_NO then
  450. for r := firstsavefpureg to lastsavefpureg do
  451. if is_reg_var[r] and
  452. (r in s) then
  453. store_regvar(list,r);
  454. if firstsavemmreg <> R_NO then
  455. for r := firstsavemmreg to lastsavemmreg do
  456. if is_reg_var[r] and
  457. (r in s) then
  458. store_regvar(list,r);
  459. end;
  460. procedure trgobj.saveusedregisters(list: taasmoutput;
  461. var saved : tpushedsaved; const s: tregisterset);
  462. var
  463. r : tregister;
  464. hr : treference;
  465. begin
  466. usedinproc:=usedinproc + s;
  467. for r:=firstsaveintreg to lastsaveintreg do
  468. begin
  469. saved[r].ofs:=reg_not_saved;
  470. { if the register is used by the calling subroutine and if }
  471. { it's not a regvar (those are handled separately) }
  472. if not is_reg_var[r] and
  473. (r in s) and
  474. { and is present in use }
  475. not(r in unusedregsint) then
  476. begin
  477. { then save it }
  478. tg.GetTemp(list,sizeof(aword),tt_persistant,hr);
  479. saved[r].ofs:=hr.offset;
  480. cg.a_load_reg_ref(list,OS_INT,r,hr);
  481. cg.a_reg_dealloc(list,r);
  482. include(unusedregsint,r);
  483. inc(countunusedregsint);
  484. end;
  485. end;
  486. { don't try to save the fpu registers if not desired (e.g. for }
  487. { the 80x86) }
  488. if firstsavefpureg <> R_NO then
  489. for r:=firstsavefpureg to lastsavefpureg do
  490. begin
  491. saved[r].ofs:=reg_not_saved;
  492. { if the register is used by the calling subroutine and if }
  493. { it's not a regvar (those are handled separately) }
  494. if not is_reg_var[r] and
  495. (r in s) and
  496. { and is present in use }
  497. not(r in unusedregsfpu) then
  498. begin
  499. { then save it }
  500. tg.GetTemp(list,extended_size,tt_persistant,hr);
  501. saved[r].ofs:=hr.offset;
  502. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  503. cg.a_reg_dealloc(list,r);
  504. include(unusedregsfpu,r);
  505. inc(countunusedregsfpu);
  506. end;
  507. end;
  508. { don't save the vector registers if there's no support for them }
  509. if firstsavemmreg <> R_NO then
  510. for r:=firstsavemmreg to lastsavemmreg do
  511. begin
  512. saved[r].ofs:=reg_not_saved;
  513. { if the register is in use and if it's not a regvar (those }
  514. { are handled separately), save it }
  515. if not is_reg_var[r] and
  516. (r in s) and
  517. { and is present in use }
  518. not(r in unusedregsmm) then
  519. begin
  520. { then save it }
  521. tg.GetTemp(list,mmreg_size,tt_persistant,hr);
  522. saved[r].ofs:=hr.offset;
  523. cg.a_loadmm_reg_ref(list,r,hr);
  524. cg.a_reg_dealloc(list,r);
  525. include(unusedregsmm,r);
  526. inc(countunusedregsmm);
  527. end;
  528. end;
  529. {$ifdef TEMPREGDEBUG}
  530. testregisters32;
  531. {$endif TEMPREGDEBUG}
  532. end;
  533. procedure trgobj.restoreusedregisters(list : taasmoutput;
  534. const saved : tpushedsaved);
  535. var
  536. r : tregister;
  537. hr : treference;
  538. begin
  539. if firstsavemmreg <> R_NO then
  540. for r:=lastsavemmreg downto firstsavemmreg do
  541. begin
  542. if saved[r].ofs <> reg_not_saved then
  543. begin
  544. reference_reset_base(hr,FRAME_POINTER_REG,saved[r].ofs);
  545. cg.a_reg_alloc(list,r);
  546. cg.a_loadmm_ref_reg(list,hr,r);
  547. if not (r in unusedregsmm) then
  548. { internalerror(10)
  549. in n386cal we always save/restore the reg *state*
  550. using save/restoreunusedstate -> the current state
  551. may not be real (JM) }
  552. else
  553. begin
  554. dec(countunusedregsmm);
  555. exclude(unusedregsmm,r);
  556. end;
  557. tg.UnGetTemp(list,hr);
  558. end;
  559. end;
  560. if firstsavefpureg <> R_NO then
  561. for r:=lastsavefpureg downto firstsavefpureg do
  562. begin
  563. if saved[r].ofs <> reg_not_saved then
  564. begin
  565. reference_reset_base(hr,FRAME_POINTER_REG,saved[r].ofs);
  566. cg.a_reg_alloc(list,r);
  567. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  568. if not (r in unusedregsfpu) then
  569. { internalerror(10)
  570. in n386cal we always save/restore the reg *state*
  571. using save/restoreunusedstate -> the current state
  572. may not be real (JM) }
  573. else
  574. begin
  575. dec(countunusedregsfpu);
  576. exclude(unusedregsfpu,r);
  577. end;
  578. tg.UnGetTemp(list,hr);
  579. end;
  580. end;
  581. for r:=lastsaveintreg downto firstsaveintreg do
  582. begin
  583. if saved[r].ofs <> reg_not_saved then
  584. begin
  585. reference_reset_base(hr,FRAME_POINTER_REG,saved[r].ofs);
  586. cg.a_reg_alloc(list,r);
  587. cg.a_load_ref_reg(list,OS_INT,hr,r);
  588. if not (r in unusedregsint) then
  589. { internalerror(10)
  590. in n386cal we always save/restore the reg *state*
  591. using save/restoreunusedstate -> the current state
  592. may not be real (JM) }
  593. else
  594. begin
  595. dec(countunusedregsint);
  596. exclude(unusedregsint,r);
  597. end;
  598. tg.UnGetTemp(list,hr);
  599. end;
  600. end;
  601. {$ifdef TEMPREGDEBUG}
  602. testregisters32;
  603. {$endif TEMPREGDEBUG}
  604. end;
  605. procedure trgobj.incrementregisterpushed(const s: tregisterset);
  606. var
  607. regi : tregister;
  608. begin
  609. for regi:=firstsaveintreg to lastsaveintreg do
  610. begin
  611. if (regi in s) then
  612. inc(reg_pushes[regi],t_times*2);
  613. end;
  614. if firstsavefpureg <> R_NO then
  615. for regi:=firstsavefpureg to lastsavefpureg do
  616. begin
  617. if (regi in s) then
  618. inc(reg_pushes[regi],t_times*2);
  619. end;
  620. if firstsavemmreg <> R_NO then
  621. for regi:=firstsavemmreg to lastsavemmreg do
  622. begin
  623. if (regi in s) then
  624. inc(reg_pushes[regi],t_times*2);
  625. end;
  626. end;
  627. procedure trgobj.clearregistercount;
  628. begin
  629. fillchar(reg_pushes,sizeof(reg_pushes),0);
  630. fillchar(is_reg_var,sizeof(is_reg_var),false);
  631. fillchar(regvar_loaded,sizeof(regvar_loaded),false);
  632. end;
  633. procedure trgobj.resetusableregisters;
  634. begin
  635. { initialize fields with constant values from cpubase }
  636. countusableregsint := cpubase.c_countusableregsint;
  637. countusableregsfpu := cpubase.c_countusableregsfpu;
  638. countusableregsmm := cpubase.c_countusableregsmm;
  639. usableregsint := cpubase.usableregsint;
  640. usableregsfpu := cpubase.usableregsfpu;
  641. usableregsmm := cpubase.usableregsmm;
  642. clearregistercount;
  643. end;
  644. procedure trgobj.makeregvar(reg: tregister);
  645. begin
  646. if reg in intregs then
  647. begin
  648. dec(countusableregsint);
  649. dec(countunusedregsint);
  650. exclude(usableregsint,reg);
  651. exclude(unusedregsint,reg);
  652. end
  653. else if reg in fpuregs then
  654. begin
  655. dec(countusableregsfpu);
  656. dec(countunusedregsfpu);
  657. exclude(usableregsfpu,reg);
  658. exclude(unusedregsfpu,reg);
  659. end
  660. else if reg in mmregs then
  661. begin
  662. dec(countusableregsmm);
  663. dec(countunusedregsmm);
  664. exclude(usableregsmm,reg);
  665. exclude(unusedregsmm,reg);
  666. end;
  667. is_reg_var[reg]:=true;
  668. end;
  669. {$ifdef TEMPREGDEBUG}
  670. procedure trgobj.testregisters;
  671. var
  672. r: tregister;
  673. test : byte;
  674. begin
  675. test:=0;
  676. for r := firstsaveintreg to lastsaveintreg do
  677. inc(test,ord(r in unusedregsint));
  678. if test<>countunusedregsint then
  679. internalerror(10);
  680. end;
  681. {$endif TEMPREGDEBUG}
  682. procedure trgobj.saveStateForInline(var state: pointer);
  683. begin
  684. new(psavedstate(state));
  685. psavedstate(state)^.unusedregsint := unusedregsint;
  686. psavedstate(state)^.usableregsint := usableregsint;
  687. psavedstate(state)^.unusedregsfpu := unusedregsfpu;
  688. psavedstate(state)^.usableregsfpu := usableregsfpu;
  689. psavedstate(state)^.unusedregsmm := unusedregsmm;
  690. psavedstate(state)^.usableregsmm := usableregsmm;
  691. psavedstate(state)^.countunusedregsint := countunusedregsint;
  692. psavedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  693. psavedstate(state)^.countunusedregsmm := countunusedregsmm;
  694. psavedstate(state)^.countusableregsint := countusableregsint;
  695. psavedstate(state)^.countusableregsfpu := countusableregsfpu;
  696. psavedstate(state)^.countusableregsmm := countusableregsmm;
  697. psavedstate(state)^.usedinproc := usedinproc;
  698. psavedstate(state)^.usedbyproc := usedbyproc;
  699. psavedstate(state)^.reg_pushes := reg_pushes;
  700. psavedstate(state)^.is_reg_var := is_reg_var;
  701. psavedstate(state)^.regvar_loaded := regvar_loaded;
  702. {$ifdef TEMPREGDEBUG}
  703. psavedstate(state)^.reg_user := reg_user;
  704. psavedstate(state)^.reg_releaser := reg_releaser;
  705. {$endif TEMPREGDEBUG}
  706. end;
  707. procedure trgobj.restoreStateAfterInline(var state: pointer);
  708. begin
  709. unusedregsint := psavedstate(state)^.unusedregsint;
  710. usableregsint := psavedstate(state)^.usableregsint;
  711. unusedregsfpu := psavedstate(state)^.unusedregsfpu;
  712. usableregsfpu := psavedstate(state)^.usableregsfpu;
  713. unusedregsmm := psavedstate(state)^.unusedregsmm;
  714. usableregsmm := psavedstate(state)^.usableregsmm;
  715. countunusedregsint := psavedstate(state)^.countunusedregsint;
  716. countunusedregsfpu := psavedstate(state)^.countunusedregsfpu;
  717. countunusedregsmm := psavedstate(state)^.countunusedregsmm;
  718. countusableregsint := psavedstate(state)^.countusableregsint;
  719. countusableregsfpu := psavedstate(state)^.countusableregsfpu;
  720. countusableregsmm := psavedstate(state)^.countusableregsmm;
  721. usedinproc := psavedstate(state)^.usedinproc;
  722. usedbyproc := psavedstate(state)^.usedbyproc;
  723. reg_pushes := psavedstate(state)^.reg_pushes;
  724. is_reg_var := psavedstate(state)^.is_reg_var;
  725. regvar_loaded := psavedstate(state)^.regvar_loaded;
  726. {$ifdef TEMPREGDEBUG}
  727. reg_user := psavedstate(state)^.reg_user;
  728. reg_releaser := psavedstate(state)^.reg_releaser;
  729. {$endif TEMPREGDEBUG}
  730. dispose(psavedstate(state));
  731. state := nil;
  732. end;
  733. procedure trgobj.saveUnusedState(var state: pointer);
  734. begin
  735. new(punusedstate(state));
  736. punusedstate(state)^.unusedregsint := unusedregsint;
  737. punusedstate(state)^.unusedregsfpu := unusedregsfpu;
  738. punusedstate(state)^.unusedregsmm := unusedregsmm;
  739. punusedstate(state)^.countunusedregsint := countunusedregsint;
  740. punusedstate(state)^.countunusedregsfpu := countunusedregsfpu;
  741. punusedstate(state)^.countunusedregsmm := countunusedregsmm;
  742. end;
  743. procedure trgobj.restoreUnusedState(var state: pointer);
  744. begin
  745. unusedregsint := punusedstate(state)^.unusedregsint;
  746. unusedregsfpu := punusedstate(state)^.unusedregsfpu;
  747. unusedregsmm := punusedstate(state)^.unusedregsmm;
  748. countunusedregsint := punusedstate(state)^.countunusedregsint;
  749. countunusedregsfpu := punusedstate(state)^.countunusedregsfpu;
  750. countunusedregsmm := punusedstate(state)^.countunusedregsmm;
  751. dispose(punusedstate(state));
  752. state := nil;
  753. end;
  754. {****************************************************************************
  755. TReference
  756. ****************************************************************************}
  757. procedure reference_reset(var ref : treference);
  758. begin
  759. FillChar(ref,sizeof(treference),0);
  760. end;
  761. procedure reference_reset_base(var ref : treference;base : tregister;offset : longint);
  762. begin
  763. FillChar(ref,sizeof(treference),0);
  764. ref.base:=base;
  765. ref.offset:=offset;
  766. end;
  767. procedure reference_reset_symbol(var ref : treference;sym : tasmsymbol;offset : longint);
  768. begin
  769. FillChar(ref,sizeof(treference),0);
  770. ref.symbol:=sym;
  771. ref.offset:=offset;
  772. end;
  773. procedure reference_release(list: taasmoutput; const ref : treference);
  774. begin
  775. rg.ungetreference(list,ref);
  776. end;
  777. function references_equal(sref : treference;dref : treference):boolean;
  778. begin
  779. references_equal:=CompareByte(sref,dref,sizeof(treference))=0;
  780. end;
  781. { on most processors , this routine does nothing, overriden currently }
  782. { only by 80x86 processor. }
  783. function trgobj.makeregsize(reg: tregister; size: tcgsize): tregister;
  784. begin
  785. makeregsize := reg;
  786. end;
  787. {****************************************************************************
  788. TLocation
  789. ****************************************************************************}
  790. procedure location_reset(var l : tlocation;lt:TLoc;lsize:TCGSize);
  791. begin
  792. FillChar(l,sizeof(tlocation),0);
  793. l.loc:=lt;
  794. l.size:=lsize;
  795. end;
  796. procedure location_release(list: taasmoutput; const l : tlocation);
  797. begin
  798. case l.loc of
  799. LOC_REGISTER,LOC_CREGISTER :
  800. begin
  801. rg.ungetregisterint(list,l.register);
  802. if l.size in [OS_64,OS_S64] then
  803. rg.ungetregisterint(list,l.registerhigh);
  804. end;
  805. LOC_CREFERENCE,LOC_REFERENCE :
  806. rg.ungetreference(list, l.reference);
  807. end;
  808. end;
  809. procedure location_freetemp(list:taasmoutput; const l : tlocation);
  810. begin
  811. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  812. tg.ungetiftemp(list,l.reference);
  813. end;
  814. procedure location_copy(var destloc,sourceloc : tlocation);
  815. begin
  816. destloc:=sourceloc;
  817. end;
  818. procedure location_swap(var destloc,sourceloc : tlocation);
  819. var
  820. swapl : tlocation;
  821. begin
  822. swapl := destloc;
  823. destloc := sourceloc;
  824. sourceloc := swapl;
  825. end;
  826. initialization
  827. ;
  828. finalization
  829. rg.free;
  830. end.
  831. {
  832. $Log$
  833. Revision 1.20 2002-10-05 12:43:28 carl
  834. * fixes for Delphi 6 compilation
  835. (warning : Some features do not work under Delphi)
  836. Revision 1.19 2002/08/23 16:14:49 peter
  837. * tempgen cleanup
  838. * tt_noreuse temp type added that will be used in genentrycode
  839. Revision 1.18 2002/08/17 22:09:47 florian
  840. * result type handling in tcgcal.pass_2 overhauled
  841. * better tnode.dowrite
  842. * some ppc stuff fixed
  843. Revision 1.17 2002/08/17 09:23:42 florian
  844. * first part of procinfo rewrite
  845. Revision 1.16 2002/08/06 20:55:23 florian
  846. * first part of ppc calling conventions fix
  847. Revision 1.15 2002/08/05 18:27:48 carl
  848. + more more more documentation
  849. + first version include/exclude (can't test though, not enough scratch for i386 :()...
  850. Revision 1.14 2002/08/04 19:06:41 carl
  851. + added generic exception support (still does not work!)
  852. + more documentation
  853. Revision 1.13 2002/07/07 09:52:32 florian
  854. * powerpc target fixed, very simple units can be compiled
  855. * some basic stuff for better callparanode handling, far from being finished
  856. Revision 1.12 2002/07/01 18:46:26 peter
  857. * internal linker
  858. * reorganized aasm layer
  859. Revision 1.11 2002/05/18 13:34:17 peter
  860. * readded missing revisions
  861. Revision 1.10 2002/05/16 19:46:44 carl
  862. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  863. + try to fix temp allocation (still in ifdef)
  864. + generic constructor calls
  865. + start of tassembler / tmodulebase class cleanup
  866. Revision 1.8 2002/04/21 15:23:03 carl
  867. + makeregsize
  868. + changeregsize is now a local routine
  869. Revision 1.7 2002/04/20 21:32:25 carl
  870. + generic FPC_CHECKPOINTER
  871. + first parameter offset in stack now portable
  872. * rename some constants
  873. + move some cpu stuff to other units
  874. - remove unused constents
  875. * fix stacksize for some targets
  876. * fix generic size problems which depend now on EXTEND_SIZE constant
  877. Revision 1.6 2002/04/15 19:03:31 carl
  878. + reg2str -> std_reg2str()
  879. Revision 1.5 2002/04/06 18:13:01 jonas
  880. * several powerpc-related additions and fixes
  881. Revision 1.4 2002/04/04 19:06:04 peter
  882. * removed unused units
  883. * use tlocation.size in cg.a_*loc*() routines
  884. Revision 1.3 2002/04/02 17:11:29 peter
  885. * tlocation,treference update
  886. * LOC_CONSTANT added for better constant handling
  887. * secondadd splitted in multiple routines
  888. * location_force_reg added for loading a location to a register
  889. of a specified size
  890. * secondassignment parses now first the right and then the left node
  891. (this is compatible with Kylix). This saves a lot of push/pop especially
  892. with string operations
  893. * adapted some routines to use the new cg methods
  894. Revision 1.2 2002/04/01 19:24:25 jonas
  895. * fixed different parameter name in interface and implementation
  896. declaration of a method (only 1.0.x detected this)
  897. Revision 1.1 2002/03/31 20:26:36 jonas
  898. + a_loadfpu_* and a_loadmm_* methods in tcg
  899. * register allocation is now handled by a class and is mostly processor
  900. independent (+rgobj.pas and i386/rgcpu.pas)
  901. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  902. * some small improvements and fixes to the optimizer
  903. * some register allocation fixes
  904. * some fpuvaroffset fixes in the unary minus node
  905. * push/popusedregisters is now called rg.save/restoreusedregisters and
  906. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  907. also better optimizable)
  908. * fixed and optimized register saving/restoring for new/dispose nodes
  909. * LOC_FPU locations now also require their "register" field to be set to
  910. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  911. - list field removed of the tnode class because it's not used currently
  912. and can cause hard-to-find bugs
  913. }