rgobj.pas 38 KB

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