tgen68k.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl, Carl Eric Codere
  4. This unit handles the temporary variables stuff for m68k
  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. unit tgen68k;
  19. interface
  20. uses
  21. cobjects,globals,tree,hcodegen,verbose,files,aasm,cpubase;
  22. type
  23. tregisterset = set of tregister;
  24. tpushed = array[R_D0..R_A6] of boolean;
  25. const
  26. { D2 to D5 usable as scratch registers }
  27. usablereg32 : byte = 4;
  28. { A2 to A4 usable as address registers }
  29. usableaddress: byte = 3;
  30. { FP2 to FP7 usable as FPU registers }
  31. usablefloatreg : byte = 6;
  32. function getregister32 : tregister;
  33. procedure ungetregister32(r : tregister);
  34. { return a free 32-bit address register }
  35. function getaddressreg: tregister;
  36. procedure ungetregister(r : tregister);
  37. procedure cleartempgen;
  38. function getfloatreg: tregister;
  39. { returns a free floating point register }
  40. { used in real, fpu mode, otherwise we }
  41. { must use standard register allocation }
  42. procedure del_reference(const ref : treference);
  43. procedure del_locref(const location : tlocation);
  44. { pushs and restores registers }
  45. procedure pushusedregisters(var pushed : tpushed;b : word);
  46. procedure popusedregisters(const pushed : tpushed);
  47. procedure clearregistercount;
  48. procedure resetusableregisters;
  49. var
  50. unused,usableregs : tregisterset;
  51. c_usableregs : longint;
  52. usedinproc : word;
  53. { count, how much a register must be pushed if it is used as register }
  54. { variable }
  55. reg_pushes : array[R_D0..R_A6] of longint;
  56. is_reg_var : array[R_D0..R_A6] of boolean;
  57. implementation
  58. function getusableaddr: byte;
  59. { Since address registers are different then data registers }
  60. { we check the unused register list to determine the number }
  61. { of address registers which are available. }
  62. var
  63. i: byte;
  64. Begin
  65. i:=0;
  66. if R_A2 in unused then
  67. Inc(i);
  68. if R_A3 in unused then
  69. Inc(i);
  70. if R_A4 in unused then
  71. Inc(i);
  72. getusableaddr:=i;
  73. end;
  74. procedure pushusedregisters(var pushed : tpushed;b : word);
  75. var
  76. r : tregister;
  77. begin
  78. { the following registers can be pushed }
  79. { D0, D1, D2, D3, D4, D5, D6, D7, A0 }
  80. { A1, A2, A3, A4 }
  81. for r:=R_D2 to R_A4 do
  82. begin
  83. pushed[r]:=false;
  84. { if the register is used by the calling subroutine }
  85. if ((b and ($800 shr word(r)))<>0) then
  86. begin
  87. { and is present in use }
  88. if not(r in unused) then
  89. begin
  90. { then save it }
  91. { then save it on the stack }
  92. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,r,R_SPPUSH)));
  93. { here was a big problem !!!!!}
  94. { you cannot do that for a register that is
  95. globally assigned to a var
  96. this also means that you must push it much more
  97. often, but there must be a better way
  98. maybe by putting the value back to the stack !! }
  99. if not(is_reg_var[r]) then
  100. unused:=unused+[r];
  101. pushed[r]:=true;
  102. end;
  103. end;
  104. end;
  105. end;
  106. procedure popusedregisters(const pushed : tpushed);
  107. var
  108. r : tregister;
  109. begin
  110. for r:=R_A4 downto R_D2 do
  111. if pushed[r] then
  112. begin
  113. exprasmlist^.concat(new(paicpu,op_reg_reg(A_MOVE,S_L,R_SPPULL,r)));
  114. unused:=unused-[r];
  115. end;
  116. end;
  117. procedure ungetregister(r : tregister);
  118. begin
  119. ungetregister32(r)
  120. end;
  121. procedure del_reference(const ref : treference);
  122. begin
  123. if ref.isintvalue then
  124. exit;
  125. ungetregister(ref.base);
  126. ungetregister32(ref.index);
  127. end;
  128. procedure del_locref(const location : tlocation);
  129. begin
  130. if (location.loc<>loc_mem) and (location.loc<>loc_reference) then
  131. exit;
  132. if location.reference.isintvalue then
  133. exit;
  134. ungetregister(location.reference.base);
  135. ungetregister32(location.reference.index);
  136. end;
  137. procedure ungetregister32(r : tregister);
  138. begin
  139. if r in [R_D2,R_D3,R_D4,R_D5,R_D7] then
  140. begin
  141. unused:=unused+[r];
  142. inc(usablereg32);
  143. end
  144. else
  145. if r in [R_FP2,R_FP3,R_FP4,R_FP5,R_FP6,R_FP7] then
  146. begin
  147. unused:=unused+[r];
  148. inc(usablefloatreg);
  149. end
  150. else
  151. if r in [R_A2,R_A3,R_A4] then
  152. begin
  153. unused:=unused+[r];
  154. inc(usableaddress);
  155. end;
  156. { other registers are RESERVED and should not be freed }
  157. end;
  158. function getfloatreg: tregister;
  159. { returns a free floating point register }
  160. { used in real, fpu mode, otherwise we }
  161. { must use standard register allocation }
  162. var
  163. i:tregister;
  164. begin
  165. dec(usablefloatreg);
  166. if usablefloatreg = 0 then
  167. Message(cg_f_internal_error_in_getfloatreg);
  168. for i:=R_FP2 to R_FP7 do
  169. begin
  170. if i in unused then
  171. begin
  172. unused := unused-[i];
  173. getfloatreg := i;
  174. exit;
  175. end;
  176. end;
  177. { if we are here, then there was an allocation failure }
  178. Message(cg_f_internal_error_in_getfloatreg);
  179. end;
  180. function getaddressreg: tregister;
  181. begin
  182. dec(usableaddress);
  183. if R_A2 in unused then
  184. begin
  185. unused:=unused-[R_A2];
  186. usedinproc:=usedinproc or ($800 shr word(R_A2));
  187. getaddressreg:=R_A2;
  188. end
  189. else
  190. if R_A3 in unused then
  191. begin
  192. unused:=unused-[R_A3];
  193. usedinproc:=usedinproc or ($800 shr word(R_A3));
  194. getaddressreg:=R_A3;
  195. end
  196. else
  197. if R_A4 in unused then
  198. begin
  199. unused:=unused-[R_A4];
  200. usedinproc:=usedinproc or ($800 shr word(R_A4));
  201. getaddressreg:=R_A4;
  202. end
  203. else
  204. begin
  205. internalerror(10);
  206. end;
  207. end;
  208. function getregister32 : tregister;
  209. begin
  210. dec(usablereg32);
  211. if R_D2 in unused then
  212. begin
  213. unused:=unused-[R_D2];
  214. usedinproc:=usedinproc or ($800 shr word(R_D2));
  215. getregister32:=R_D2;
  216. end
  217. else if R_D3 in unused then
  218. begin
  219. unused:=unused-[R_D3];
  220. usedinproc:=usedinproc or ($800 shr word(R_D3));
  221. getregister32:=R_D3;
  222. end
  223. else if R_D4 in unused then
  224. begin
  225. unused:=unused-[R_D4];
  226. usedinproc:=usedinproc or ($800 shr word(R_D4));
  227. getregister32:=R_D4;
  228. end
  229. else if R_D5 in unused then
  230. begin
  231. unused:=unused-[R_D5];
  232. usedinproc:=usedinproc or ($800 shr word(R_D5));
  233. getregister32:=R_D5;
  234. end
  235. else if R_D7 in unused then
  236. begin
  237. unused:=unused-[R_D7];
  238. usedinproc:=usedinproc or ($800 shr word(R_D7));
  239. getregister32:=R_D7;
  240. end
  241. else
  242. begin
  243. internalerror(10);
  244. end;
  245. end;
  246. procedure cleartempgen;
  247. begin
  248. unused:=usableregs;
  249. usablereg32:=c_usableregs;
  250. usableaddress:=getusableaddr;
  251. end;
  252. procedure clearregistercount;
  253. var
  254. regi : tregister;
  255. begin
  256. for regi:=R_D0 to R_A6 do
  257. begin
  258. reg_pushes[regi]:=0;
  259. is_reg_var[regi]:=false;
  260. end;
  261. end;
  262. procedure resetusableregisters;
  263. begin
  264. usableregs:=[R_D0,R_D1,R_D2,R_D3,R_D4,R_D5,R_D6,R_D7,R_A0,R_A1,R_A2,R_A3,R_A4,
  265. R_FP0,R_FP1,R_FP2,R_FP3,R_FP4,R_FP5,R_FP6,R_FP7];
  266. c_usableregs:=4;
  267. usableaddress:=3;
  268. usablefloatreg:=6;
  269. end;
  270. begin
  271. resetusableregisters;
  272. end.
  273. {
  274. $Log$
  275. Revision 1.5 1999-09-16 23:05:57 florian
  276. * m68k compiler is again compilable (only gas writer, no assembler reader)
  277. Revision 1.4 1998/09/01 09:03:48 peter
  278. + resetregistercount, resetusableregisters
  279. Revision 1.3 1998/08/31 12:26:35 peter
  280. * m68k and palmos updates from surebugfixes
  281. Revision 1.2 1998/06/08 13:13:46 pierre
  282. + temporary variables now in temp_gen.pas unit
  283. because it is processor independent
  284. * mppc68k.bat modified to undefine i386 and support_mmx
  285. (which are defaults for i386)
  286. }