1 {
2     Copyright (c) 2000-2009 by Florian Klaempfl and David Zhang
3 
4     Code generation for add nodes on the FVM32
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 ncpuadd;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28 uses
29   node, ncgadd, cpubase, aasmbase, cgbase;
30 
31 type
32 
33   { tmipsaddnode }
34 
35   tmipsaddnode = class(tcgaddnode)
36   private
37     procedure cmp64_lt(left_reg, right_reg: TRegister64;unsigned:boolean);
38     procedure cmp64_le(left_reg, right_reg: TRegister64;unsigned:boolean);
39     procedure second_generic_cmp32(unsigned: boolean);
40     procedure second_mul64bit;
41   protected
42     procedure second_addfloat; override;
43     procedure second_cmpfloat; override;
44     procedure second_cmpboolean; override;
45     procedure second_cmpsmallset; override;
46     procedure second_add64bit; override;
47     procedure second_cmp64bit; override;
48     procedure second_cmpordinal; override;
49     procedure second_addordinal; override;
50   public
use_generic_mul32to64null51     function use_generic_mul32to64: boolean; override;
use_generic_mul64bitnull52     function use_generic_mul64bit: boolean; override;
53   end;
54 
55 implementation
56 
57 uses
58   systems, globtype, globals,
59   cutils, verbose,
60   paramgr,
61   aasmtai, aasmcpu, aasmdata,
62   defutil,
63   cpuinfo,
64   {cgbase,} cgcpu, cgutils,
65   cpupara,
66   procinfo,
67   symconst,symdef,
68   ncon, nset, nadd,
69   ncgutil, hlcgobj, cgobj;
70 
71 {*****************************************************************************
72                                tmipsaddnode
73 *****************************************************************************}
74 
75 procedure tmipsaddnode.second_generic_cmp32(unsigned: boolean);
76 var
77   cond: TOpCmp;
78 begin
79   pass_left_right;
80   force_reg_left_right(True, True);
81   location_reset(location,LOC_FLAGS,OS_NO);
82 
83   cond:=cmpnode2topcmp(unsigned);
84   if nf_swapped in flags then
85     cond:=swap_opcmp(cond);
86 
87   location.resflags.cond:=cond;
88   location.resflags.reg1:=left.location.register;
89   location.resflags.use_const:=(right.location.loc=LOC_CONSTANT);
90   if location.resflags.use_const then
91     location.resflags.value:=right.location.value
92   else
93     location.resflags.reg2:=right.location.register;
94 end;
95 
96 
97 procedure tmipsaddnode.second_add64bit;
98 begin
99   if (nodetype=muln) then
100     second_mul64bit
101   else
102     inherited second_add64bit;
103 end;
104 
105 
106 const
107   cmpops: array[boolean] of TOpCmp = (OC_LT,OC_B);
108 
109 procedure tmipsaddnode.cmp64_lt(left_reg, right_reg: TRegister64;unsigned: boolean);
110 begin
111   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],right_reg.reghi,left_reg.reghi,location.truelabel);
112   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
113   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,right_reg.reglo,left_reg.reglo,location.truelabel);
114   cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
115 end;
116 
117 
118 procedure tmipsaddnode.cmp64_le(left_reg, right_reg: TRegister64;unsigned: boolean);
119 begin
120   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,cmpops[unsigned],left_reg.reghi,right_reg.reghi,location.falselabel);
121   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
122   cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_B,left_reg.reglo,right_reg.reglo,location.falselabel);
123   cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
124 end;
125 
126 
127 procedure tmipsaddnode.second_cmp64bit;
128 var
129   truelabel,
130   falselabel: tasmlabel;
131   unsigned: boolean;
132   left_reg,right_reg: TRegister64;
133 begin
134   current_asmdata.getjumplabel(truelabel);
135   current_asmdata.getjumplabel(falselabel);
136   location_reset_jump(location,truelabel,falselabel);
137 
138   pass_left_right;
139   force_reg_left_right(true,true);
140 
141   unsigned:=not(is_signed(left.resultdef)) or
142             not(is_signed(right.resultdef));
143 
144   left_reg:=left.location.register64;
145   if (right.location.loc=LOC_CONSTANT) then
146     begin
147       if lo(right.location.value64)=0 then
148         right_reg.reglo:=NR_R0
149       else
150         begin
151           right_reg.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
152           cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,lo(right.location.value64),right_reg.reglo);
153         end;
154       if hi(right.location.value64)=0 then
155         right_reg.reghi:=NR_R0
156       else
157         begin
158           right_reg.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
159           cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,hi(right.location.value64),right_reg.reghi);
160         end;
161     end
162   else
163     right_reg:=right.location.register64;
164 
165   case NodeType of
166     equaln:
167       begin
168         cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.falselabel);
169         cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.falselabel);
170         cg.a_jmp_always(current_asmdata.CurrAsmList,location.truelabel);
171       end;
172     unequaln:
173       begin
174         cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reghi,right_reg.reghi,location.truelabel);
175         cg.a_cmp_reg_reg_label(current_asmdata.CurrAsmList,OS_INT,OC_NE,left_reg.reglo,right_reg.reglo,location.truelabel);
176         cg.a_jmp_always(current_asmdata.CurrAsmList,location.falselabel);
177       end;
178   else
179     if nf_swapped in flags then
180       case NodeType of
181         ltn:
182           cmp64_lt(right_reg, left_reg,unsigned);
183         lten:
184           cmp64_le(right_reg, left_reg,unsigned);
185         gtn:
186           cmp64_lt(left_reg, right_reg,unsigned);
187         gten:
188           cmp64_le(left_reg, right_reg,unsigned);
189       end
190     else
191       case NodeType of
192         ltn:
193           cmp64_lt(left_reg, right_reg,unsigned);
194         lten:
195           cmp64_le(left_reg, right_reg,unsigned);
196         gtn:
197           cmp64_lt(right_reg, left_reg,unsigned);
198         gten:
199           cmp64_le(right_reg, left_reg,unsigned);
200       end;
201   end;
202 end;
203 
204 
205 procedure tmipsaddnode.second_addfloat;
206 var
207   op: TAsmOp;
208 begin
209   pass_left_right;
210   if (nf_swapped in flags) then
211     swapleftright;
212 
213         { force fpureg as location, left right doesn't matter
214           as both will be in a fpureg }
215   hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
216   hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
217 
218   location_reset(location, LOC_FPUREGISTER, def_cgsize(resultdef));
219   location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
220 
221   case nodetype of
222     addn:
223     begin
224       if location.size = OS_F64 then
225         op := A_ADD_D
226       else
227         op := A_ADD_S;
228     end;
229     muln:
230     begin
231       if location.size = OS_F64 then
232         op := A_MUL_D
233       else
234         op := A_MUL_S;
235     end;
236     subn:
237     begin
238       if location.size = OS_F64 then
239         op := A_SUB_D
240       else
241         op := A_SUB_S;
242     end;
243     slashn:
244     begin
245       if location.size = OS_F64 then
246         op := A_DIV_D
247       else
248         op := A_DIV_S;
249     end;
250     else
251       internalerror(200306014);
252   end;
253   current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,
254     location.Register, left.location.Register, right.location.Register));
255 
256 end;
257 
258 
259 const
260   ops_cmpfloat: array[boolean,ltn..unequaln] of TAsmOp = (
261   // ltn       lten      gtn       gten      equaln    unequaln
262     (A_C_LT_S, A_C_LE_S, A_C_LT_S, A_C_LE_S, A_C_EQ_S, A_C_EQ_S),
263     (A_C_LT_D, A_C_LE_D, A_C_LT_D, A_C_LE_D, A_C_EQ_D, A_C_EQ_D)
264   );
265 
266 procedure tmipsaddnode.second_cmpfloat;
267 var
268   op: tasmop;
269   lreg,rreg: tregister;
270 begin
271   pass_left_right;
272   if nf_swapped in flags then
273     swapleftright;
274 
275   hlcg.location_force_fpureg(current_asmdata.CurrAsmList, left.location, left.resultdef, True);
276   hlcg.location_force_fpureg(current_asmdata.CurrAsmList, right.location, right.resultdef, True);
277   location_reset(location, LOC_FLAGS, OS_NO);
278 
279   op:=ops_cmpfloat[left.location.size=OS_F64,nodetype];
280 
281   if (nodetype in [gtn,gten]) then
282     begin
283       lreg:=right.location.register;
284       rreg:=left.location.register;
285     end
286   else
287     begin
288       lreg:=left.location.register;
289       rreg:=right.location.register;
290     end;
291 
292   current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,lreg,rreg));
293   location.resflags.reg1:=NR_FCC0;
294   if (nodetype=unequaln) then
295     location.resflags.cond:=OC_EQ
296   else
297     location.resflags.cond:=OC_NE;
298 end;
299 
300 
301 procedure tmipsaddnode.second_cmpboolean;
302 begin
303   second_generic_cmp32(true);
304 end;
305 
306 
307 procedure tmipsaddnode.second_cmpsmallset;
308 begin
309   second_generic_cmp32(true);
310 end;
311 
312 
313 procedure tmipsaddnode.second_cmpordinal;
314 var
315   unsigned: boolean;
316 begin
317   unsigned := not (is_signed(left.resultdef)) or not (is_signed(right.resultdef));
318   second_generic_cmp32(unsigned);
319 end;
320 
321 
322 const
323   multops: array[boolean] of TAsmOp = (A_MULT, A_MULTU);
324 
325 procedure tmipsaddnode.second_addordinal;
326 var
327   unsigned: boolean;
328 begin
329   unsigned:=not(is_signed(left.resultdef)) or
330             not(is_signed(right.resultdef));
331   if (nodetype=muln) and is_64bit(resultdef) then
332     begin
333       pass_left_right;
334       force_reg_left_right(true,false);
335       location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
336       location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
337       location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
338       current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg(multops[unsigned],left.location.register,right.location.register));
339       current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
340       current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
341     end
342   else
343     inherited second_addordinal;
344 end;
345 
346 procedure tmipsaddnode.second_mul64bit;
347 var
348   list: TAsmList;
349   hreg1,hreg2,tmpreg: TRegister;
350 begin
351   list:=current_asmdata.CurrAsmList;
352   pass_left_right;
353   location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
354   hlcg.location_force_reg(list,left.location,left.resultdef,left.resultdef,true);
355   { calculate 32-bit terms lo(right)*hi(left) and hi(left)*lo(right) }
356   hreg1:=NR_NO;
357   hreg2:=NR_NO;
358   tmpreg:=NR_NO;
359   if (right.location.loc=LOC_CONSTANT) then
360     begin
361       { Omit zero terms, if any }
362       if hi(right.location.value64)<>0 then
363         begin
364           hreg2:=cg.getintregister(list,OS_INT);
365           tmpreg:=cg.getintregister(list,OS_INT);
366           cg.a_load_const_reg(list,OS_INT,longint(hi(right.location.value64)),tmpreg);
367           list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,tmpreg,left.location.register64.reglo));
368         end;
369       tmpreg:=NR_NO;
370       if lo(right.location.value64)<>0 then
371         begin
372           hreg1:=cg.getintregister(list,OS_INT);
373           tmpreg:=cg.getintregister(list,OS_INT);
374           cg.a_load_const_reg(list,OS_INT,longint(lo(right.location.value64)),tmpreg);
375           list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,tmpreg,left.location.register64.reghi));
376         end;
377     end
378   else
379     begin
380       hlcg.location_force_reg(list,right.location,right.resultdef,right.resultdef,true);
381       tmpreg:=right.location.register64.reglo;
382       hreg1:=cg.getintregister(list,OS_INT);
383       hreg2:=cg.getintregister(list,OS_INT);
384       list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg1,right.location.register64.reglo,left.location.register64.reghi));
385       list.concat(taicpu.op_reg_reg_reg(A_MUL,hreg2,right.location.register64.reghi,left.location.register64.reglo));
386     end;
387 
388   { At this point, tmpreg is either lo(right) or NR_NO if lo(left)*lo(right) is zero }
389   if (tmpreg=NR_NO) then
390     begin
391       if (hreg2<>NR_NO) and (hreg1<>NR_NO) then
392         begin
393           location.register64.reghi:=cg.getintregister(list,OS_INT);
394           list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,hreg1,hreg2));
395         end
396       else if (hreg2<>NR_NO) then
397         location.register64.reghi:=hreg2
398       else if (hreg1<>NR_NO) then
399         location.register64.reghi:=hreg1
400       else
401         InternalError(2014122701);
402       location.register64.reglo:=NR_R0;
403     end
404   else
405     begin
406       list.concat(taicpu.op_reg_reg(A_MULTU,left.location.register64.reglo,tmpreg));
407       location.register64.reghi:=cg.getintregister(list,OS_INT);
408       location.register64.reglo:=cg.getintregister(list,OS_INT);
409       current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFLO,location.register64.reglo));
410       current_asmdata.CurrAsmList.Concat(taicpu.op_reg(A_MFHI,location.register64.reghi));
411       if (hreg2<>NR_NO) then
412         list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg2));
413       if (hreg1<>NR_NO) then
414         list.concat(taicpu.op_reg_reg_reg(A_ADDU,location.register64.reghi,location.register64.reghi,hreg1));
415     end;
416 end;
417 
tmipsaddnode.use_generic_mul32to64null418 function tmipsaddnode.use_generic_mul32to64: boolean;
419 begin
420   result:=false;
421 end;
422 
tmipsaddnode.use_generic_mul64bitnull423 function tmipsaddnode.use_generic_mul64bit: boolean;
424 begin
425   result:=(cs_check_overflow in current_settings.localswitches) or
426     (not (CPUMIPS_HAS_ISA32R2 in cpu_capabilities[current_settings.cputype]));
427 end;
428 
429 
430 begin
431   caddnode := tmipsaddnode;
432 end.
433