rgllvm.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  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. end;
  62. procedure trgllvm.do_register_allocation(list: TAsmList; headertai: tai);
  63. begin
  64. { these are SSA by design, they're only assigned by alloca
  65. instructions }
  66. if regtype=R_TEMPREGISTER then
  67. exit;
  68. inherited;
  69. end;
  70. procedure trgllvm.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  71. var
  72. ins: taillvm;
  73. def: tdef;
  74. begin
  75. def:=tdef(reginfo[orgsupreg].def);
  76. if not assigned(def) then
  77. internalerror(2013110803);
  78. ins:=taillvm.op_reg_size_ref(la_load,tempreg,cpointerdef.getreusable(def),spilltemp);
  79. list.insertafter(ins,pos);
  80. {$ifdef DEBUG_SPILLING}
  81. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Read')),ins);
  82. {$endif}
  83. end;
  84. procedure trgllvm.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  85. var
  86. ins: taillvm;
  87. def: tdef;
  88. begin
  89. def:=tdef(reginfo[orgsupreg].def);
  90. if not assigned(def) then
  91. internalerror(2013110802);
  92. ins:=taillvm.op_size_reg_size_ref(la_store,def,tempreg,cpointerdef.getreusable(def),spilltemp);
  93. list.insertafter(ins,pos);
  94. {$ifdef DEBUG_SPILLING}
  95. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Write')),ins);
  96. {$endif}
  97. end;
  98. function trgllvm.instr_get_oper_spilling_info(var regs: tspillregsinfo; const r: tsuperregisterset; instr: tai_cpu_abstract_sym; opidx: longint): boolean;
  99. var
  100. paracnt: longint;
  101. callpara: pllvmcallpara;
  102. begin
  103. result:=false;
  104. with instr.oper[opidx]^ do
  105. begin
  106. case typ of
  107. top_para:
  108. begin
  109. for paracnt:=0 to paras.count-1 do
  110. begin
  111. callpara:=pllvmcallpara(paras[paracnt]);
  112. if (callpara^.typ=top_reg) and
  113. (getregtype(callpara^.register)=regtype) then
  114. begin
  115. result:=addreginfo(regs,r,callpara^.register,operand_read) or result;
  116. break
  117. end;
  118. end;
  119. end;
  120. else
  121. result:=inherited;
  122. end;
  123. end;
  124. end;
  125. procedure trgllvm.substitute_spilled_registers(const regs: tspillregsinfo; instr: tai_cpu_abstract_sym; opidx: longint);
  126. var
  127. i, paracnt: longint;
  128. callpara: pllvmcallpara;
  129. begin
  130. with instr.oper[opidx]^ do
  131. case typ of
  132. top_para:
  133. begin
  134. for paracnt:=0 to paras.count-1 do
  135. begin
  136. callpara:=pllvmcallpara(paras[paracnt]);
  137. if (callpara^.typ=top_reg) and
  138. (getregtype(callpara^.register)=regtype) then
  139. try_replace_reg(regs, callpara^.register,true);
  140. end;
  141. end;
  142. else
  143. inherited;
  144. end;
  145. end;
  146. procedure trgllvm.determine_spill_registers(list: TasmList; headertai: tai);
  147. var
  148. hp: tai;
  149. reg: tregister;
  150. sr: tsuperregister;
  151. i: longint;
  152. begin
  153. spillednodes.clear;
  154. { there should be only one round of spilling per register type, we
  155. shouldn't generate multiple writes to a single register here }
  156. if spillcounter<>0 then
  157. exit;
  158. { registers must be in SSA form -> determine all registers that are
  159. written to more than once }
  160. hp:=headertai;
  161. { 2 bits per superregister, rounded up to a byte }
  162. writtenregs:=allocmem((maxreg*bitsizeof(twrittenregs[low(tsuperregister)])+7) shr 3);
  163. while assigned(hp) do
  164. begin
  165. case hp.typ of
  166. ait_llvmins:
  167. begin
  168. for i:=0 to taillvm(hp).ops-1 do
  169. if (taillvm(hp).oper[i]^.typ=top_reg) and
  170. (getregtype(taillvm(hp).oper[i]^.reg)=regtype) and
  171. (taillvm(hp).spilling_get_operation_type(i)=operand_write) then
  172. begin
  173. reg:=taillvm(hp).oper[i]^.reg;
  174. sr:=getsupreg(reg);
  175. if writtenregs^[sr]<rw_multiple then
  176. writtenregs^[sr]:=succ(writtenregs^[sr]);
  177. end;
  178. end;
  179. else
  180. ;
  181. end;
  182. hp:=tai(hp.next);
  183. end;
  184. { add all registers with multiple writes to the spilled nodes }
  185. for sr:=0 to maxreg-1 do
  186. if writtenregs^[sr]=rw_multiple then
  187. spillednodes.add(sr);
  188. freemem(writtenregs);
  189. end;
  190. procedure trgllvm.get_spill_temp(list: TAsmlist; spill_temps: Pspill_temp_list; supreg: tsuperregister);
  191. var
  192. supstart: tai;
  193. i, paracnt: longint;
  194. def: tdef;
  195. callpara: pllvmcallpara;
  196. begin
  197. supstart:=live_start[supreg];
  198. if supstart.typ<>ait_llvmins then
  199. internalerror(2013110701);
  200. { determine type of register so we can allocate a temp of the right
  201. type }
  202. def:=nil;
  203. for i:=0 to taillvm(supstart).ops-1 do
  204. begin
  205. case taillvm(supstart).oper[i]^.typ of
  206. top_reg:
  207. if (getregtype(taillvm(supstart).oper[i]^.reg)=regtype) and
  208. (getsupreg(taillvm(supstart).oper[i]^.reg)=supreg) then
  209. begin
  210. def:=taillvm(supstart).spilling_get_reg_type(i);
  211. break
  212. end;
  213. top_para:
  214. begin
  215. for paracnt:=0 to taillvm(supstart).oper[i]^.paras.count-1 do
  216. begin
  217. callpara:=pllvmcallpara(taillvm(supstart).oper[i]^.paras[paracnt]);
  218. if (callpara^.typ=top_reg) and
  219. (getregtype(callpara^.register)=regtype) and
  220. (getsupreg(callpara^.register)=supreg) then
  221. begin
  222. def:=callpara^.def;
  223. break
  224. end;
  225. end;
  226. end;
  227. else
  228. ;
  229. end;
  230. end;
  231. if not assigned(def) then
  232. internalerror(2013110702);
  233. tg.gethltemp(list,def,def.size,tt_noreuse,spill_temps^[supreg]);
  234. { record for use in spill instructions }
  235. reginfo[supreg].def:=def;
  236. end;
  237. end.