rgcpu.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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. 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 try_remove_store_dealloc_load(var p: tai): boolean;
  119. var
  120. dealloc,
  121. load: tai;
  122. reg: tregister;
  123. begin
  124. result:=false;
  125. { check for:
  126. store regx
  127. dealloc regx
  128. load regx
  129. and remove. We don't have to check that the load/store
  130. types match, because they have to for this to be
  131. valid JVM code }
  132. dealloc:=nextskipping(p,[ait_comment]);
  133. load:=nextskipping(dealloc,[ait_comment]);
  134. reg:=NR_NO;
  135. if issimpleregstore(p,reg,true) and
  136. isregallocoftyp(dealloc,ra_dealloc,reg) and
  137. issimpleregload(load,reg,true) then
  138. begin
  139. { remove the whole sequence: the store }
  140. list.remove(p);
  141. p.free;
  142. p:=Tai(load.next);
  143. { the load }
  144. list.remove(load);
  145. load.free;
  146. result:=true;
  147. end;
  148. end;
  149. var
  150. p,next: tai;
  151. reg: tregister;
  152. removedsomething: boolean;
  153. begin
  154. repeat
  155. removedsomething:=false;
  156. p:=headertai;
  157. while assigned(p) do
  158. begin
  159. case p.typ of
  160. ait_regalloc:
  161. begin
  162. reg:=NR_NO;
  163. next:=nextskipping(p,[ait_comment]);
  164. { remove
  165. alloc reg
  166. dealloc reg
  167. (can appear after optimisations, necessary to prevent
  168. useless stack slot allocations) }
  169. if isregallocoftyp(p,ra_alloc,reg) and
  170. isregallocoftyp(next,ra_dealloc,reg) then
  171. begin
  172. list.remove(p);
  173. p.free;
  174. p:=tai(next.next);
  175. list.remove(next);
  176. next.free;
  177. removedsomething:=true;
  178. continue;
  179. end;
  180. end;
  181. ait_instruction:
  182. begin
  183. if try_remove_store_dealloc_load(p) then
  184. begin
  185. removedsomething:=true;
  186. continue;
  187. end;
  188. { todo in peephole optimizer:
  189. alloc regx // not double precision
  190. store regx // not double precision
  191. load regy or memy
  192. dealloc regx
  193. load regx
  194. -> change into
  195. load regy or memy
  196. swap // can only handle single precision
  197. and then
  198. swap
  199. <commutative op>
  200. -> remove swap
  201. }
  202. end;
  203. end;
  204. p:=tai(p.next);
  205. end;
  206. until not removedsomething;
  207. end;
  208. class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
  209. var
  210. spill_temps : tspilltemps;
  211. templist : TAsmList;
  212. intrg,
  213. fprg : trgcpu;
  214. p,q : tai;
  215. size : longint;
  216. begin
  217. { Since there are no actual registers, we simply spill everything. We
  218. use tt_regallocator temps, which are not used by the temp allocator
  219. during code generation, so that we cannot accidentally overwrite
  220. any temporary values }
  221. { get references to all register allocators }
  222. intrg:=trgcpu(cg.rg[R_INTREGISTER]);
  223. fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
  224. { determine the live ranges of all registers }
  225. intrg.insert_regalloc_info_all(list);
  226. fprg.insert_regalloc_info_all(list);
  227. { Don't do the actual allocation when -sr is passed }
  228. if (cs_no_regalloc in current_settings.globalswitches) then
  229. exit;
  230. { remove some simple useless store/load sequences }
  231. remove_dummy_load_stores(list,headertai);
  232. { allocate room to store the virtual register -> temp mapping }
  233. spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
  234. spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
  235. { List to insert temp allocations into }
  236. templist:=TAsmList.create;
  237. { allocate/replace all registers }
  238. p:=headertai;
  239. while assigned(p) do
  240. begin
  241. case p.typ of
  242. ait_regalloc:
  243. with Tai_regalloc(p) do
  244. begin
  245. case getregtype(reg) of
  246. R_INTREGISTER:
  247. if getsubreg(reg)=R_SUBD then
  248. size:=4
  249. else
  250. size:=8;
  251. R_ADDRESSREGISTER:
  252. size:=4;
  253. R_FPUREGISTER:
  254. if getsubreg(reg)=R_SUBFS then
  255. size:=4
  256. else
  257. size:=8;
  258. else
  259. internalerror(2010122912);
  260. end;
  261. case ratype of
  262. ra_alloc :
  263. tg.gettemp(templist,
  264. size,1,
  265. tt_regallocator,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  266. ra_dealloc :
  267. begin
  268. tg.ungettemp(templist,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  269. { don't invalidate the temp reference, may still be used one instruction
  270. later }
  271. end;
  272. end;
  273. { insert the tempallocation/free at the right place }
  274. list.insertlistbefore(p,templist);
  275. { remove the register allocation info for the register
  276. (p.previous is valid because we just inserted the temp
  277. allocation/free before p) }
  278. q:=Tai(p.previous);
  279. list.remove(p);
  280. p.free;
  281. p:=q;
  282. end;
  283. ait_instruction:
  284. do_spill_replace_all(list,taicpu(p),spill_temps);
  285. end;
  286. p:=Tai(p.next);
  287. end;
  288. freemem(spill_temps[R_INTREGISTER]);
  289. freemem(spill_temps[R_FPUREGISTER]);
  290. end;
  291. end.