rgx86.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit implements the x86 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 rgx86;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. cclasses,globtype,
  24. cpubase,cpuinfo,cgbase,cgutils,
  25. aasmbase,aasmtai,aasmcpu,
  26. rgobj;
  27. type
  28. trgx86 = class(trgobj)
  29. function get_spill_subreg(r : tregister) : tsubregister;override;
  30. function do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;override;
  31. end;
  32. tpushedsavedloc = record
  33. case byte of
  34. 0: (pushed: boolean);
  35. 1: (ofs: longint);
  36. end;
  37. tpushedsavedfpu = array[tsuperregister] of tpushedsavedloc;
  38. trgx86fpu = class
  39. { The "usableregsxxx" contain all registers of type "xxx" that }
  40. { aren't currently allocated to a regvar. The "unusedregsxxx" }
  41. { contain all registers of type "xxx" that aren't currently }
  42. { allocated }
  43. unusedregsfpu,usableregsfpu : Tsuperregisterset;
  44. { these counters contain the number of elements in the }
  45. { unusedregsxxx/usableregsxxx sets }
  46. countunusedregsfpu : byte;
  47. { Contains the registers which are really used by the proc itself.
  48. It doesn't take care of registers used by called procedures
  49. }
  50. used_in_proc : tcpuregisterset;
  51. {reg_pushes_other : regvarother_longintarray;
  52. is_reg_var_other : regvarother_booleanarray;
  53. regvar_loaded_other : regvarother_booleanarray;}
  54. { tries to hold the amount of times which the current tree is processed }
  55. t_times: longint;
  56. fpuvaroffset : byte;
  57. constructor create;
  58. function getregisterfpu(list: taasmoutput) : tregister;
  59. procedure ungetregisterfpu(list: taasmoutput; r : tregister);
  60. { pushes and restores registers }
  61. procedure saveusedfpuregisters(list:Taasmoutput;
  62. var saved:Tpushedsavedfpu;
  63. const s:Tcpuregisterset);
  64. procedure restoreusedfpuregisters(list:Taasmoutput;
  65. const saved:Tpushedsavedfpu);
  66. { corrects the fpu stack register by ofs }
  67. function correct_fpuregister(r : tregister;ofs : byte) : tregister;
  68. end;
  69. implementation
  70. uses
  71. systems,
  72. verbose;
  73. const
  74. { This value is used in tsaved. If the array value is equal
  75. to this, then this means that this register is not used.}
  76. reg_not_saved = $7fffffff;
  77. {******************************************************************************
  78. Trgcpu
  79. ******************************************************************************}
  80. function trgx86.get_spill_subreg(r : tregister) : tsubregister;
  81. begin
  82. result:=getsubreg(r);
  83. end;
  84. function trgx86.do_spill_replace(list:Taasmoutput;instr:taicpu;orgreg:tsuperregister;const spilltemp:treference):boolean;
  85. var
  86. replaceoper : longint;
  87. begin
  88. result:=false;
  89. with instr do
  90. begin
  91. replaceoper:=-1;
  92. case ops of
  93. 1 :
  94. begin
  95. if (oper[0]^.typ=top_reg) then
  96. begin
  97. if getsupreg(oper[0]^.reg)<>orgreg then
  98. internalerror(200410101);
  99. replaceoper:=0;
  100. end;
  101. end;
  102. 2,3 :
  103. begin
  104. { We can handle opcodes with 2 and 3 operands the same way. The opcodes
  105. with 3 registers are shrd/shld, where the 3rd operand is const or CL,
  106. that doesn't need spilling }
  107. if (oper[0]^.typ=top_reg) and
  108. (oper[1]^.typ=top_reg) and
  109. (getsupreg(oper[0]^.reg)<>getsupreg(oper[1]^.reg)) then
  110. begin
  111. { One of the arguments shall be able to be replaced }
  112. if (getregtype(oper[0]^.reg)=regtype) and
  113. (getsupreg(oper[0]^.reg)=orgreg) then
  114. replaceoper:=0
  115. else
  116. if (getregtype(oper[0]^.reg)=regtype) and
  117. (getsupreg(oper[1]^.reg)=orgreg) then
  118. replaceoper:=1
  119. else
  120. internalerror(200410101);
  121. case replaceoper of
  122. 0 :
  123. begin
  124. { Some instructions don't allow memory references
  125. for source }
  126. case instr.opcode of
  127. A_BT,
  128. A_BTS,
  129. A_BTC,
  130. A_BTR :
  131. replaceoper:=-1;
  132. end;
  133. end;
  134. 1 :
  135. begin
  136. { Some instructions don't allow memory references
  137. for destination }
  138. case instr.opcode of
  139. A_MOVZX,
  140. A_MOVSX,
  141. A_MULSS,
  142. A_MULSD,
  143. A_SUBSS,
  144. A_SUBSD,
  145. A_ADDSD,
  146. A_ADDSS,
  147. A_DIVSD,
  148. A_DIVSS,
  149. A_SHLD,
  150. A_SHRD,
  151. A_IMUL :
  152. replaceoper:=-1;
  153. end;
  154. end;
  155. end;
  156. end;
  157. end;
  158. end;
  159. { Replace register with spill reference }
  160. if replaceoper<>-1 then
  161. begin
  162. oper[replaceoper]^.typ:=top_ref;
  163. new(oper[replaceoper]^.ref);
  164. oper[replaceoper]^.ref^:=spilltemp;
  165. result:=true;
  166. end;
  167. end;
  168. end;
  169. {******************************************************************************
  170. Trgx86fpu
  171. ******************************************************************************}
  172. constructor Trgx86fpu.create;
  173. begin
  174. used_in_proc:=[];
  175. t_times := 0;
  176. unusedregsfpu:=usableregsfpu;
  177. end;
  178. function trgx86fpu.getregisterfpu(list: taasmoutput) : tregister;
  179. begin
  180. { note: don't return R_ST0, see comments above implementation of }
  181. { a_loadfpu_* methods in cgcpu (JM) }
  182. result:=NR_ST;
  183. end;
  184. procedure trgx86fpu.ungetregisterfpu(list : taasmoutput; r : tregister);
  185. begin
  186. { nothing to do, fpu stack management is handled by the load/ }
  187. { store operations in cgcpu (JM) }
  188. end;
  189. function trgx86fpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
  190. begin
  191. correct_fpuregister:=r;
  192. setsupreg(correct_fpuregister,ofs);
  193. end;
  194. procedure trgx86fpu.saveusedfpuregisters(list: taasmoutput;
  195. var saved : tpushedsavedfpu;
  196. const s: tcpuregisterset);
  197. var
  198. r : tregister;
  199. hr : treference;
  200. begin
  201. used_in_proc:=used_in_proc+s;
  202. {$warning TODO firstsavefpureg}
  203. (*
  204. { don't try to save the fpu registers if not desired (e.g. for }
  205. { the 80x86) }
  206. if firstsavefpureg <> R_NO then
  207. for r.enum:=firstsavefpureg to lastsavefpureg do
  208. begin
  209. saved[r.enum].ofs:=reg_not_saved;
  210. { if the register is used by the calling subroutine and if }
  211. { it's not a regvar (those are handled separately) }
  212. if not is_reg_var_other[r.enum] and
  213. (r.enum in s) and
  214. { and is present in use }
  215. not(r.enum in unusedregsfpu) then
  216. begin
  217. { then save it }
  218. tg.GetTemp(list,extended_size,tt_persistent,hr);
  219. saved[r.enum].ofs:=hr.offset;
  220. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  221. cg.a_reg_dealloc(list,r);
  222. include(unusedregsfpu,r.enum);
  223. inc(countunusedregsfpu);
  224. end;
  225. end;
  226. *)
  227. end;
  228. procedure trgx86fpu.restoreusedfpuregisters(list : taasmoutput;
  229. const saved : tpushedsavedfpu);
  230. var
  231. r,r2 : tregister;
  232. hr : treference;
  233. begin
  234. {$warning TODO firstsavefpureg}
  235. (*
  236. if firstsavefpureg <> R_NO then
  237. for r.enum:=lastsavefpureg downto firstsavefpureg do
  238. begin
  239. if saved[r.enum].ofs <> reg_not_saved then
  240. begin
  241. r2.enum:=R_INTREGISTER;
  242. r2.number:=NR_FRAME_POINTER_REG;
  243. reference_reset_base(hr,r2,saved[r.enum].ofs);
  244. cg.a_reg_alloc(list,r);
  245. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  246. if not (r.enum in unusedregsfpu) then
  247. { internalerror(10)
  248. in n386cal we always save/restore the reg *state*
  249. using save/restoreunusedstate -> the current state
  250. may not be real (JM) }
  251. else
  252. begin
  253. dec(countunusedregsfpu);
  254. exclude(unusedregsfpu,r.enum);
  255. end;
  256. tg.UnGetTemp(list,hr);
  257. end;
  258. end;
  259. *)
  260. end;
  261. (*
  262. procedure Trgx86fpu.saveotherregvars(list: taasmoutput; const s: totherregisterset);
  263. var
  264. r: Tregister;
  265. begin
  266. if not(cs_regvars in aktglobalswitches) then
  267. exit;
  268. if firstsavefpureg <> NR_NO then
  269. for r.enum := firstsavefpureg to lastsavefpureg do
  270. if is_reg_var_other[r.enum] and
  271. (r.enum in s) then
  272. store_regvar(list,r);
  273. end;
  274. *)
  275. end.
  276. {
  277. $Log$
  278. Revision 1.13 2005-03-10 00:27:04 peter
  279. movzx,movsx don't support memory destinations
  280. Revision 1.12 2005/02/14 17:13:10 peter
  281. * truncate log
  282. }