1 {
2     Copyright (c) 1998-2002 by Florian Klaempfl
3 
4     Generate ARM assembler for type converting 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 narmcnv;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       node,ncnv,ncgcnv;
30 
31     type
32        tarmtypeconvnode = class(tcgtypeconvnode)
33          protected
first_int_to_realnull34            function first_int_to_real: tnode;override;
first_real_to_realnull35            function first_real_to_real: tnode; override;
36          { procedure second_int_to_int;override; }
37          { procedure second_string_to_string;override; }
38          { procedure second_cstring_to_pchar;override; }
39          { procedure second_string_to_chararray;override; }
40          { procedure second_array_to_pointer;override; }
first_int_to_realnull41          // function first_int_to_real: tnode; override;
42          { procedure second_pointer_to_array;override; }
43          { procedure second_chararray_to_string;override; }
44          { procedure second_char_to_string;override; }
45            procedure second_int_to_real;override;
46          // procedure second_real_to_real;override;
47          { procedure second_cord_to_pointer;override; }
48          { procedure second_proc_to_procvar;override; }
49          { procedure second_bool_to_int;override; }
50            procedure second_int_to_bool;override;
51          { procedure second_load_smallset;override;  }
52          { procedure second_ansistring_to_pchar;override; }
53          { procedure second_pchar_to_string;override; }
54          { procedure second_class_to_intf;override; }
55          { procedure second_char_to_char;override; }
56        end;
57 
58 implementation
59 
60    uses
61       verbose,globtype,globals,symdef,aasmbase,aasmtai,aasmdata,symtable,
62       defutil,
63       cgbase,cgutils,
64       pass_1,pass_2,procinfo,ncal,
65       ncgutil,
66       cpubase,cpuinfo,aasmcpu,cgobj,hlcgobj,cgcpu;
67 
68 
69 {*****************************************************************************
70                              FirstTypeConv
71 *****************************************************************************}
72 
tarmtypeconvnode.first_int_to_realnull73     function tarmtypeconvnode.first_int_to_real: tnode;
74       var
75         fname: string[19];
76       begin
77         if (cs_fp_emulation in current_settings.moduleswitches) or
78 {$ifdef cpufpemu}
79           (current_settings.fputype=fpu_soft) or
80 {$endif cpufpemu}
81           (current_settings.fputype=fpu_fpv4_s16) then
82           result:=inherited first_int_to_real
83         else
84           begin
85             { converting a 64bit integer to a float requires a helper }
86             if is_64bitint(left.resultdef) or
87               is_currency(left.resultdef) then
88               begin
89                 { hack to avoid double division by 10000, as it's
90                   already done by typecheckpass.resultdef_int_to_real }
91                 if is_currency(left.resultdef) then
92                   left.resultdef := s64inttype;
93                 if is_signed(left.resultdef) then
94                   fname := 'fpc_int64_to_double'
95                 else
96                   fname := 'fpc_qword_to_double';
97                 result := ccallnode.createintern(fname,ccallparanode.create(
98                   left,nil));
99                 left:=nil;
100                 if (tfloatdef(resultdef).floattype=s32real) then
101                   inserttypeconv(result,s32floattype);
102                 firstpass(result);
103                 exit;
104               end
105             else
106               { other integers are supposed to be 32 bit }
107               begin
108                 if is_signed(left.resultdef) then
109                   inserttypeconv(left,s32inttype)
110                 else
111                   inserttypeconv(left,u32inttype);
112                 firstpass(left);
113               end;
114             result := nil;
115             case current_settings.fputype of
116               fpu_fpa,
117               fpu_fpa10,
118               fpu_fpa11:
119                 expectloc:=LOC_FPUREGISTER;
120               fpu_vfpv2,
121               fpu_vfpv3,
122               fpu_vfpv4,
123               fpu_vfpv3_d16,
124               fpu_fpv4_s16:
125                 expectloc:=LOC_MMREGISTER;
126               else
127                 internalerror(2009112702);
128             end;
129           end;
130       end;
131 
tarmtypeconvnode.first_real_to_realnull132     function tarmtypeconvnode.first_real_to_real: tnode;
133       begin
134         if (current_settings.fputype=fpu_fpv4_s16) then
135           begin
136             case tfloatdef(left.resultdef).floattype of
137               s32real:
138                 case tfloatdef(resultdef).floattype of
139                   s64real:
140                     result:=ctypeconvnode.create_explicit(ccallnode.createintern('float32_to_float64',ccallparanode.create(
141                       ctypeconvnode.create_internal(left,search_system_type('FLOAT32REC').typedef),nil)),resultdef);
142                   s32real:
143                     begin
144                       result:=left;
145                       left:=nil;
146                     end;
147                   else
148                     internalerror(200610151);
149                 end;
150               s64real:
151                 case tfloatdef(resultdef).floattype of
152                   s32real:
153                     result:=ctypeconvnode.create_explicit(ccallnode.createintern('float64_to_float32',ccallparanode.create(
154                       ctypeconvnode.create_internal(left,search_system_type('FLOAT64').typedef),nil)),resultdef);
155                   s64real:
156                     begin
157                       result:=left;
158                       left:=nil;
159                     end;
160                   else
161                     internalerror(200610152);
162                 end;
163               else
164                 internalerror(200610153);
165             end;
166             left:=nil;
167             firstpass(result);
168             exit;
169           end
170         else
171           Result := inherited first_real_to_real;
172       end;
173 
174 
175     procedure tarmtypeconvnode.second_int_to_real;
176       const
177         signedprec2vfppf: array[boolean,OS_F32..OS_F64] of toppostfix =
178           ((PF_F32U32,PF_F64U32),
179            (PF_F32S32,PF_F64S32));
180       var
181         instr : taicpu;
182         href : treference;
183         l1,l2 : tasmlabel;
184         hregister : tregister;
185         signed : boolean;
186       begin
187         case current_settings.fputype of
188           fpu_fpa,
189           fpu_fpa10,
190           fpu_fpa11:
191             begin
192               { convert first to double to avoid precision loss }
193               location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
194               hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,u32inttype,true);
195               location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
196               instr:=taicpu.op_reg_reg(A_FLT,location.register,left.location.register);
197               if is_signed(left.resultdef) then
198                 begin
199                   instr.oppostfix:=cgsize2fpuoppostfix[def_cgsize(resultdef)];
200                   current_asmdata.CurrAsmList.concat(instr);
201                 end
202               else
203                 begin
204                   { flt does a signed load, fix this }
205                   case tfloatdef(resultdef).floattype of
206                     s32real,
207                     s64real:
208                       begin
209                         { converting dword to s64real first and cut off at the end avoids precision loss }
210                         instr.oppostfix:=PF_D;
211                         current_asmdata.CurrAsmList.concat(instr);
212 
213                         current_asmdata.getglobaldatalabel(l1);
214                         current_asmdata.getjumplabel(l2);
215                         reference_reset_symbol(href,l1,0,const_align(8),[]);
216 
217                         cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
218                         current_asmdata.CurrAsmList.concat(Taicpu.op_reg_const(A_CMP,left.location.register,0));
219                         cg.a_jmp_flags(current_asmdata.CurrAsmList,F_GE,l2);
220                         cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
221 
222                         hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,OS_F64);
223                         new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,l1.name,const_align(8));
224                         current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(l1));
225                         { I got this constant from a test program (FK) }
226                         current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_32bit($41f00000));
227                         current_asmdata.asmlists[al_typedconsts].concat(Tai_const.Create_32bit(0));
228 
229                         cg.a_loadfpu_ref_reg(current_asmdata.CurrAsmList,OS_F64,OS_F64,href,hregister);
230                         current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_ADF,location.register,hregister,location.register),PF_D));
231                         cg.a_label(current_asmdata.CurrAsmList,l2);
232 
233                         { cut off if we should convert to single }
234                         if tfloatdef(resultdef).floattype=s32real then
235                           begin
236                             hregister:=location.register;
237                             location.register:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
238                             cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
239                             current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_MVF,location.register,hregister),PF_S));
240                           end;
241                       end;
242                     else
243                       internalerror(200410031);
244                   end;
245               end;
246             end;
247           fpu_vfpv2,
248           fpu_vfpv3,
249           fpu_vfpv4,
250           fpu_vfpv3_d16:
251             begin
252               location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef));
253               signed:=left.location.size=OS_S32;
254               hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
255               if (left.location.size<>OS_F32) then
256                 internalerror(2009112703);
257               if left.location.size<>location.size then
258                 location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size)
259               else
260                 location.register:=left.location.register;
261               current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,
262                 location.register,left.location.register),
263                 signedprec2vfppf[signed,location.size]));
264             end;
265           fpu_fpv4_s16:
266             begin
267               location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef));
268               signed:=left.location.size=OS_S32;
269               hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,false);
270               if (left.location.size<>OS_F32) then
271                 internalerror(2009112703);
272               if left.location.size<>location.size then
273                 location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size)
274               else
275                 location.register:=left.location.register;
276               if signed then
277                 current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,location.register,left.location.register), PF_F32S32))
278               else
279                 current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VCVT,location.register,left.location.register), PF_F32U32));
280             end;
281         end;
282       end;
283 
284 
285     procedure tarmtypeconvnode.second_int_to_bool;
286       var
287         hreg1,
288         hregister : tregister;
289         href      : treference;
290         resflags  : tresflags;
291         hlabel    : tasmlabel;
292         newsize   : tcgsize;
293       begin
294          secondpass(left);
295          if codegenerror then
296           exit;
297 
298          { Explicit typecasts from any ordinal type to a boolean type }
299          { must not change the ordinal value                          }
300          if (nf_explicit in flags) and
301             not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then
302            begin
303               location_copy(location,left.location);
304               newsize:=def_cgsize(resultdef);
305               { change of size? change sign only if location is LOC_(C)REGISTER? Then we have to sign/zero-extend }
306               if (tcgsize2size[newsize]<>tcgsize2size[left.location.size]) or
307                  ((newsize<>left.location.size) and (location.loc in [LOC_REGISTER,LOC_CREGISTER])) then
308                 hlcg.location_force_reg(current_asmdata.CurrAsmList,location,left.resultdef,resultdef,true)
309               else
310                 location.size:=newsize;
311               exit;
312            end;
313 
314          { Load left node into flag F_NE/F_E }
315          resflags:=F_NE;
316 
317          if (left.location.loc in [LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF]) then
318            hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
319 
320          case left.location.loc of
321             LOC_CREFERENCE,
322             LOC_REFERENCE :
323               begin
324                 if left.location.size in [OS_64,OS_S64] then
325                  begin
326                    hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
327                    cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.reference,hregister);
328                    href:=left.location.reference;
329                    inc(href.offset,4);
330                    tbasecgarm(cg).cgsetflags:=true;
331                    cg.a_op_ref_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,href,hregister);
332                    tbasecgarm(cg).cgsetflags:=false;
333                  end
334                 else
335                  begin
336                    hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true);
337                    tbasecgarm(cg).cgsetflags:=true;
338                    cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,left.location.size,left.location.register,left.location.register);
339                    tbasecgarm(cg).cgsetflags:=false;
340                  end;
341               end;
342             LOC_FLAGS :
343               begin
344                 resflags:=left.location.resflags;
345               end;
346             LOC_REGISTER,LOC_CREGISTER :
347               begin
348                 if left.location.size in [OS_64,OS_S64] then
349                  begin
350                    hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
351                    cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,left.location.register64.reglo,hregister);
352                    tbasecgarm(cg).cgsetflags:=true;
353                    cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_32,left.location.register64.reghi,hregister);
354                    tbasecgarm(cg).cgsetflags:=false;
355                  end
356                 else
357                  begin
358                    tbasecgarm(cg).cgsetflags:=true;
359                    cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,left.location.size,left.location.register,left.location.register);
360                    tbasecgarm(cg).cgsetflags:=false;
361                  end;
362               end;
363             LOC_JUMP :
364               begin
365                 hregister:=cg.getintregister(current_asmdata.CurrAsmList,OS_INT);
366                 current_asmdata.getjumplabel(hlabel);
367                 cg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
368                 cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,1,hregister);
369                 cg.a_jmp_always(current_asmdata.CurrAsmList,hlabel);
370                 cg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
371                 cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_INT,0,hregister);
372                 cg.a_label(current_asmdata.CurrAsmList,hlabel);
373                 tbasecgarm(cg).cgsetflags:=true;
374                 cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_OR,OS_INT,hregister,hregister);
375                 tbasecgarm(cg).cgsetflags:=false;
376               end;
377             else
378               internalerror(200311301);
379          end;
380          { load flags to register }
381          location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
382          hreg1:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
383          cg.g_flags2reg(current_asmdata.CurrAsmList,location.size,resflags,hreg1);
384          cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS);
385          if (is_cbool(resultdef)) then
386            cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NEG,location.size,hreg1,hreg1);
387 
388 {$ifndef cpu64bitalu}
389          if (location.size in [OS_64,OS_S64]) then
390            begin
391              location.register64.reglo:=hreg1;
392              location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
393              if (is_cbool(resultdef)) then
394                { reglo is either 0 or -1 -> reghi has to become the same }
395                cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,location.register64.reglo,location.register64.reghi)
396              else
397                { unsigned }
398                cg.a_load_const_reg(current_asmdata.CurrAsmList,OS_32,0,location.register64.reghi);
399            end
400          else
401 {$endif cpu64bitalu}
402            location.register:=hreg1;
403       end;
404 
405 
406 begin
407   ctypeconvnode:=tarmtypeconvnode;
408 end.
409