rgcpu.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. {
  2. Copyright (c) 2010 by Jonas Maebe
  3. This unit implements the JVM specific class for the register
  4. allocator
  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. unit rgcpu;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. aasmbase,aasmcpu,aasmtai,aasmdata,
  22. cgbase,cgutils,
  23. cpubase,
  24. rgobj;
  25. type
  26. tspilltemps = array[tregistertype] of ^Tspill_temp_list;
  27. { trgcpu }
  28. trgcpu=class(trgobj)
  29. protected
  30. class procedure do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
  31. class procedure remove_dummy_load_stores(list: TAsmList; headertai: tai);
  32. public
  33. { performs the register allocation for *all* register types }
  34. class procedure do_all_register_allocation(list: TAsmList; headertai: tai);
  35. end;
  36. implementation
  37. uses
  38. verbose,cutils,
  39. globtype,globals,
  40. cgobj,
  41. tgobj;
  42. { trgcpu }
  43. class procedure trgcpu.do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
  44. var
  45. l: longint;
  46. reg: tregister;
  47. begin
  48. { jvm instructions never have more than one memory (virtual register)
  49. operand, so there is no danger of superregister conflicts }
  50. for l:=0 to instr.ops-1 do
  51. if instr.oper[l]^.typ=top_reg then
  52. begin
  53. reg:=instr.oper[l]^.reg;
  54. instr.loadref(l,spilltemps[getregtype(reg)]^[getsupreg(reg)]);
  55. end;
  56. end;
  57. class procedure trgcpu.remove_dummy_load_stores(list: TAsmList; headertai: tai);
  58. type
  59. taitypeset = set of taitype;
  60. function nextskipping(p: tai; const skip: taitypeset): tai;
  61. begin
  62. result:=p;
  63. if not assigned(result) then
  64. exit;
  65. repeat
  66. result:=tai(result.next);
  67. until not assigned(result) or
  68. not(result.typ in skip);
  69. end;
  70. function issimpleregstore(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
  71. const
  72. simplestoressp = [a_astore,a_fstore,a_istore];
  73. simplestoresdp = [a_dstore,a_lstore];
  74. begin
  75. result:=
  76. assigned(p) and
  77. (p.typ=ait_instruction) and
  78. ((taicpu(p).opcode in simplestoressp) or
  79. (doubleprecisionok and
  80. (taicpu(p).opcode in simplestoresdp))) and
  81. ((reg=NR_NO) or
  82. (taicpu(p).oper[0]^.typ=top_reg) and
  83. (taicpu(p).oper[0]^.reg=reg));
  84. if result and
  85. (reg=NR_NO) then
  86. reg:=taicpu(p).oper[0]^.reg;
  87. end;
  88. function issimpleregload(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
  89. const
  90. simpleloadssp = [a_aload,a_fload,a_iload];
  91. simpleloadsdp = [a_dload,a_lload];
  92. begin
  93. result:=
  94. assigned(p) and
  95. (p.typ=ait_instruction) and
  96. ((taicpu(p).opcode in simpleloadssp) or
  97. (doubleprecisionok and
  98. (taicpu(p).opcode in simpleloadsdp))) and
  99. ((reg=NR_NO) or
  100. (taicpu(p).oper[0]^.typ=top_reg) and
  101. (taicpu(p).oper[0]^.reg=reg));
  102. if result and
  103. (reg=NR_NO) then
  104. reg:=taicpu(p).oper[0]^.reg;
  105. end;
  106. function isregallocoftyp(p: tai; typ: TRegAllocType;var reg: tregister): boolean;
  107. begin
  108. result:=
  109. assigned(p) and
  110. (p.typ=ait_regalloc) and
  111. (tai_regalloc(p).ratype=typ);
  112. if result then
  113. if reg=NR_NO then
  114. reg:=tai_regalloc(p).reg
  115. else
  116. result:=tai_regalloc(p).reg=reg;
  117. end;
  118. function regininstruction(p: tai; reg: tregister): boolean;
  119. var
  120. sr: tsuperregister;
  121. i: longint;
  122. begin
  123. result:=false;
  124. if p.typ<>ait_instruction then
  125. exit;
  126. sr:=getsupreg(reg);
  127. for i:=0 to taicpu(p).ops-1 do
  128. case taicpu(p).oper[0]^.typ of
  129. top_reg:
  130. if (getsupreg(taicpu(p).oper[0]^.reg)=sr) then
  131. exit(true);
  132. top_ref:
  133. begin
  134. if (getsupreg(taicpu(p).oper[0]^.ref^.base)=sr) then
  135. exit(true);
  136. if (getsupreg(taicpu(p).oper[0]^.ref^.index)=sr) then
  137. exit(true);
  138. if (getsupreg(taicpu(p).oper[0]^.ref^.indexbase)=sr) then
  139. exit(true);
  140. if (getsupreg(taicpu(p).oper[0]^.ref^.indexbase)=sr) then
  141. exit(true);
  142. end;
  143. end;
  144. end;
  145. function try_remove_store_dealloc_load(var p: tai): boolean;
  146. var
  147. dealloc,
  148. load: tai;
  149. reg: tregister;
  150. begin
  151. result:=false;
  152. { check for:
  153. store regx
  154. dealloc regx
  155. load regx
  156. and remove. We don't have to check that the load/store
  157. types match, because they have to for this to be
  158. valid JVM code }
  159. dealloc:=nextskipping(p,[ait_comment]);
  160. load:=nextskipping(dealloc,[ait_comment]);
  161. reg:=NR_NO;
  162. if issimpleregstore(p,reg,true) and
  163. isregallocoftyp(dealloc,ra_dealloc,reg) and
  164. issimpleregload(load,reg,true) then
  165. begin
  166. { remove the whole sequence: the store }
  167. list.remove(p);
  168. p.free;
  169. p:=Tai(load.next);
  170. { the load }
  171. list.remove(load);
  172. load.free;
  173. result:=true;
  174. end;
  175. end;
  176. var
  177. p,next,nextnext: tai;
  178. reg: tregister;
  179. removedsomething: boolean;
  180. begin
  181. repeat
  182. removedsomething:=false;
  183. p:=headertai;
  184. while assigned(p) do
  185. begin
  186. case p.typ of
  187. ait_regalloc:
  188. begin
  189. reg:=NR_NO;
  190. next:=nextskipping(p,[ait_comment]);
  191. nextnext:=nextskipping(next,[ait_comment,ait_regalloc]);
  192. if assigned(nextnext) then
  193. begin
  194. { remove
  195. alloc reg
  196. dealloc reg
  197. (can appear after optimisations, necessary to prevent
  198. useless stack slot allocations) }
  199. if isregallocoftyp(p,ra_alloc,reg) and
  200. isregallocoftyp(next,ra_dealloc,reg) and
  201. not regininstruction(nextnext,reg) then
  202. begin
  203. list.remove(p);
  204. p.free;
  205. p:=tai(next.next);
  206. list.remove(next);
  207. next.free;
  208. removedsomething:=true;
  209. continue;
  210. end;
  211. end;
  212. end;
  213. ait_instruction:
  214. begin
  215. if try_remove_store_dealloc_load(p) then
  216. begin
  217. removedsomething:=true;
  218. continue;
  219. end;
  220. { todo in peephole optimizer:
  221. alloc regx // not double precision
  222. store regx // not double precision
  223. load regy or memy
  224. dealloc regx
  225. load regx
  226. -> change into
  227. load regy or memy
  228. swap // can only handle single precision
  229. and then
  230. swap
  231. <commutative op>
  232. -> remove swap
  233. }
  234. end;
  235. end;
  236. p:=tai(p.next);
  237. end;
  238. until not removedsomething;
  239. end;
  240. class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
  241. var
  242. spill_temps : tspilltemps;
  243. templist : TAsmList;
  244. intrg,
  245. fprg : trgcpu;
  246. p,q : tai;
  247. size : longint;
  248. begin
  249. { Since there are no actual registers, we simply spill everything. We
  250. use tt_regallocator temps, which are not used by the temp allocator
  251. during code generation, so that we cannot accidentally overwrite
  252. any temporary values }
  253. { get references to all register allocators }
  254. intrg:=trgcpu(cg.rg[R_INTREGISTER]);
  255. fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
  256. { determine the live ranges of all registers }
  257. intrg.insert_regalloc_info_all(list);
  258. fprg.insert_regalloc_info_all(list);
  259. { Don't do the actual allocation when -sr is passed }
  260. if (cs_no_regalloc in current_settings.globalswitches) then
  261. exit;
  262. { remove some simple useless store/load sequences }
  263. remove_dummy_load_stores(list,headertai);
  264. { allocate room to store the virtual register -> temp mapping }
  265. spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
  266. spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
  267. { List to insert temp allocations into }
  268. templist:=TAsmList.create;
  269. { allocate/replace all registers }
  270. p:=headertai;
  271. while assigned(p) do
  272. begin
  273. case p.typ of
  274. ait_regalloc:
  275. with Tai_regalloc(p) do
  276. begin
  277. case getregtype(reg) of
  278. R_INTREGISTER:
  279. if getsubreg(reg)=R_SUBD then
  280. size:=4
  281. else
  282. size:=8;
  283. R_ADDRESSREGISTER:
  284. size:=4;
  285. R_FPUREGISTER:
  286. if getsubreg(reg)=R_SUBFS then
  287. size:=4
  288. else
  289. size:=8;
  290. else
  291. internalerror(2010122912);
  292. end;
  293. case ratype of
  294. ra_alloc :
  295. tg.gettemp(templist,
  296. size,1,
  297. tt_regallocator,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  298. ra_dealloc :
  299. begin
  300. tg.ungettemp(templist,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  301. { don't invalidate the temp reference, may still be used one instruction
  302. later }
  303. end;
  304. end;
  305. { insert the tempallocation/free at the right place }
  306. list.insertlistbefore(p,templist);
  307. { remove the register allocation info for the register
  308. (p.previous is valid because we just inserted the temp
  309. allocation/free before p) }
  310. q:=Tai(p.previous);
  311. list.remove(p);
  312. p.free;
  313. p:=q;
  314. end;
  315. ait_instruction:
  316. do_spill_replace_all(list,taicpu(p),spill_temps);
  317. end;
  318. p:=Tai(p.next);
  319. end;
  320. freemem(spill_temps[R_INTREGISTER]);
  321. freemem(spill_temps[R_FPUREGISTER]);
  322. templist.free;
  323. end;
  324. end.