rgobj.pas 33 KB

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