rgcpu.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the i386 specific class for the register
  5. allocator
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit rgcpu;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cpubase,
  24. cpuinfo,
  25. aasmbase,aasmtai,aasmcpu,
  26. cclasses,globtype,cgbase,cginfo,rgobj;
  27. type
  28. trgcpu = class(trgobj)
  29. fpuvaroffset : byte;
  30. { to keep the same allocation order as with the old routines }
  31. function getregisterint(list: taasmoutput): tregister; override;
  32. procedure ungetregisterint(list: taasmoutput; r : tregister); override;
  33. function getexplicitregisterint(list: taasmoutput; r : Toldregister) : tregister; override;
  34. function getregisterfpu(list: taasmoutput) : tregister; override;
  35. procedure ungetregisterfpu(list: taasmoutput; r : tregister); override;
  36. procedure ungetreference(list: taasmoutput; const ref : treference); override;
  37. {# Returns a subset register of the register r with the specified size.
  38. WARNING: There is no clearing of the upper parts of the register,
  39. if a 8-bit / 16-bit register is converted to a 32-bit register.
  40. It is up to the code generator to correctly zero fill the register
  41. }
  42. function makeregsize(reg: tregister; size: tcgsize): tregister; override;
  43. { pushes and restores registers }
  44. procedure pushusedregisters(list: taasmoutput;
  45. var pushed : tpushedsaved;const s: tregisterset);
  46. procedure popusedregisters(list: taasmoutput;
  47. const pushed : tpushedsaved);
  48. procedure saveusedregisters(list: taasmoutput;
  49. var saved : tpushedsaved;const s: tregisterset);override;
  50. procedure restoreusedregisters(list: taasmoutput;
  51. const saved : tpushedsaved);override;
  52. procedure resetusableregisters;override;
  53. { corrects the fpu stack register by ofs }
  54. function correct_fpuregister(r : tregister;ofs : byte) : tregister;
  55. end;
  56. implementation
  57. uses
  58. systems,
  59. globals,verbose,
  60. tgobj;
  61. {************************************************************************}
  62. { routine helpers }
  63. {************************************************************************}
  64. const
  65. reg2reg32 : array[firstreg..lastreg] of Toldregister = (R_NO,
  66. R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
  67. R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
  68. R_EAX,R_ECX,R_EDX,R_EBX,R_NO,R_NO,R_NO,R_NO,
  69. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  70. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  71. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  72. R_NO,R_NO,R_NO,R_NO,
  73. R_NO,R_NO,R_NO,R_NO,R_NO,
  74. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  75. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO
  76. );
  77. reg2reg16 : array[firstreg..lastreg] of Toldregister = (R_NO,
  78. R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
  79. R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
  80. R_AX,R_CX,R_DX,R_BX,R_NO,R_NO,R_NO,R_NO,
  81. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  82. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  83. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  84. R_NO,R_NO,R_NO,R_NO,
  85. R_NO,R_NO,R_NO,R_NO,R_NO,
  86. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  87. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO
  88. );
  89. reg2reg8 : array[firstreg..lastreg] of Toldregister = (R_NO,
  90. R_AL,R_CL,R_DL,R_BL,R_NO,R_NO,R_NO,R_NO,
  91. R_AL,R_CL,R_DL,R_BL,R_NO,R_NO,R_NO,R_NO,
  92. R_AL,R_CL,R_DL,R_BL,R_NO,R_NO,R_NO,R_NO,
  93. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  94. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  95. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  96. R_NO,R_NO,R_NO,R_NO,
  97. R_NO,R_NO,R_NO,R_NO,R_NO,
  98. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,
  99. R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO,R_NO
  100. );
  101. { convert a register to a specfied register size }
  102. function changeregsize(r:tregister;size:topsize):tregister;
  103. var
  104. reg : tregister;
  105. begin
  106. case size of
  107. S_B :
  108. reg.enum:=reg2reg8[r.enum];
  109. S_W :
  110. reg.enum:=reg2reg16[r.enum];
  111. S_L :
  112. reg.enum:=reg2reg32[r.enum];
  113. else
  114. internalerror(200204101);
  115. end;
  116. if reg.enum=R_NO then
  117. internalerror(200204102);
  118. changeregsize:=reg;
  119. end;
  120. {************************************************************************}
  121. { trgcpu }
  122. {************************************************************************}
  123. function trgcpu.getregisterint(list: taasmoutput): tregister;
  124. begin
  125. if countunusedregsint=0 then
  126. internalerror(10);
  127. {$ifdef TEMPREGDEBUG}
  128. if curptree^.usableregsint-countunusedregsint>curptree^.registers32 then
  129. internalerror(10);
  130. {$endif TEMPREGDEBUG}
  131. {$ifdef EXTTEMPREGDEBUG}
  132. if curptree^.usableregs-countunusedregistersint>curptree^^.reallyusedregs then
  133. curptree^.reallyusedregs:=curptree^^.usableregs-countunusedregistersint;
  134. {$endif EXTTEMPREGDEBUG}
  135. dec(countunusedregsint);
  136. if R_EAX in unusedregsint then
  137. begin
  138. exclude(unusedregsint,R_EAX);
  139. include(usedinproc,R_EAX);
  140. getregisterint.enum:=R_EAX;
  141. {$ifdef TEMPREGDEBUG}
  142. reg_user[R_EAX]:=curptree^;
  143. {$endif TEMPREGDEBUG}
  144. exprasmlist.concat(tai_regalloc.alloc(getregisterint));
  145. end
  146. else if R_EDX in unusedregsint then
  147. begin
  148. exclude(unusedregsint,R_EDX);
  149. include(usedinproc,R_EDX);
  150. getregisterint.enum:=R_EDX;
  151. {$ifdef TEMPREGDEBUG}
  152. reg_user[R_EDX]:=curptree^;
  153. {$endif TEMPREGDEBUG}
  154. exprasmlist.concat(tai_regalloc.alloc(getregisterint));
  155. end
  156. else if R_EBX in unusedregsint then
  157. begin
  158. exclude(unusedregsint,R_EBX);
  159. include(usedinproc,R_EBX);
  160. getregisterint.enum:=R_EBX;
  161. {$ifdef TEMPREGDEBUG}
  162. reg_user[R_EBX]:=curptree^;
  163. {$endif TEMPREGDEBUG}
  164. exprasmlist.concat(tai_regalloc.alloc(getregisterint));
  165. end
  166. else if R_ECX in unusedregsint then
  167. begin
  168. exclude(unusedregsint,R_ECX);
  169. include(usedinproc,R_ECX);
  170. getregisterint.enum:=R_ECX;
  171. {$ifdef TEMPREGDEBUG}
  172. reg_user[R_ECX]:=curptree^;
  173. {$endif TEMPREGDEBUG}
  174. exprasmlist.concat(tai_regalloc.alloc(getregisterint));
  175. end
  176. else internalerror(10);
  177. {$ifdef TEMPREGDEBUG}
  178. testregisters;
  179. {$endif TEMPREGDEBUG}
  180. end;
  181. procedure trgcpu.ungetregisterint(list: taasmoutput; r : tregister);
  182. begin
  183. if r.enum=R_NO then
  184. exit;
  185. r := makeregsize(r,OS_INT);
  186. if r.enum>lastreg then
  187. internalerror(200301081);
  188. if (r.enum = R_EDI) or
  189. ((not assigned(procinfo._class)) and (r.enum = R_ESI)) then
  190. begin
  191. list.concat(tai_regalloc.DeAlloc(r));
  192. exit;
  193. end;
  194. if not(r.enum in [R_EAX,R_EBX,R_ECX,R_EDX]) then
  195. exit;
  196. inherited ungetregisterint(list,r);
  197. end;
  198. function trgcpu.getexplicitregisterint(list: taasmoutput; r : Toldregister) : tregister;
  199. var r2:Tregister;
  200. begin
  201. if r in [R_ESI,R_EDI] then
  202. begin
  203. r2.enum:=r;
  204. list.concat(tai_regalloc.Alloc(r2));
  205. getexplicitregisterint := r2;
  206. exit;
  207. end;
  208. result := inherited getexplicitregisterint(list,r);
  209. end;
  210. function trgcpu.getregisterfpu(list: taasmoutput) : tregister;
  211. begin
  212. { note: don't return R_ST0, see comments above implementation of }
  213. { a_loadfpu_* methods in cgcpu (JM) }
  214. result.enum := R_ST;
  215. end;
  216. procedure trgcpu.ungetregisterfpu(list : taasmoutput; r : tregister);
  217. begin
  218. { nothing to do, fpu stack management is handled by the load/ }
  219. { store operations in cgcpu (JM) }
  220. end;
  221. procedure trgcpu.ungetreference(list: taasmoutput; const ref : treference);
  222. begin
  223. ungetregisterint(list,ref.base);
  224. ungetregisterint(list,ref.index);
  225. end;
  226. procedure trgcpu.pushusedregisters(list: taasmoutput;
  227. var pushed : tpushedsaved; const s: tregisterset);
  228. var
  229. r: Toldregister;
  230. r2: Tregister;
  231. {$ifdef SUPPORT_MMX}
  232. hr : treference;
  233. {$endif SUPPORT_MMX}
  234. begin
  235. usedinproc:=usedinproc + s;
  236. for r:=R_EAX to R_EBX do
  237. begin
  238. r2.enum:=r;
  239. pushed[r].pushed:=false;
  240. { if the register is used by the calling subroutine }
  241. if not is_reg_var[r] and
  242. (r in s) and
  243. { and is present in use }
  244. not(r in unusedregsint) then
  245. begin
  246. { then save it }
  247. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r2));
  248. include(unusedregsint,r);
  249. inc(countunusedregsint);
  250. pushed[r].pushed:=true;
  251. end;
  252. end;
  253. {$ifdef SUPPORT_MMX}
  254. for r:=R_MM0 to R_MM6 do
  255. begin
  256. pushed[r].pushed:=false;
  257. { if the register is used by the calling subroutine }
  258. if not is_reg_var[r] and
  259. (r in s) and
  260. { and is present in use }
  261. not(r in unusedregsmm) then
  262. begin
  263. r2.enum:=R_ESP;
  264. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,8,r2));
  265. reference_reset_base(hr,r2,0);
  266. r2.enum:=r;
  267. list.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,r2,hr));
  268. include(unusedregsmm,r);
  269. inc(countunusedregsmm);
  270. pushed[r].pushed:=true;
  271. end;
  272. end;
  273. {$endif SUPPORT_MMX}
  274. {$ifdef TEMPREGDEBUG}
  275. testregisters;
  276. {$endif TEMPREGDEBUG}
  277. end;
  278. procedure trgcpu.popusedregisters(list: taasmoutput;
  279. const pushed : tpushedsaved);
  280. var
  281. r : Toldregister;
  282. r2,r3 : Tregister;
  283. {$ifdef SUPPORT_MMX}
  284. hr : treference;
  285. {$endif SUPPORT_MMX}
  286. begin
  287. { restore in reverse order: }
  288. {$ifdef SUPPORT_MMX}
  289. for r:=R_MM6 downto R_MM0 do
  290. if pushed[r].pushed then
  291. begin
  292. r2.enum:=R_ESP;
  293. reference_reset_base(hr,r2,0);
  294. r3.enum:=r;
  295. list.concat(Taicpu.Op_ref_reg(
  296. A_MOVQ,S_NO,hr,r3));
  297. list.concat(Taicpu.Op_const_reg(
  298. A_ADD,S_L,8,r2));
  299. if not (r in unusedregsmm) then
  300. { internalerror(10)
  301. in cg386cal we always restore regs
  302. that appear as used
  303. due to a unused tmep storage PM }
  304. else
  305. dec(countunusedregsmm);
  306. exclude(unusedregsmm,r);
  307. end;
  308. {$endif SUPPORT_MMX}
  309. for r:=R_EBX downto R_EAX do
  310. if pushed[r].pushed then
  311. begin
  312. r2.enum:=r;
  313. list.concat(Taicpu.Op_reg(A_POP,S_L,r2));
  314. if not (r in unusedregsint) then
  315. { internalerror(10)
  316. in cg386cal we always restore regs
  317. that appear as used
  318. due to a unused tmep storage PM }
  319. else
  320. dec(countunusedregsint);
  321. exclude(unusedregsint,r);
  322. end;
  323. {$ifdef TEMPREGDEBUG}
  324. testregisters;
  325. {$endif TEMPREGDEBUG}
  326. end;
  327. procedure trgcpu.saveusedregisters(list: taasmoutput;var saved : tpushedsaved;
  328. const s: tregisterset);
  329. begin
  330. if (aktoptprocessor in [class386,classP5]) or
  331. (CS_LittleSize in aktglobalswitches) then
  332. pushusedregisters(list,saved,s)
  333. else
  334. inherited saveusedregisters(list,saved,s);
  335. end;
  336. procedure trgcpu.restoreusedregisters(list: taasmoutput;
  337. const saved : tpushedsaved);
  338. begin
  339. if (aktoptprocessor in [class386,classP5]) or
  340. (CS_LittleSize in aktglobalswitches) then
  341. popusedregisters(list,saved)
  342. else
  343. inherited restoreusedregisters(list,saved);
  344. end;
  345. procedure trgcpu.resetusableregisters;
  346. begin
  347. inherited resetusableregisters;
  348. fpuvaroffset := 0;
  349. end;
  350. function trgcpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
  351. begin
  352. correct_fpuregister.enum:=Toldregister(longint(r.enum)+ofs);
  353. end;
  354. function trgcpu.makeregsize(reg: tregister; size: tcgsize): tregister;
  355. var
  356. _result : topsize;
  357. begin
  358. case size of
  359. OS_32,OS_S32:
  360. begin
  361. _result := S_L;
  362. end;
  363. OS_8,OS_S8:
  364. begin
  365. _result := S_B;
  366. end;
  367. OS_16,OS_S16:
  368. begin
  369. _result := S_W;
  370. end;
  371. else
  372. internalerror(2001092312);
  373. end;
  374. makeregsize := changeregsize(reg,_result);
  375. end;
  376. initialization
  377. rg := trgcpu.create;
  378. end.
  379. {
  380. $Log$
  381. Revision 1.11 2003-01-08 18:43:57 daniel
  382. * Tregister changed into a record
  383. Revision 1.10 2002/10/05 12:43:29 carl
  384. * fixes for Delphi 6 compilation
  385. (warning : Some features do not work under Delphi)
  386. Revision 1.9 2002/08/17 09:23:48 florian
  387. * first part of procinfo rewrite
  388. Revision 1.8 2002/07/01 18:46:34 peter
  389. * internal linker
  390. * reorganized aasm layer
  391. Revision 1.7 2002/05/16 19:46:52 carl
  392. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  393. + try to fix temp allocation (still in ifdef)
  394. + generic constructor calls
  395. + start of tassembler / tmodulebase class cleanup
  396. Revision 1.6 2002/05/12 16:53:18 peter
  397. * moved entry and exitcode to ncgutil and cgobj
  398. * foreach gets extra argument for passing local data to the
  399. iterator function
  400. * -CR checks also class typecasts at runtime by changing them
  401. into as
  402. * fixed compiler to cycle with the -CR option
  403. * fixed stabs with elf writer, finally the global variables can
  404. be watched
  405. * removed a lot of routines from cga unit and replaced them by
  406. calls to cgobj
  407. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  408. u32bit then the other is typecasted also to u32bit without giving
  409. a rangecheck warning/error.
  410. * fixed pascal calling method with reversing also the high tree in
  411. the parast, detected by tcalcst3 test
  412. Revision 1.5 2002/04/21 15:43:32 carl
  413. * changeregsize -> rg.makeregsize
  414. * changeregsize moved from cpubase to here
  415. Revision 1.4 2002/04/15 19:44:22 peter
  416. * fixed stackcheck that would be called recursively when a stack
  417. error was found
  418. * generic changeregsize(reg,size) for i386 register resizing
  419. * removed some more routines from cga unit
  420. * fixed returnvalue handling
  421. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  422. Revision 1.3 2002/04/04 19:06:13 peter
  423. * removed unused units
  424. * use tlocation.size in cg.a_*loc*() routines
  425. Revision 1.2 2002/04/02 17:11:39 peter
  426. * tlocation,treference update
  427. * LOC_CONSTANT added for better constant handling
  428. * secondadd splitted in multiple routines
  429. * location_force_reg added for loading a location to a register
  430. of a specified size
  431. * secondassignment parses now first the right and then the left node
  432. (this is compatible with Kylix). This saves a lot of push/pop especially
  433. with string operations
  434. * adapted some routines to use the new cg methods
  435. Revision 1.1 2002/03/31 20:26:40 jonas
  436. + a_loadfpu_* and a_loadmm_* methods in tcg
  437. * register allocation is now handled by a class and is mostly processor
  438. independent (+rgobj.pas and i386/rgcpu.pas)
  439. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  440. * some small improvements and fixes to the optimizer
  441. * some register allocation fixes
  442. * some fpuvaroffset fixes in the unary minus node
  443. * push/popusedregisters is now called rg.save/restoreusedregisters and
  444. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  445. also better optimizable)
  446. * fixed and optimized register saving/restoring for new/dispose nodes
  447. * LOC_FPU locations now also require their "register" field to be set to
  448. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  449. - list field removed of the tnode class because it's not used currently
  450. and can cause hard-to-find bugs
  451. }