rgcpu.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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 function do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps):boolean;
  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 function trgcpu.do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps):boolean;
  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. function issimpleregstore(p: tai; reg: tregister; doubleprecisionok: boolean): boolean;
  59. const
  60. simplestoressp = [a_astore,a_fstore,a_istore];
  61. simplestoresdp = [a_dstore,a_lstore];
  62. begin
  63. result:=
  64. assigned(p) and
  65. (p.typ=ait_instruction) and
  66. ((taicpu(p).opcode in simplestoressp) or
  67. (doubleprecisionok and
  68. (taicpu(p).opcode in simplestoresdp))) and
  69. ((reg=NR_NO) or
  70. (taicpu(p).oper[0]^.typ=top_reg) and
  71. (taicpu(p).oper[0]^.reg=reg));
  72. end;
  73. function issimpleregload(p: tai; reg: tregister; doubleprecisionok: boolean): boolean;
  74. const
  75. simpleloadssp = [a_aload,a_fload,a_iload];
  76. simpleloadsdp = [a_dload,a_lload];
  77. begin
  78. result:=
  79. assigned(p) and
  80. (p.typ=ait_instruction) and
  81. ((taicpu(p).opcode in simpleloadssp) or
  82. (doubleprecisionok and
  83. (taicpu(p).opcode in simpleloadsdp))) and
  84. ((reg=NR_NO) or
  85. (taicpu(p).oper[0]^.typ=top_reg) and
  86. (taicpu(p).oper[0]^.reg=reg));
  87. end;
  88. function try_remove_alloc_store_dealloc_load(var p: tai; reg: tregister): boolean;
  89. var
  90. q: tai;
  91. begin
  92. result:=false;
  93. { check for:
  94. alloc regx
  95. store regx
  96. dealloc regx
  97. load regx
  98. and remove. We don't have to check that the load/store
  99. types match, because they have to for this to be
  100. valid JVM code }
  101. if issimpleregstore(tai(p.next),reg,true) and
  102. assigned(p.next.next) and
  103. (tai(p.next.next).typ=ait_regalloc) and
  104. (tai_regalloc(p.next.next).ratype=ra_dealloc) and
  105. (tai_regalloc(p.next.next).reg=reg) and
  106. issimpleregload(tai(p.next.next.next),reg,true) then
  107. begin
  108. { remove the whole sequence: the allocation }
  109. q:=Tai(p.next);
  110. list.remove(p);
  111. p.free;
  112. p:=q;
  113. { the store }
  114. q:=Tai(p.next);
  115. list.remove(p);
  116. p.free;
  117. p:=q;
  118. { the dealloc }
  119. q:=Tai(p.next);
  120. list.remove(p);
  121. p.free;
  122. p:=q;
  123. { the load }
  124. q:=Tai(p.next);
  125. list.remove(p);
  126. p.free;
  127. p:=q;
  128. result:=true;
  129. end;
  130. end;
  131. var
  132. p: tai;
  133. reg: tregister;
  134. removedsomething: boolean;
  135. begin
  136. repeat
  137. removedsomething:=false;
  138. p:=headertai;
  139. while assigned(p) do
  140. begin
  141. case p.typ of
  142. ait_regalloc:
  143. begin
  144. if (tai_regalloc(p).ratype=ra_alloc) then
  145. begin
  146. reg:=tai_regalloc(p).reg;
  147. if try_remove_alloc_store_dealloc_load(p,reg) then
  148. begin
  149. removedsomething:=true;
  150. continue;
  151. end;
  152. { todo in peephole optimizer:
  153. alloc regx // not double precision
  154. store regx // not double precision
  155. load regy or memy
  156. dealloc regx
  157. load regx
  158. -> change into
  159. load regy or memy
  160. swap // can only handle single precision
  161. and then
  162. swap
  163. <commutative op>
  164. -> remove swap
  165. }
  166. end;
  167. end;
  168. end;
  169. p:=tai(p.next);
  170. end;
  171. until not removedsomething;
  172. end;
  173. class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
  174. var
  175. spill_temps : tspilltemps;
  176. templist : TAsmList;
  177. intrg,
  178. fprg : trgcpu;
  179. p,q : tai;
  180. size : longint;
  181. begin
  182. { Since there are no actual registers, we simply spill everything. We
  183. use tt_regallocator temps, which are not used by the temp allocator
  184. during code generation, so that we cannot accidentally overwrite
  185. any temporary values }
  186. { get references to all register allocators }
  187. intrg:=trgcpu(cg.rg[R_INTREGISTER]);
  188. fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
  189. { determine the live ranges of all registers }
  190. intrg.insert_regalloc_info_all(list);
  191. fprg.insert_regalloc_info_all(list);
  192. { Don't do the actual allocation when -sr is passed }
  193. if (cs_no_regalloc in current_settings.globalswitches) then
  194. exit;
  195. { remove some simple useless store/load sequences }
  196. remove_dummy_load_stores(list,headertai);
  197. { allocate room to store the virtual register -> temp mapping }
  198. spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
  199. spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
  200. { List to insert temp allocations into }
  201. templist:=TAsmList.create;
  202. { allocate/replace all registers }
  203. p:=headertai;
  204. while assigned(p) do
  205. begin
  206. case p.typ of
  207. ait_regalloc:
  208. with Tai_regalloc(p) do
  209. begin
  210. case getregtype(reg) of
  211. R_INTREGISTER:
  212. if getsubreg(reg)=R_SUBD then
  213. size:=4
  214. else
  215. size:=8;
  216. R_ADDRESSREGISTER:
  217. size:=4;
  218. R_FPUREGISTER:
  219. if getsubreg(reg)=R_SUBFS then
  220. size:=4
  221. else
  222. size:=8;
  223. else
  224. internalerror(2010122912);
  225. end;
  226. case ratype of
  227. ra_alloc :
  228. tg.gettemp(templist,
  229. size,1,
  230. tt_regallocator,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  231. ra_dealloc :
  232. begin
  233. tg.ungettemp(templist,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  234. { don't invalidate the temp reference, may still be used one instruction
  235. later }
  236. end;
  237. end;
  238. { insert the tempallocation/free at the right place }
  239. list.insertlistbefore(p,templist);
  240. { remove the register allocation info for the register
  241. (p.previous is valid because we just inserted the temp
  242. allocation/free before p) }
  243. q:=Tai(p.previous);
  244. list.remove(p);
  245. p.free;
  246. p:=q;
  247. end;
  248. ait_instruction:
  249. do_spill_replace_all(list,taicpu(p),spill_temps);
  250. end;
  251. p:=Tai(p.next);
  252. end;
  253. freemem(spill_temps[R_INTREGISTER]);
  254. freemem(spill_temps[R_FPUREGISTER]);
  255. end;
  256. end.