2
0

rgllvm.pas 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. {
  2. Copyright (c) 2013 by Jonas Maebe, member of the Free Pascal development
  3. team
  4. This unit implements the LLVM-specific class for the register
  5. allocator
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************}
  18. unit rgllvm;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmcpu,aasmsym,aasmtai,aasmdata,
  23. symtype,
  24. cgbase,cgutils,
  25. cpubase,llvmbase,
  26. rgobj;
  27. type
  28. { trgllvm }
  29. trgllvm=class(trgobj)
  30. constructor create(Aregtype: Tregistertype; Adefaultsub: Tsubregister; const Ausable: array of tsuperregister; Afirst_imaginary: Tsuperregister; Apreserved_by_proc: Tcpuregisterset); reintroduce;
  31. procedure do_register_allocation(list: TAsmList; headertai: tai); override;
  32. procedure do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
  33. procedure do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister); override;
  34. protected
  35. function instr_get_oper_spilling_info(var regs: tspillregsinfo; const r: tsuperregisterset; instr: tai_cpu_abstract_sym; opidx: longint): boolean; override;
  36. procedure substitute_spilled_registers(const regs: tspillregsinfo; instr: tai_cpu_abstract_sym; opidx: longint); override;
  37. procedure determine_spill_registers(list: TasmList; headertai: tai); override;
  38. procedure get_spill_temp(list:TAsmlist;spill_temps: Pspill_temp_list; supreg: tsuperregister);override;
  39. strict protected
  40. type
  41. tregwrites = (rw_none, rw_one, rw_multiple);
  42. pwrittenregs = ^twrittenregs;
  43. twrittenregs = bitpacked array[tsuperregister] of tregwrites;
  44. var
  45. spillcounter: longint;
  46. writtenregs: pwrittenregs;
  47. end;
  48. implementation
  49. uses
  50. verbose,cutils,
  51. globtype,globals,
  52. symdef,
  53. aasmllvm,
  54. tgobj;
  55. { trgllvm }
  56. constructor trgllvm.create(Aregtype: Tregistertype; Adefaultsub: Tsubregister; const Ausable: array of tsuperregister; Afirst_imaginary: Tsuperregister; Apreserved_by_proc: Tcpuregisterset);
  57. begin
  58. inherited;
  59. { tell the generic register allocator to generate SSA spilling code }
  60. ssa_safe:=true;
  61. { all registers are "usable" for us; we only care about SSA form. This
  62. prevents the register allocator from trying to spill every single
  63. register (because our "usable registers" array contains just one,
  64. dummy, register) }
  65. usable_registers_cnt:=high(usable_registers_cnt);
  66. end;
  67. procedure trgllvm.do_register_allocation(list: TAsmList; headertai: tai);
  68. begin
  69. { these are SSA by design, they're only assigned by alloca
  70. instructions }
  71. if regtype=R_TEMPREGISTER then
  72. exit;
  73. inherited;
  74. end;
  75. procedure trgllvm.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  76. var
  77. ins: taillvm;
  78. def: tdef;
  79. begin
  80. def:=tdef(reginfo[orgsupreg].def);
  81. if not assigned(def) then
  82. internalerror(2013110803);
  83. ins:=taillvm.op_reg_size_ref(la_load,tempreg,cpointerdef.getreusable(def),spilltemp);
  84. list.insertafter(ins,pos);
  85. {$ifdef DEBUG_SPILLING}
  86. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Read')),ins);
  87. {$endif}
  88. end;
  89. procedure trgllvm.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  90. var
  91. ins: taillvm;
  92. def: tdef;
  93. begin
  94. def:=tdef(reginfo[orgsupreg].def);
  95. if not assigned(def) then
  96. internalerror(2013110802);
  97. ins:=taillvm.op_size_reg_size_ref(la_store,def,tempreg,cpointerdef.getreusable(def),spilltemp);
  98. list.insertafter(ins,pos);
  99. {$ifdef DEBUG_SPILLING}
  100. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Write')),ins);
  101. {$endif}
  102. end;
  103. function trgllvm.instr_get_oper_spilling_info(var regs: tspillregsinfo; const r: tsuperregisterset; instr: tai_cpu_abstract_sym; opidx: longint): boolean;
  104. var
  105. paracnt: longint;
  106. callpara: pllvmcallpara;
  107. begin
  108. result:=false;
  109. with instr.oper[opidx]^ do
  110. begin
  111. case typ of
  112. top_para:
  113. begin
  114. for paracnt:=0 to paras.count-1 do
  115. begin
  116. callpara:=pllvmcallpara(paras[paracnt]);
  117. if (callpara^.typ=top_reg) and
  118. (getregtype(callpara^.register)=regtype) then
  119. begin
  120. result:=addreginfo(regs,r,callpara^.register,operand_read) or result;
  121. break
  122. end;
  123. end;
  124. end;
  125. else
  126. result:=inherited;
  127. end;
  128. end;
  129. end;
  130. procedure trgllvm.substitute_spilled_registers(const regs: tspillregsinfo; instr: tai_cpu_abstract_sym; opidx: longint);
  131. var
  132. i, paracnt: longint;
  133. callpara: pllvmcallpara;
  134. begin
  135. with instr.oper[opidx]^ do
  136. case typ of
  137. top_para:
  138. begin
  139. for paracnt:=0 to paras.count-1 do
  140. begin
  141. callpara:=pllvmcallpara(paras[paracnt]);
  142. if (callpara^.typ=top_reg) and
  143. (getregtype(callpara^.register)=regtype) then
  144. try_replace_reg(regs, callpara^.register,true);
  145. end;
  146. end;
  147. else
  148. inherited;
  149. end;
  150. end;
  151. procedure trgllvm.determine_spill_registers(list: TasmList; headertai: tai);
  152. var
  153. hp: tai;
  154. reg: tregister;
  155. sr: tsuperregister;
  156. i: longint;
  157. begin
  158. spillednodes.clear;
  159. { there should be only one round of spilling per register type, we
  160. shouldn't generate multiple writes to a single register here }
  161. if spillcounter<>0 then
  162. exit;
  163. { registers must be in SSA form -> determine all registers that are
  164. written to more than once }
  165. hp:=headertai;
  166. { 2 bits per superregister, rounded up to a byte }
  167. writtenregs:=allocmem((maxreg*bitsizeof(twrittenregs[low(tsuperregister)])+7) shr 3);
  168. while assigned(hp) do
  169. begin
  170. case hp.typ of
  171. ait_llvmins:
  172. begin
  173. for i:=0 to taillvm(hp).ops-1 do
  174. if (taillvm(hp).oper[i]^.typ=top_reg) and
  175. (getregtype(taillvm(hp).oper[i]^.reg)=regtype) and
  176. (taillvm(hp).spilling_get_operation_type(i)=operand_write) then
  177. begin
  178. reg:=taillvm(hp).oper[i]^.reg;
  179. sr:=getsupreg(reg);
  180. if writtenregs^[sr]<rw_multiple then
  181. writtenregs^[sr]:=succ(writtenregs^[sr]);
  182. end;
  183. end;
  184. else
  185. ;
  186. end;
  187. hp:=tai(hp.next);
  188. end;
  189. { add all registers with multiple writes to the spilled nodes }
  190. for sr:=0 to maxreg-1 do
  191. if writtenregs^[sr]=rw_multiple then
  192. spillednodes.add(sr);
  193. freemem(writtenregs);
  194. end;
  195. procedure trgllvm.get_spill_temp(list: TAsmlist; spill_temps: Pspill_temp_list; supreg: tsuperregister);
  196. var
  197. supstart: tai;
  198. i, paracnt: longint;
  199. def: tdef;
  200. callpara: pllvmcallpara;
  201. begin
  202. supstart:=live_start[supreg];
  203. if supstart.typ<>ait_llvmins then
  204. internalerror(2013110701);
  205. { determine type of register so we can allocate a temp of the right
  206. type }
  207. def:=nil;
  208. for i:=0 to taillvm(supstart).ops-1 do
  209. begin
  210. case taillvm(supstart).oper[i]^.typ of
  211. top_reg:
  212. if (getregtype(taillvm(supstart).oper[i]^.reg)=regtype) and
  213. (getsupreg(taillvm(supstart).oper[i]^.reg)=supreg) then
  214. begin
  215. def:=taillvm(supstart).spilling_get_reg_type(i);
  216. break
  217. end;
  218. top_para:
  219. begin
  220. for paracnt:=0 to taillvm(supstart).oper[i]^.paras.count-1 do
  221. begin
  222. callpara:=pllvmcallpara(taillvm(supstart).oper[i]^.paras[paracnt]);
  223. if (callpara^.typ=top_reg) and
  224. (getregtype(callpara^.register)=regtype) and
  225. (getsupreg(callpara^.register)=supreg) then
  226. begin
  227. def:=callpara^.def;
  228. break
  229. end;
  230. end;
  231. end;
  232. else
  233. ;
  234. end;
  235. end;
  236. if not assigned(def) then
  237. internalerror(2013110702);
  238. tg.gethltemp(list,def,def.size,tt_noreuse,spill_temps^[supreg]);
  239. { record for use in spill instructions }
  240. reginfo[supreg].def:=def;
  241. end;
  242. end.