2
0

rgcpu.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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,ait_tempalloc]);
  160. load:=nextskipping(dealloc,[ait_comment,ait_tempalloc]);
  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. function try_swap_store_x_load(var p: tai): boolean;
  177. var
  178. insertpos,
  179. storex,
  180. deallocy,
  181. loady,
  182. deallocx,
  183. loadx: tai;
  184. swapxy: taicpu;
  185. regx, regy: tregister;
  186. begin
  187. result:=false;
  188. { check for:
  189. alloc regx (optional)
  190. store regx (p)
  191. dealloc regy
  192. load regy
  193. dealloc regx
  194. load regx
  195. and change to
  196. dealloc regy
  197. load regy
  198. swap
  199. alloc regx (if it existed)
  200. store regx
  201. dealloc regx
  202. load regx
  203. This will create opportunities to remove the store/load regx
  204. (and possibly also for regy)
  205. }
  206. regx:=NR_NO;
  207. regy:=NR_NO;
  208. if not issimpleregstore(p,regx,false) then
  209. exit;
  210. storex:=p;
  211. deallocy:=nextskipping(storex,[ait_comment,ait_tempalloc]);
  212. loady:=nextskipping(deallocy,[ait_comment,ait_tempalloc]);
  213. deallocx:=nextskipping(loady,[ait_comment,ait_tempalloc]);
  214. loadx:=nextskipping(deallocx,[ait_comment,ait_tempalloc]);
  215. if not assigned(loadx) then
  216. exit;
  217. if not issimpleregload(loady,regy,false) then
  218. exit;
  219. if not issimpleregload(loadx,regx,false) then
  220. exit;
  221. if not isregallocoftyp(deallocy,ra_dealloc,regy) then
  222. exit;
  223. if not isregallocoftyp(deallocx,ra_dealloc,regx) then
  224. exit;
  225. insertpos:=tai(p.previous);
  226. if not assigned(insertpos) or
  227. not isregallocoftyp(insertpos,ra_alloc,regx) then
  228. insertpos:=storex;
  229. list.remove(deallocy);
  230. list.insertbefore(deallocy,insertpos);
  231. list.remove(loady);
  232. list.insertbefore(loady,insertpos);
  233. swapxy:=taicpu.op_none(a_swap);
  234. swapxy.fileinfo:=taicpu(loady).fileinfo;
  235. list.insertbefore(swapxy,insertpos);
  236. result:=true;
  237. end;
  238. var
  239. p,next,nextnext: tai;
  240. reg: tregister;
  241. removedsomething: boolean;
  242. begin
  243. repeat
  244. removedsomething:=false;
  245. p:=headertai;
  246. while assigned(p) do
  247. begin
  248. case p.typ of
  249. ait_regalloc:
  250. begin
  251. reg:=NR_NO;
  252. next:=nextskipping(p,[ait_comment,ait_tempalloc]);
  253. nextnext:=nextskipping(next,[ait_comment,ait_regalloc]);
  254. if assigned(nextnext) then
  255. begin
  256. { remove
  257. alloc reg
  258. dealloc reg
  259. (can appear after optimisations, necessary to prevent
  260. useless stack slot allocations) }
  261. if isregallocoftyp(p,ra_alloc,reg) and
  262. isregallocoftyp(next,ra_dealloc,reg) and
  263. not regininstruction(nextnext,reg) then
  264. begin
  265. list.remove(p);
  266. p.free;
  267. p:=tai(next.next);
  268. list.remove(next);
  269. next.free;
  270. removedsomething:=true;
  271. continue;
  272. end;
  273. end;
  274. end;
  275. ait_instruction:
  276. begin
  277. if try_remove_store_dealloc_load(p) or
  278. try_swap_store_x_load(p) then
  279. begin
  280. removedsomething:=true;
  281. continue;
  282. end;
  283. end;
  284. end;
  285. p:=tai(p.next);
  286. end;
  287. until not removedsomething;
  288. end;
  289. class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
  290. var
  291. spill_temps : tspilltemps;
  292. templist : TAsmList;
  293. intrg,
  294. fprg : trgcpu;
  295. p,q : tai;
  296. size : longint;
  297. begin
  298. { Since there are no actual registers, we simply spill everything. We
  299. use tt_regallocator temps, which are not used by the temp allocator
  300. during code generation, so that we cannot accidentally overwrite
  301. any temporary values }
  302. { get references to all register allocators }
  303. intrg:=trgcpu(cg.rg[R_INTREGISTER]);
  304. fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
  305. { determine the live ranges of all registers }
  306. intrg.insert_regalloc_info_all(list);
  307. fprg.insert_regalloc_info_all(list);
  308. { Don't do the actual allocation when -sr is passed }
  309. if (cs_no_regalloc in current_settings.globalswitches) then
  310. exit;
  311. { remove some simple useless store/load sequences }
  312. remove_dummy_load_stores(list,headertai);
  313. { allocate room to store the virtual register -> temp mapping }
  314. spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
  315. spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
  316. { List to insert temp allocations into }
  317. templist:=TAsmList.create;
  318. { allocate/replace all registers }
  319. p:=headertai;
  320. while assigned(p) do
  321. begin
  322. case p.typ of
  323. ait_regalloc:
  324. with Tai_regalloc(p) do
  325. begin
  326. case getregtype(reg) of
  327. R_INTREGISTER:
  328. if getsubreg(reg)=R_SUBD then
  329. size:=4
  330. else
  331. size:=8;
  332. R_ADDRESSREGISTER:
  333. size:=4;
  334. R_FPUREGISTER:
  335. if getsubreg(reg)=R_SUBFS then
  336. size:=4
  337. else
  338. size:=8;
  339. else
  340. internalerror(2010122912);
  341. end;
  342. case ratype of
  343. ra_alloc :
  344. tg.gettemp(templist,
  345. size,1,
  346. tt_regallocator,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  347. ra_dealloc :
  348. begin
  349. tg.ungettemp(templist,spill_temps[getregtype(reg)]^[getsupreg(reg)]);
  350. { don't invalidate the temp reference, may still be used one instruction
  351. later }
  352. end;
  353. end;
  354. { insert the tempallocation/free at the right place }
  355. list.insertlistbefore(p,templist);
  356. { remove the register allocation info for the register
  357. (p.previous is valid because we just inserted the temp
  358. allocation/free before p) }
  359. q:=Tai(p.previous);
  360. list.remove(p);
  361. p.free;
  362. p:=q;
  363. end;
  364. ait_instruction:
  365. do_spill_replace_all(list,taicpu(p),spill_temps);
  366. end;
  367. p:=Tai(p.next);
  368. end;
  369. freemem(spill_temps[R_INTREGISTER]);
  370. freemem(spill_temps[R_FPUREGISTER]);
  371. templist.free;
  372. end;
  373. end.