tgcpu.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. {
  2. $Id$
  3. Copyright (C) 2000 by Florian Klaempfl
  4. This unit handles the temporary variables stuff for iA64
  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 tgcpu;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cobjects,globals,
  23. hcodegen,verbose,aasm,
  24. node,
  25. cpuinfo,cpubase,cpuasm;
  26. const
  27. { this is iA64 specific }
  28. countusableregqp : byte = c_countusableregsqp;
  29. { this value is used in tsaved, if the register isn't saved }
  30. reg_not_saved = $7fffffff;
  31. type
  32. tpushed = array[R_NO..R_NO] of boolean;
  33. tsaved = array[R_NO..R_NO] of longint;
  34. var
  35. { tries to hold the amount of times which the current tree is processed }
  36. t_times : longint;
  37. function getregisterint : tregister;
  38. procedure ungetregisterint(r : tregister);
  39. { tries to allocate the passed register, if possible }
  40. function getexplicitregisterint(r : tregister) : tregister;
  41. procedure ungetregister(r : tregister);
  42. procedure cleartempgen;
  43. procedure del_reference(const ref : treference);
  44. procedure del_locref(const location : tlocation);
  45. procedure del_location(const l : tlocation);
  46. { pushs and restores registers }
  47. procedure pushusedregisters(var pushed : tpushed;b : byte);
  48. procedure popusedregisters(const pushed : tpushed);
  49. { saves and restores used registers to temp. values }
  50. procedure saveusedregisters(var saved : tsaved;b : byte);
  51. procedure restoreusedregisters(const saved : tsaved);
  52. { increments the push count of all registers in b}
  53. procedure incrementregisterpushed(b : byte);
  54. procedure clearregistercount;
  55. procedure resetusableregisters;
  56. type
  57. regvar_longintarray = array[0..128+128+64-1] of longint;
  58. regvar_booleanarray = array[0..128+128+64-1] of boolean;
  59. regvar_ptreearray = array[0..128+128+64-1] of tnode;
  60. var
  61. unused,usableregs : tregisterset;
  62. { uses only 1 byte while a set uses in FPC 32 bytes }
  63. usedinproc : byte;
  64. { count, how much a register must be pushed if it is used as register }
  65. { variable }
  66. reg_pushes : regvar_longintarray;
  67. is_reg_var : regvar_booleanarray;
  68. implementation
  69. uses
  70. globtype,temp_gen;
  71. procedure incrementregisterpushed(b : byte);
  72. var
  73. regi : tregister;
  74. begin
  75. {!!!!!!!!
  76. for regi:=R_EAX to R_EDI do
  77. begin
  78. if (b and ($80 shr word(regi)))<>0 then
  79. inc(reg_pushes[regi],t_times*2);
  80. end;
  81. }
  82. end;
  83. procedure pushusedregisters(var pushed : tpushed;b : byte);
  84. var
  85. r : tregister;
  86. begin
  87. {!!!!!!!!
  88. usedinproc:=usedinproc or b;
  89. for r:=R_EAX to R_EBX do
  90. begin
  91. pushed[r]:=false;
  92. { if the register is used by the calling subroutine }
  93. if ((b and ($80 shr byte(r)))<>0) then
  94. begin
  95. { and is present in use }
  96. if not(r in unused) then
  97. begin
  98. { then save it }
  99. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,r)));
  100. { here was a big problem !!!!!}
  101. { you cannot do that for a register that is
  102. globally assigned to a var
  103. this also means that you must push it much more
  104. often, but there must be a better way
  105. maybe by putting the value back to the stack !! }
  106. if not(is_reg_var[r]) then
  107. begin
  108. unused:=unused+[r];
  109. end;
  110. pushed[r]:=true;
  111. end;
  112. end;
  113. end;
  114. }
  115. end;
  116. procedure saveusedregisters(var saved : tsaved;b : byte);
  117. var
  118. r : tregister;
  119. hr : treference;
  120. begin
  121. {!!!!!!!
  122. usedinproc:=usedinproc or b;
  123. for r:=R_EAX to R_EBX do
  124. begin
  125. saved[r]:=reg_not_saved;
  126. { if the register is used by the calling subroutine }
  127. if ((b and ($80 shr byte(r)))<>0) then
  128. begin
  129. { and is present in use }
  130. if not(r in unused) then
  131. begin
  132. { then save it }
  133. gettempofsizereference(4,hr);
  134. saved[r]:=hr.offset;
  135. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,r,newreference(hr))));
  136. { here was a big problem !!!!!}
  137. { you cannot do that for a register that is
  138. globally assigned to a var
  139. this also means that you must push it much more
  140. often, but there must be a better way
  141. maybe by putting the value back to the stack !! }
  142. if not(is_reg_var[r]) then
  143. begin
  144. unused:=unused+[r];
  145. end;
  146. end;
  147. end;
  148. end;
  149. }
  150. end;
  151. procedure popusedregisters(const pushed : tpushed);
  152. var
  153. r : tregister;
  154. begin
  155. {!!!!!!!
  156. { restore in reverse order: }
  157. for r:=R_EBX downto R_EAX do
  158. if pushed[r] then
  159. begin
  160. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,r)));
  161. unused:=unused-[r];
  162. end;
  163. }
  164. end;
  165. procedure restoreusedregisters(const saved : tsaved);
  166. var
  167. r : tregister;
  168. hr : treference;
  169. begin
  170. {
  171. { restore in reverse order: }
  172. for r:=R_EBX downto R_EAX do
  173. if saved[r]<>reg_not_saved then
  174. begin
  175. reset_reference(hr);
  176. hr.base:=frame_pointer_reg;
  177. hr.offset:=saved[r];
  178. exprasmlist^.concat(new(paicpu,op_ref_reg(A_MOV,S_L,newreference(hr),r)));
  179. unused:=unused-[r];
  180. ungetiftemp(hr);
  181. end;
  182. }
  183. end;
  184. procedure ungetregister(r : tregister);
  185. begin
  186. {
  187. if r in [R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI] then
  188. ungetregister32(r)
  189. else if r in [R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI] then
  190. ungetregister32(reg16toreg32(r))
  191. else if r in [R_AL,R_BL,R_CL,R_DL] then
  192. ungetregister32(reg8toreg32(r))
  193. else internalerror(18);
  194. }
  195. end;
  196. procedure ungetregisterint(r : tregister);
  197. begin
  198. {
  199. if (r = R_EDI) or
  200. ((not assigned(procinfo^._class)) and (r = R_ESI)) then
  201. begin
  202. exprasmlist^.concat(new(pairegalloc,dealloc(r)));
  203. exit;
  204. end;
  205. if cs_regalloc in aktglobalswitches then
  206. begin
  207. { takes much time }
  208. if not(r in usableregs) then
  209. exit;
  210. unused:=unused+[r];
  211. inc(usablereg32);
  212. end
  213. else
  214. begin
  215. if not(r in [R_EAX,R_EBX,R_ECX,R_EDX]) then
  216. exit;
  217. inc(usablereg32);
  218. unused:=unused+[r];
  219. end;
  220. exprasmlist^.concat(new(pairegalloc,dealloc(r)));
  221. }
  222. end;
  223. procedure del_reference(const ref : treference);
  224. begin
  225. if ref.is_immediate then
  226. exit;
  227. ungetregisterint(ref.base);
  228. end;
  229. procedure del_locref(const location : tlocation);
  230. begin
  231. if (location.loc<>LOC_MEM) and (location.loc<>LOC_REFERENCE) then
  232. exit;
  233. if location.reference.is_immediate then
  234. exit;
  235. ungetregisterint(location.reference.base);
  236. end;
  237. procedure del_location(const l : tlocation);
  238. begin
  239. case l.loc of
  240. LOC_REGISTER :
  241. ungetregister(l.register);
  242. LOC_MEM,LOC_REFERENCE :
  243. del_reference(l.reference);
  244. end;
  245. end;
  246. function getregisterint : tregister;
  247. begin
  248. {
  249. if usableregint=0 then
  250. internalerror(10);
  251. dec(usableregint);
  252. if R_EAX in unused then
  253. begin
  254. unused:=unused-[R_EAX];
  255. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  256. getregister32:=R_EAX;
  257. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  258. end
  259. else if R_EDX in unused then
  260. begin
  261. unused:=unused-[R_EDX];
  262. usedinproc:=usedinproc or ($80 shr byte(R_EDX));
  263. getregister32:=R_EDX;
  264. exprasmlist^.concat(new(pairegalloc,alloc(R_EDX)));
  265. end
  266. else if R_EBX in unused then
  267. begin
  268. unused:=unused-[R_EBX];
  269. usedinproc:=usedinproc or ($80 shr byte(R_EBX));
  270. getregister32:=R_EBX;
  271. exprasmlist^.concat(new(pairegalloc,alloc(R_EBX)));
  272. end
  273. else if R_ECX in unused then
  274. begin
  275. unused:=unused-[R_ECX];
  276. usedinproc:=usedinproc or ($80 shr byte(R_ECX));
  277. getregister32:=R_ECX;
  278. exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
  279. end
  280. else internalerror(10);
  281. }
  282. end;
  283. function getexplicitregisterint(r : tregister) : tregister;
  284. begin
  285. {
  286. if r in [R_ESI,R_EDI] then
  287. begin
  288. exprasmlist^.concat(new(pairegalloc,alloc(r)));
  289. getexplicitregister32 := r;
  290. exit;
  291. end;
  292. if r in unused then
  293. begin
  294. dec(usablereg32);
  295. unused:=unused-[r];
  296. usedinproc:=usedinproc or ($80 shr byte(r));
  297. exprasmlist^.concat(new(pairegalloc,alloc(r)));
  298. getexplicitregister32:=r;
  299. end
  300. else
  301. getexplicitregister32:=getregister32;
  302. }
  303. end;
  304. procedure cleartempgen;
  305. begin
  306. unused:=usableregs;
  307. countusableregint:=c_countusableregsint;
  308. countusableregfpu:=c_countusableregsfpu;
  309. countusableregqp:=c_countusableregsqp;
  310. end;
  311. procedure clearregistercount;
  312. var
  313. regi : tregister;
  314. begin
  315. {
  316. for regi:=R_EAX to R_EDI do
  317. begin
  318. reg_pushes[regi]:=0;
  319. is_reg_var[regi]:=false;
  320. end;
  321. }
  322. end;
  323. procedure resetusableregisters;
  324. begin
  325. {
  326. usableregs:=[R_EAX,R_EBX,R_ECX,R_EDX];
  327. c_usableregs:=4;
  328. }
  329. end;
  330. begin
  331. resetusableregisters;
  332. end.
  333. {
  334. $Log$
  335. Revision 1.3 2002-05-16 19:46:52 carl
  336. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  337. + try to fix temp allocation (still in ifdef)
  338. + generic constructor calls
  339. + start of tassembler / tmodulebase class cleanup
  340. Revision 1.2 2002/04/20 21:38:45 carl
  341. * renamed some constants
  342. Revision 1.1 2000/12/31 16:54:19 florian
  343. + initial revision
  344. }