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