rgllvm.pas 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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,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. procedure determine_spill_registers(list: TasmList; headertai: tai); override;
  36. procedure get_spill_temp(list:TAsmlist;spill_temps: Pspill_temp_list; supreg: tsuperregister);override;
  37. strict protected
  38. type
  39. tregwrites = (rw_none, rw_one, rw_multiple);
  40. pwrittenregs = ^twrittenregs;
  41. twrittenregs = bitpacked array[tsuperregister] of tregwrites;
  42. var
  43. spillcounter: longint;
  44. writtenregs: pwrittenregs;
  45. end;
  46. implementation
  47. uses
  48. verbose,cutils,
  49. globtype,globals,
  50. symdef,
  51. aasmllvm,
  52. tgobj;
  53. { trgllvm }
  54. constructor trgllvm.create(Aregtype: Tregistertype; Adefaultsub: Tsubregister; const Ausable: array of tsuperregister; Afirst_imaginary: Tsuperregister; Apreserved_by_proc: Tcpuregisterset);
  55. begin
  56. inherited;
  57. { tell the generic register allocator to generate SSA spilling code }
  58. ssa_safe:=true;
  59. end;
  60. procedure trgllvm.do_register_allocation(list: TAsmList; headertai: tai);
  61. begin
  62. { these are SSA by design, they're only assigned by alloca
  63. instructions }
  64. if regtype=R_TEMPREGISTER then
  65. exit;
  66. inherited;
  67. end;
  68. procedure trgllvm.do_spill_read(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  69. var
  70. ins: taillvm;
  71. def: tdef;
  72. begin
  73. def:=tdef(reginfo[orgsupreg].def);
  74. if not assigned(def) then
  75. internalerror(2013110803);
  76. ins:=taillvm.op_reg_size_ref(la_load,tempreg,getpointerdef(def),spilltemp);
  77. list.insertafter(ins,pos);
  78. {$ifdef DEBUG_SPILLING}
  79. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Read')),ins);
  80. {$endif}
  81. end;
  82. procedure trgllvm.do_spill_written(list: TAsmList; pos: tai; const spilltemp: treference; tempreg: tregister; orgsupreg: tsuperregister);
  83. var
  84. ins: taillvm;
  85. def: tdef;
  86. begin
  87. def:=tdef(reginfo[orgsupreg].def);
  88. if not assigned(def) then
  89. internalerror(2013110802);
  90. ins:=taillvm.op_size_reg_size_ref(la_store,def,tempreg,getpointerdef(def),spilltemp);
  91. list.insertafter(ins,pos);
  92. {$ifdef DEBUG_SPILLING}
  93. list.Insertbefore(tai_comment.Create(strpnew('Spilling: Spill Write')),ins);
  94. {$endif}
  95. end;
  96. procedure trgllvm.determine_spill_registers(list: TasmList; headertai: tai);
  97. var
  98. hp: tai;
  99. reg: tregister;
  100. sr: tsuperregister;
  101. i: longint;
  102. begin
  103. spillednodes.clear;
  104. { there should be only one round of spilling per register type, we
  105. shouldn't generate multiple writes so a single register here }
  106. if spillcounter<>0 then
  107. exit;
  108. { registers must be in SSA form -> determine all registers that are
  109. written to more than once }
  110. hp:=headertai;
  111. { 2 bits per superregister, rounded up to a byte }
  112. writtenregs:=allocmem((maxreg*2+7) shr 3);
  113. while assigned(hp) do
  114. begin
  115. case hp.typ of
  116. ait_llvmins:
  117. begin
  118. for i:=0 to taillvm(hp).ops-1 do
  119. if (taillvm(hp).oper[i]^.typ=top_reg) and
  120. (getregtype(taillvm(hp).oper[i]^.reg)=regtype) and
  121. (taillvm(hp).spilling_get_operation_type(i)=operand_write) then
  122. begin
  123. reg:=taillvm(hp).oper[i]^.reg;
  124. sr:=getsupreg(reg);
  125. if writtenregs^[sr]<rw_multiple then
  126. writtenregs^[sr]:=succ(writtenregs^[sr]);
  127. end;
  128. end;
  129. end;
  130. hp:=tai(hp.next);
  131. end;
  132. { add all registers with multiple writes to the spilled nodes }
  133. for sr:=0 to maxreg-1 do
  134. if writtenregs^[sr]=rw_multiple then
  135. spillednodes.add(sr);
  136. freemem(writtenregs);
  137. end;
  138. procedure trgllvm.get_spill_temp(list: TAsmlist; spill_temps: Pspill_temp_list; supreg: tsuperregister);
  139. var
  140. supstart: tai;
  141. i: longint;
  142. def: tdef;
  143. begin
  144. supstart:=live_start[supreg];
  145. if supstart.typ<>ait_llvmins then
  146. internalerror(2013110701);
  147. { determine type of register so we can allocate a temp of the right
  148. type }
  149. def:=nil;
  150. for i:=0 to taillvm(supstart).ops-1 do
  151. begin
  152. if (taillvm(supstart).oper[i]^.typ=top_reg) and
  153. (getsupreg(taillvm(supstart).oper[i]^.reg)=supreg) then
  154. begin
  155. def:=taillvm(supstart).spilling_get_reg_type(i);
  156. break
  157. end;
  158. end;
  159. if not assigned(def) then
  160. internalerror(2013110702);
  161. tg.gethltemp(list,def,def.size,tt_noreuse,spill_temps^[supreg]);
  162. { record for use in spill instructions }
  163. reginfo[supreg].def:=def;
  164. end;
  165. end.