rgx86.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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_MULSS,
  140. A_MULSD,
  141. A_SUBSS,
  142. A_SUBSD,
  143. A_ADDSD,
  144. A_ADDSS,
  145. A_DIVSD,
  146. A_DIVSS,
  147. A_SHLD,
  148. A_SHRD,
  149. A_IMUL :
  150. replaceoper:=-1;
  151. end;
  152. end;
  153. end;
  154. end;
  155. end;
  156. end;
  157. { Replace register with spill reference }
  158. if replaceoper<>-1 then
  159. begin
  160. oper[replaceoper]^.typ:=top_ref;
  161. new(oper[replaceoper]^.ref);
  162. oper[replaceoper]^.ref^:=spilltemp;
  163. result:=true;
  164. end;
  165. end;
  166. end;
  167. {******************************************************************************
  168. Trgx86fpu
  169. ******************************************************************************}
  170. constructor Trgx86fpu.create;
  171. begin
  172. used_in_proc:=[];
  173. t_times := 0;
  174. unusedregsfpu:=usableregsfpu;
  175. end;
  176. function trgx86fpu.getregisterfpu(list: taasmoutput) : tregister;
  177. begin
  178. { note: don't return R_ST0, see comments above implementation of }
  179. { a_loadfpu_* methods in cgcpu (JM) }
  180. result:=NR_ST;
  181. end;
  182. procedure trgx86fpu.ungetregisterfpu(list : taasmoutput; r : tregister);
  183. begin
  184. { nothing to do, fpu stack management is handled by the load/ }
  185. { store operations in cgcpu (JM) }
  186. end;
  187. function trgx86fpu.correct_fpuregister(r : tregister;ofs : byte) : tregister;
  188. begin
  189. correct_fpuregister:=r;
  190. setsupreg(correct_fpuregister,ofs);
  191. end;
  192. procedure trgx86fpu.saveusedfpuregisters(list: taasmoutput;
  193. var saved : tpushedsavedfpu;
  194. const s: tcpuregisterset);
  195. var
  196. r : tregister;
  197. hr : treference;
  198. begin
  199. used_in_proc:=used_in_proc+s;
  200. {$warning TODO firstsavefpureg}
  201. (*
  202. { don't try to save the fpu registers if not desired (e.g. for }
  203. { the 80x86) }
  204. if firstsavefpureg <> R_NO then
  205. for r.enum:=firstsavefpureg to lastsavefpureg do
  206. begin
  207. saved[r.enum].ofs:=reg_not_saved;
  208. { if the register is used by the calling subroutine and if }
  209. { it's not a regvar (those are handled separately) }
  210. if not is_reg_var_other[r.enum] and
  211. (r.enum in s) and
  212. { and is present in use }
  213. not(r.enum in unusedregsfpu) then
  214. begin
  215. { then save it }
  216. tg.GetTemp(list,extended_size,tt_persistent,hr);
  217. saved[r.enum].ofs:=hr.offset;
  218. cg.a_loadfpu_reg_ref(list,OS_FLOAT,r,hr);
  219. cg.a_reg_dealloc(list,r);
  220. include(unusedregsfpu,r.enum);
  221. inc(countunusedregsfpu);
  222. end;
  223. end;
  224. *)
  225. end;
  226. procedure trgx86fpu.restoreusedfpuregisters(list : taasmoutput;
  227. const saved : tpushedsavedfpu);
  228. var
  229. r,r2 : tregister;
  230. hr : treference;
  231. begin
  232. {$warning TODO firstsavefpureg}
  233. (*
  234. if firstsavefpureg <> R_NO then
  235. for r.enum:=lastsavefpureg downto firstsavefpureg do
  236. begin
  237. if saved[r.enum].ofs <> reg_not_saved then
  238. begin
  239. r2.enum:=R_INTREGISTER;
  240. r2.number:=NR_FRAME_POINTER_REG;
  241. reference_reset_base(hr,r2,saved[r.enum].ofs);
  242. cg.a_reg_alloc(list,r);
  243. cg.a_loadfpu_ref_reg(list,OS_FLOAT,hr,r);
  244. if not (r.enum in unusedregsfpu) then
  245. { internalerror(10)
  246. in n386cal we always save/restore the reg *state*
  247. using save/restoreunusedstate -> the current state
  248. may not be real (JM) }
  249. else
  250. begin
  251. dec(countunusedregsfpu);
  252. exclude(unusedregsfpu,r.enum);
  253. end;
  254. tg.UnGetTemp(list,hr);
  255. end;
  256. end;
  257. *)
  258. end;
  259. (*
  260. procedure Trgx86fpu.saveotherregvars(list: taasmoutput; const s: totherregisterset);
  261. var
  262. r: Tregister;
  263. begin
  264. if not(cs_regvars in aktglobalswitches) then
  265. exit;
  266. if firstsavefpureg <> NR_NO then
  267. for r.enum := firstsavefpureg to lastsavefpureg do
  268. if is_reg_var_other[r.enum] and
  269. (r.enum in s) then
  270. store_regvar(list,r);
  271. end;
  272. *)
  273. end.
  274. {
  275. $Log$
  276. Revision 1.11 2004-11-01 17:30:17 florian
  277. + added sse instruction being not be able writing to a memory location
  278. Revision 1.10 2004/10/31 21:45:04 peter
  279. * generic tlocation
  280. * move tlocation to cgutils
  281. Revision 1.9 2004/10/10 16:30:26 peter
  282. * optimized spilling writing when the reg operand can be
  283. replaced by reference
  284. Revision 1.8 2004/10/05 20:41:02 peter
  285. * more spilling rewrites
  286. Revision 1.7 2004/10/04 20:46:22 peter
  287. * spilling code rewritten for x86. It now used the generic
  288. spilling routines. Special x86 optimization still needs
  289. to be added.
  290. * Spilling fixed when both operands needed to be spilled
  291. * Cleanup of spilling routine, do_spill_readwritten removed
  292. Revision 1.6 2004/09/27 14:49:45 peter
  293. * handle 3 operand opcodes the same as 2 operand opcodes, the
  294. third operand can only be a const or register CL, so it doesn't
  295. affect spilling
  296. * support shrd/shld that don't allow memory operands
  297. Revision 1.5 2004/09/26 07:15:07 florian
  298. * ie checking in spilling code improved
  299. Revision 1.4 2004/06/20 08:55:32 florian
  300. * logs truncated
  301. Revision 1.3 2004/06/16 20:07:11 florian
  302. * dwarf branch merged
  303. Revision 1.2.2.1 2004/04/10 12:36:42 peter
  304. * fixed alignment issues
  305. Revision 1.2 2004/01/12 16:37:59 peter
  306. * moved spilling code from taicpu to rg
  307. }