rgcpu.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. {*****************************************************************************}
  2. { File : rgcpu.pas }
  3. { Author : Mazen NEIFER }
  4. { Project : Free Pascal Compiler (FPC) }
  5. { Creation date : 2002\26\26 }
  6. { Last modification date : 2002\08\20 }
  7. { Licence : GPL }
  8. { Bug report : [email protected] }
  9. {*****************************************************************************}
  10. {
  11. $Id$
  12. Copyright (c) 1998-2002 by Florian Klaempfl
  13. This unit implements the i386 specific class for the register
  14. allocator
  15. This program is free software; you can redistribute it and/or modify
  16. it under the terms of the GNU General Public License as published by
  17. the Free Software Foundation; either version 2 of the License, or
  18. (at your option) any later version.
  19. This program is distributed in the hope that it will be useful,
  20. but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. GNU General Public License for more details.
  23. You should have received a copy of the GNU General Public License
  24. along with this program; if not, write to the Free Software
  25. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26. ****************************************************************************
  27. }
  28. unit rgcpu;
  29. {$INCLUDE fpcdefs.inc}
  30. interface
  31. uses
  32. cpubase,
  33. cpuinfo,
  34. aasmcpu,
  35. aasmtai,
  36. cclasses,globtype,cgbase,aasmbase,rgobj;
  37. type
  38. trgcpu = class(trgobj)
  39. { to keep the same allocation order as with the old routines }
  40. function getregisterint(list: taasmoutput): tregister; override;
  41. procedure ungetregisterint(list: taasmoutput; r : tregister); override;
  42. function getexplicitregisterint(list: taasmoutput; r : tregister) : tregister; override;
  43. function getregisterfpu(list: taasmoutput) : tregister; override;
  44. procedure ungetregisterfpu(list: taasmoutput; r : tregister); override;
  45. procedure ungetreference(list: taasmoutput; const ref : treference); override;
  46. { pushes and restores registers }
  47. procedure pushusedregisters(list: taasmoutput;
  48. var pushed : tpushedsaved;const s: tregisterset);
  49. procedure popusedregisters(list: taasmoutput;
  50. const pushed : tpushedsaved);
  51. procedure resetusableregisters;override;
  52. { corrects the fpu stack register by ofs }
  53. function correct_fpuregister(r : tregister;ofs : byte) : tregister;
  54. fpuvaroffset : byte;
  55. end;
  56. implementation
  57. uses
  58. systems,
  59. globals,verbose,node,
  60. cgobj,tgobj,cga;
  61. function trgcpu.getregisterint(list: taasmoutput): tregister;
  62. begin
  63. if countunusedregsint=0 then
  64. internalerror(10);(*
  65. {$ifdef TEMPREGDEBUG}
  66. if curptree^.usableregsint-countunusedregsint>curptree^.registers32 then
  67. internalerror(10);
  68. {$endif TEMPREGDEBUG}
  69. {$ifdef EXTTEMPREGDEBUG}
  70. if curptree^.usableregs-countunusedregistersint>curptree^^.reallyusedregs then
  71. curptree^.reallyusedregs:=curptree^^.usableregs-countunusedregistersint;
  72. {$endif EXTTEMPREGDEBUG}
  73. dec(countunusedregsint);
  74. if R_EAX in unusedregsint then
  75. begin
  76. exclude(unusedregsint,R_EAX);
  77. include(usedinproc,R_EAX);
  78. getregisterint:=R_EAX;
  79. {$ifdef TEMPREGDEBUG}
  80. reg_user[R_EAX]:=curptree^;
  81. {$endif TEMPREGDEBUG}
  82. exprasmlist.concat(tairegalloc.alloc(R_EAX));
  83. end
  84. else if R_EDX in unusedregsint then
  85. begin
  86. exclude(unusedregsint,R_EDX);
  87. include(usedinproc,R_EDX);
  88. getregisterint:=R_EDX;
  89. {$ifdef TEMPREGDEBUG}
  90. reg_user[R_EDX]:=curptree^;
  91. {$endif TEMPREGDEBUG}
  92. exprasmlist.concat(tairegalloc.alloc(R_EDX));
  93. end
  94. else if R_EBX in unusedregsint then
  95. begin
  96. exclude(unusedregsint,R_EBX);
  97. include(usedinproc,R_EBX);
  98. getregisterint:=R_EBX;
  99. {$ifdef TEMPREGDEBUG}
  100. reg_user[R_EBX]:=curptree^;
  101. {$endif TEMPREGDEBUG}
  102. exprasmlist.concat(tairegalloc.alloc(R_EBX));
  103. end
  104. else if R_ECX in unusedregsint then
  105. begin
  106. exclude(unusedregsint,R_ECX);
  107. include(usedinproc,R_ECX);
  108. getregisterint:=R_ECX;
  109. {$ifdef TEMPREGDEBUG}
  110. reg_user[R_ECX]:=curptree^;
  111. {$endif TEMPREGDEBUG}
  112. exprasmlist.concat(tairegalloc.alloc(R_ECX));
  113. end
  114. else internalerror(10);
  115. {$ifdef TEMPREGDEBUG}
  116. testregisters;
  117. {$endif TEMPREGDEBUG}*)
  118. end;
  119. procedure trgcpu.ungetregisterint(list: taasmoutput; r : tregister);
  120. begin
  121. { if (r = R_EDI) or
  122. ((not assigned(procinfo^._class)) and (r = R_ESI)) then
  123. begin
  124. list.concat(Tairegalloc.DeAlloc(r));
  125. exit;
  126. end;
  127. if not(r in [R_EAX,R_EBX,R_ECX,R_EDX]) then
  128. exit;
  129. inherited ungetregisterint(list,r);}
  130. end;
  131. function trgcpu.getexplicitregisterint(list: taasmoutput; r : tregister) : tregister;
  132. begin
  133. { if r in [R_ESI,R_EDI] then
  134. begin
  135. list.concat(Tairegalloc.Alloc(r));
  136. getexplicitregisterint := r;
  137. exit;
  138. end;}
  139. result := inherited getexplicitregisterint(list,r);
  140. end;
  141. function trgcpu.getregisterfpu(list: taasmoutput) : tregister;
  142. begin
  143. { note: don't return R_ST0, see comments above implementation of }
  144. { a_loadfpu_* methods in cgcpu (JM) }
  145. // result := R_ST;
  146. end;
  147. procedure trgcpu.ungetregisterfpu(list : taasmoutput; r : tregister);
  148. begin
  149. { nothing to do, fpu stack management is handled by the load/ }
  150. { store operations in cgcpu (JM) }
  151. end;
  152. procedure trgcpu.ungetreference(list: taasmoutput; const ref : treference);
  153. begin
  154. ungetregisterint(list,ref.base);
  155. ungetregisterint(list,ref.index);
  156. end;
  157. procedure trgcpu.pushusedregisters(list: taasmoutput;
  158. var pushed : tpushedsaved; const s: tregisterset);
  159. var
  160. r: tregister;
  161. hr: treference;
  162. begin
  163. usedinproc:=usedinproc + s;
  164. (* for r:=R_EAX to R_EBX do
  165. begin
  166. pushed[r].pushed:=false;
  167. { if the register is used by the calling subroutine }
  168. if not is_reg_var[r] and
  169. (r in s) and
  170. { and is present in use }
  171. not(r in unusedregsint) then
  172. begin
  173. { then save it }
  174. list.concat(Taicpu.Op_reg(A_PUSH,S_L,r));
  175. include(unusedregsint,r);
  176. inc(countunusedregsint);
  177. pushed[r].pushed:=true;
  178. end;
  179. end;*)
  180. {$ifdef SUPPORT_MMX}
  181. (*for r:=R_MM0 to R_MM6 do
  182. begin
  183. pushed[r].pushed:=false;
  184. { if the register is used by the calling subroutine }
  185. if not is_reg_var[r] and
  186. (r in s) and
  187. { and is present in use }
  188. not(r in unusedregsmm) then
  189. begin
  190. list.concat(Taicpu.Op_const_reg(A_SUB,S_L,8,R_ESP));
  191. reference_reset_base(hr,R_ESP,0);
  192. list.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,r,hr));
  193. include(unusedregsmm,r);
  194. inc(countunusedregsmm);
  195. pushed[r].pushed:=true;
  196. end;
  197. end;*)
  198. {$endif SUPPORT_MMX}
  199. {$ifdef TEMPREGDEBUG}
  200. testregisters;
  201. {$endif TEMPREGDEBUG}
  202. end;
  203. procedure trgcpu.popusedregisters(list: taasmoutput;
  204. const pushed : tpushedsaved);
  205. var
  206. r : tregister;
  207. {$ifdef SUPPORT_MMX}
  208. hr : treference;
  209. {$endif SUPPORT_MMX}
  210. begin
  211. { restore in reverse order: }
  212. {$ifdef SUPPORT_MMX}
  213. for r:=R_MM6 downto R_MM0 do
  214. if pushed[r].pushed then
  215. begin
  216. reference_reset_base(hr,R_ESP,0);
  217. list.concat(Taicpu.Op_ref_reg(
  218. A_MOVQ,S_NO,hr,r));
  219. list.concat(Taicpu.Op_const_reg(
  220. A_ADD,S_L,8,R_ESP));
  221. if not (r in unusedregsmm) then
  222. { internalerror(10)
  223. in cg386cal we always restore regs
  224. that appear as used
  225. due to a unused tmep storage PM }
  226. else
  227. dec(countunusedregsmm);
  228. exclude(unusedregsmm,r);
  229. end;
  230. {$endif SUPPORT_MMX}
  231. (* for r:=R_EBX downto R_EAX do
  232. if pushed[r].pushed then
  233. begin
  234. list.concat(Taicpu.Op_reg(A_POP,S_L,r));
  235. if not (r in unusedregsint) then
  236. { internalerror(10)
  237. in cg386cal we always restore regs
  238. that appear as used
  239. due to a unused tmep storage PM }
  240. else
  241. dec(countunusedregsint);
  242. exclude(unusedregsint,r);
  243. end;*)
  244. {$ifdef TEMPREGDEBUG}
  245. testregisters;
  246. {$endif TEMPREGDEBUG}
  247. end;
  248. procedure trgcpu.resetusableregisters;
  249. begin
  250. inherited resetusableregisters;
  251. fpuvaroffset := 0;
  252. end;
  253. function trgcpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
  254. begin
  255. correct_fpuregister:=tregister(longint(r)+ofs);
  256. end;
  257. initialization
  258. rg := trgcpu.create;
  259. end.
  260. {
  261. $Log$
  262. Revision 1.1 2002-08-21 13:30:07 mazen
  263. *** empty log message ***
  264. Revision 1.2 2002/04/02 17:11:39 peter
  265. * tlocation,treference update
  266. * LOC_CONSTANT added for better constant handling
  267. * secondadd splitted in multiple routines
  268. * location_force_reg added for loading a location to a register
  269. of a specified size
  270. * secondassignment parses now first the right and then the left node
  271. (this is compatible with Kylix). This saves a lot of push/pop especially
  272. with string operations
  273. * adapted some routines to use the new cg methods
  274. Revision 1.1 2002/03/31 20:26:40 jonas
  275. + a_loadfpu_* and a_loadmm_* methods in tcg
  276. * register allocation is now handled by a class and is mostly processor
  277. independent (+rgobj.pas and i386/rgcpu.pas)
  278. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  279. * some small improvements and fixes to the optimizer
  280. * some register allocation fixes
  281. * some fpuvaroffset fixes in the unary minus node
  282. * fixed and optimized register saving/restoring for new/dispose nodes
  283. * LOC_FPU locations now also require their "register" field to be set to
  284. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  285. - list field removed of the tnode class because it's not used currently
  286. and can cause hard-to-find bugs
  287. }