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