1 { 2 Copyright (c) 1998-2002,2012 by Florian Klaempfl, Jonas Maebe 3 4 This unit implements the LLVM-specific temp. generator 5 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 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 20 **************************************************************************** 21 } 22 23 unit tgllvm; 24 25 {$i fpcdefs.inc} 26 27 interface 28 29 uses 30 cclasses, 31 globals,globtype, 32 symtype, 33 cpubase,cpuinfo,cgbase,cgutils, 34 aasmbase,aasmtai,aasmdata, 35 tgobj; 36 37 type 38 39 { LLVM temp manager: in LLVM, you allocate every temp separately using 40 the "alloca" instrinsic. Every such temp is a separate stack slot, but 41 can be turned into a regvar (or be decomposed) by LLVM. To avoid 42 problems with turning stack slots into regvars, we don't allocate one 43 big blob of memory that we manage ourselves using the regular temp 44 manager. Instead, we just allocate a new "stack pointer register" 45 (R_TEMPREGISTER) every time we need a new temp. This allows for having 46 the generic code generator modify the offset without interfering with 47 our ability to determine which temp the reference points to. 48 49 Temps are currently not reused, but that should probably be added in 50 the future (except if adding liveness information for the temps enables 51 llvm to do so by itself and we don't run out of temp registers). 52 } 53 54 { ttgllvm } 55 56 ttgllvm = class(ttgobj) 57 protected 58 procedure alloctemp(list: TAsmList; size: asizeint; alignment: shortint; temptype: ttemptype; def: tdef; fini: boolean; out ref: treference); override; 59 procedure gethltempintern(list: TAsmList; def: tdef; alignment: shortint; forcesize: asizeint; temptype: ttemptype; out ref: treference); 60 public 61 alloclist: tasmlist; 62 63 constructor create; override; 64 destructor destroy; override; 65 procedure setfirsttemp(l: asizeint); override; 66 procedure temp_to_ref(p: ptemprecord; out ref: treference); override; 67 procedure getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref: treference); override; 68 procedure gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); override; 69 end; 70 71 72 var 73 orgtgclass: ttgobjclass; 74 75 implementation 76 77 uses 78 cutils, 79 systems,verbose, 80 procinfo, 81 llvmbase,aasmllvm, 82 symconst,symdef, 83 cgobj 84 ; 85 86 87 { ttgllvm } 88 89 procedure ttgllvm.alloctemp(list: TAsmList; size: asizeint; alignment: shortint; temptype: ttemptype; def: tdef; fini: boolean; out ref: treference); 90 var 91 tl: ptemprecord; 92 reg: tregister; 93 oldfileinfo: tfileposinfo; 94 begin 95 reg:=cg.gettempregister(list); 96 new(tl); 97 98 tl^.temptype:=temptype; 99 tl^.def:=def; 100 tl^.fini:=fini; 101 tl^.alignment:=alignment; 102 tl^.pos:=getsupreg(reg); 103 tl^.size:=size; 104 tl^.next:=templist; 105 tl^.nextfree:=nil; 106 templist:=tl; 107 temp_to_ref(tl,ref); 108 list.concat(tai_tempalloc.alloc(tl^.pos,tl^.size)); 109 { TODO: add llvm.lifetime.start() for this allocation and afterwards 110 llvm.lifetime.end() for freetemp (if the llvm version supports it) } 111 inc(lasttemp); 112 { allocation for the temp -- should have lineinfo of the start of the 113 routine } 114 if assigned(current_procinfo) then 115 begin 116 oldfileinfo:=current_filepos; 117 current_filepos:=current_procinfo.procdef.fileinfo; 118 end 119 else 120 { avoid uninitialised warning later } 121 oldfileinfo.line:=0; 122 alloclist.concat(taillvm.op_ref_size(la_alloca,ref,def)); 123 if assigned(current_procinfo) then 124 current_filepos:=oldfileinfo; 125 end; 126 127 procedure ttgllvm.gethltempintern(list: TAsmList; def: tdef; alignment: shortint; forcesize: asizeint; temptype: ttemptype; out ref: treference); 128 begin 129 { empty array (can happen for arrayconstructors) -> don't request the 130 size, as that will internalerror } 131 if (def.typ=arraydef) and 132 (tarraydef(def).highrange<tarraydef(def).lowrange) then 133 alloctemp(list,0,alignment,temptype,def,false,ref) 134 else 135 alloctemp(list,def.size,alignment,temptype,def,false,ref); 136 end; 137 138 139 procedure ttgllvm.temp_to_ref(p: ptemprecord; out ref: treference); 140 var 141 temppos: treftemppos; 142 begin 143 { on the LLVM target, every temp is independent and encoded via a 144 separate temp register whose superregister number is stored in p^.pos } 145 temppos.val:=p^.pos; 146 reference_reset_base(ref,newreg(R_TEMPREGISTER,p^.pos,R_SUBWHOLE),0,temppos,p^.alignment,[]); 147 end; 148 149 150 constructor ttgllvm.create; 151 begin 152 inherited create; 153 direction:=1; 154 alloclist:=TAsmList.create; 155 end; 156 157 158 destructor ttgllvm.destroy; 159 begin 160 alloclist.free; 161 inherited destroy; 162 end; 163 164 165 procedure ttgllvm.setfirsttemp(l: asizeint); 166 begin 167 firsttemp:=l; 168 lasttemp:=l; 169 end; 170 171 172 procedure ttgllvm.getlocal(list: TAsmList; size: asizeint; alignment: shortint; def: tdef; var ref: treference); 173 begin 174 alignment:=used_align(alignment,current_settings.alignment.localalignmin,current_settings.alignment.localalignmax); 175 gethltempintern(list,def,alignment,size,tt_persistent,ref); 176 end; 177 178 179 procedure ttgllvm.gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); 180 begin 181 gethltempintern(list,def,def.alignment,forcesize,tt_persistent,ref); 182 end; 183 184 185 begin 186 orgtgclass:=tgobjclass; 187 tgobjclass:=ttgllvm; 188 end. 189