1 {
2     Copyright (c) 2013 by Jonas Maebe
3 
4     Generate LLVM bytecode for add nodes
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 unit nllvmadd;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       node,
30       ncgadd;
31 
32     type
33       tllvmaddnode = class(tcgaddnode)
34        public
pass_1null35         function pass_1: tnode; override;
36         procedure force_reg_left_right(allow_swap, allow_constant: boolean); override;
37        protected
38         procedure second_cmpsmallset; override;
39         procedure second_cmpordinal; override;
40         procedure second_add64bit; override;
41         procedure second_cmp64bit; override;
42         procedure second_addfloat; override;
43         procedure second_cmpfloat; override;
44       end;
45 
46 
47 implementation
48 
49      uses
50        verbose,globtype,
51        aasmdata,
52        symconst,symtype,symdef,defutil,
53        llvmbase,aasmllvm,
54        cgbase,cgutils,
55        hlcgobj,
56        nadd
57        ;
58 
59 { tllvmaddnode }
60 
tllvmaddnode.pass_1null61   function tllvmaddnode.pass_1: tnode;
62     begin
63       result:=inherited pass_1;
64       { there are no flags in LLVM }
65       if expectloc=LOC_FLAGS then
66         expectloc:=LOC_REGISTER;
67     end;
68 
69 
70   procedure tllvmaddnode.force_reg_left_right(allow_swap, allow_constant: boolean);
71     begin
72       { comparison with pointer -> no immediate, as icmp can't handle pointer
73         immediates (except for nil as "null", but we don't generate that) }
74       if (nodetype in [equaln,unequaln,gtn,gten,ltn,lten]) and
75          ((left.nodetype in [pointerconstn,niln]) or
76           (right.nodetype in [pointerconstn,niln])) then
77         allow_constant:=false;
78       inherited;
79       { pointer - pointer = integer -> make all defs pointer since we can't
80         subtract pointers }
81       if (nodetype=subn) and
82          (left.resultdef.typ=pointerdef) and
83          (right.resultdef.typ=pointerdef) then
84         begin
85           hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
86           hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
87         end
88       { pointer +/- integer -> make defs the same since a_op_* only gets a
89         single type as argument }
90       else if (nodetype in [addn,subn]) and
91               ((left.resultdef.typ=pointerdef)<>(right.resultdef.typ=pointerdef)) then
92         begin
93           { the result is a pointerdef -> typecast both arguments to pointer;
94             a_op_*_reg will convert them back to integer as needed }
95           if left.resultdef.typ<>pointerdef then
96             hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
97           if right.resultdef.typ<>pointerdef then
98             hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
99         end;
100     end;
101 
102 
103   procedure tllvmaddnode.second_cmpsmallset;
104     var
105       tmpreg,
106       tmpreg2: tregister;
107       cmpop : topcmp;
108     begin
109       pass_left_right;
110 
111       location_reset(location,LOC_REGISTER,OS_8);
112       location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
113 
114       force_reg_left_right(false,false);
115 
116       case nodetype of
117         equaln,
118         unequaln:
119           begin
120             if nodetype=equaln then
121               cmpop:=OC_EQ
122             else
123               cmpop:=OC_NE;
124             current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
125               location.register,cmpop,left.resultdef,left.location.register,right.location.register));
126           end;
127         lten,
128         gten:
129           begin
130             if (not(nf_swapped in flags) and
131                 (nodetype = lten)) or
132                ((nf_swapped in flags) and
133                 (nodetype = gten)) then
134               swapleftright;
135             { set1<=set2 <-> set2 and not(set1) = 0 }
136             tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
137             hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,left.location.register,tmpreg);
138             tmpreg2:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef);
139             hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,OP_AND,left.resultdef,right.location.register,tmpreg,tmpreg2);
140             current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
141               location.register,OC_EQ,left.resultdef,tmpreg2,0));
142           end;
143         else
144           internalerror(2012042701);
145       end;
146       tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
147       hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
148       location.register:=tmpreg;
149     end;
150 
151 
152   procedure tllvmaddnode.second_cmpordinal;
153     var
154       tmpreg: tregister;
155       cmpop: topcmp;
156       unsigned : boolean;
157     begin
158       pass_left_right;
159       force_reg_left_right(true,true);
160 
161       unsigned:=not(is_signed(left.resultdef)) or
162                 not(is_signed(right.resultdef));
163 
164       case nodetype of
165         ltn:
166           if unsigned then
167             cmpop:=OC_B
168           else
169             cmpop:=OC_LT;
170         lten:
171           if unsigned then
172             cmpop:=OC_BE
173           else
174             cmpop:=OC_LTE;
175         gtn:
176           if unsigned then
177             cmpop:=OC_A
178           else
179             cmpop:=OC_GT;
180         gten:
181           if unsigned then
182             cmpop:=OC_AE
183           else
184             cmpop:=OC_GTE;
185         equaln:
186           cmpop:=OC_EQ;
187         unequaln:
188           cmpop:=OC_NE;
189         else
190           internalerror(2015031505);
191       end;
192       if nf_swapped in flags then
193         cmpop:=swap_opcmp(cmpop);
194 
195       location_reset(location,LOC_REGISTER,OS_8);
196       location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
197 
198       if right.location.loc=LOC_CONSTANT then
199         current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_const(la_icmp,
200           location.register,cmpop,left.resultdef,left.location.register,right.location.value64))
201       else
202         current_asmdata.CurrAsmList.concat(taillvm.op_reg_cond_size_reg_reg(la_icmp,
203           location.register,cmpop,left.resultdef,left.location.register,right.location.register));
204 
205       tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
206       hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
207       location.register:=tmpreg;
208     end;
209 
210 
211   procedure tllvmaddnode.second_add64bit;
212     begin
213       second_addordinal;
214     end;
215 
216 
217   procedure tllvmaddnode.second_cmp64bit;
218     begin
219       second_cmpordinal;
220     end;
221 
222 
223   procedure tllvmaddnode.second_addfloat;
224     var
225       tmpreg: tregister;
226       op    : tllvmop;
227       llvmfpcmp : tllvmfpcmp;
228       size : tdef;
229       cmpop,
230       singleprec : boolean;
231     begin
232       pass_left_right;
233 
234       cmpop:=false;
235       singleprec:=tfloatdef(left.resultdef).floattype=s32real;
236       { avoid uninitialised warning }
237       llvmfpcmp:=lfc_invalid;
238       case nodetype of
239         addn :
240           op:=la_fadd;
241         muln :
242           op:=la_fmul;
243         subn :
244           op:=la_fsub;
245         slashn :
246           op:=la_fdiv;
247         ltn,lten,gtn,gten,
248         equaln,unequaln :
249           begin
250             op:=la_fcmp;
251             cmpop:=true;
252             case nodetype of
253               ltn:
254                 llvmfpcmp:=lfc_olt;
255               lten:
256                 llvmfpcmp:=lfc_ole;
257               gtn:
258                 llvmfpcmp:=lfc_ogt;
259               gten:
260                 llvmfpcmp:=lfc_oge;
261               equaln:
262                 llvmfpcmp:=lfc_oeq;
263               unequaln:
264                 llvmfpcmp:=lfc_one;
265               else
266                 internalerror(2015031506);
267             end;
268           end;
269         else
270           internalerror(2013102401);
271       end;
272 
273       { get the operands in the correct order; there are no special cases here,
274         everything is register-based }
275       if nf_swapped in flags then
276         swapleftright;
277 
278       { put both operands in a register }
279       hlcg.location_force_fpureg(current_asmdata.CurrAsmList,right.location,right.resultdef,true);
280       hlcg.location_force_fpureg(current_asmdata.CurrAsmList,left.location,left.resultdef,true);
281 
282       { initialize the result location }
283       if not cmpop then
284         begin
285           location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
286           location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
287         end
288       else
289         begin
290           location_reset(location,LOC_REGISTER,OS_8);
291           location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,llvmbool1type);
292         end;
293 
294       { see comment in thlcgllvm.a_loadfpu_ref_reg }
295       if tfloatdef(left.resultdef).floattype in [s64comp,s64currency] then
296         size:=sc80floattype
297       else
298         size:=left.resultdef;
299 
300       { emit the actual operation }
301       if not cmpop then
302         begin
303           current_asmdata.CurrAsmList.concat(taillvm.op_reg_size_reg_reg(op,location.register,size,
304             left.location.register,right.location.register))
305         end
306       else
307         begin
308           current_asmdata.CurrAsmList.concat(taillvm.op_reg_fpcond_size_reg_reg(op,
309             location.register,llvmfpcmp,size,left.location.register,right.location.register));
310           tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
311           hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,llvmbool1type,resultdef,location.register,tmpreg);
312           location.register:=tmpreg;
313         end;
314     end;
315 
316 
317   procedure tllvmaddnode.second_cmpfloat;
318     begin
319       second_addfloat;
320     end;
321 
322 
323 begin
324   caddnode:=tllvmaddnode;
325 end.
326 
327