fix-mixed-struct (patch by Pip Cet)
[tinycc.git] / arm-gen.c
Commit [+]AuthorDateLineData
4df5bd2e bellard2003-10-14 22:15:56 +00001/*
2 * ARMv4 code generator for TCC
0650ab01 Joseph Poirier2013-11-08 13:24:15 -06003 *
aa812e87 Edmund Grimley Evans2015-03-08 22:07:50 +00004 * Copyright (c) 2003 Daniel Glöckner
6ccee6ed Thomas Preud'homme2013-01-30 17:34:19 +01005 * Copyright (c) 2012 Thomas Preud'homme
4df5bd2e bellard2003-10-14 22:15:56 +00006 *
7 * Based on i386-gen.c by Fabrice Bellard
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
88a3ccab grischka2009-12-20 01:53:49 +010024#ifdef TARGET_DEFS_ONLY
25
70a088af
TP
Thomas Preud'homme2014-01-07 16:04:12 +080026#if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP)
27#error "Currently TinyCC only supports float computation with VFP instructions"
66d992d8 Thomas Preud'homme2011-05-16 14:54:22 +020028#endif
f99d3de2 grischka2007-12-04 20:38:09 +000029
4df5bd2e bellard2003-10-14 22:15:56 +000030/* number of available registers */
f99d3de2 grischka2007-12-04 20:38:09 +000031#ifdef TCC_ARM_VFP
32#define NB_REGS 13
33#else
4df5bd2e bellard2003-10-14 22:15:56 +000034#define NB_REGS 9
f99d3de2 grischka2007-12-04 20:38:09 +000035#endif
4df5bd2e bellard2003-10-14 22:15:56 +000036
4e04f67c seyko2015-05-14 07:32:24 +030037typedef int RegArgs;
38
828ccde9 grischka2013-01-30 17:45:21 +010039#ifndef TCC_ARM_VERSION
40# define TCC_ARM_VERSION 5
41#endif
42
4df5bd2e bellard2003-10-14 22:15:56 +000043/* a register can belong to several classes. The classes must be
44 sorted from more general to more precise (see gv2() code which does
45 assumptions on it). */
46#define RC_INT 0x0001 /* generic integer register */
47#define RC_FLOAT 0x0002 /* generic float register */
48#define RC_R0 0x0004
0650ab01 Joseph Poirier2013-11-08 13:24:15 -060049#define RC_R1 0x0008
4df5bd2e bellard2003-10-14 22:15:56 +000050#define RC_R2 0x0010
51#define RC_R3 0x0020
52#define RC_R12 0x0040
53#define RC_F0 0x0080
54#define RC_F1 0x0100
55#define RC_F2 0x0200
56#define RC_F3 0x0400
f99d3de2 grischka2007-12-04 20:38:09 +000057#ifdef TCC_ARM_VFP
58#define RC_F4 0x0800
59#define RC_F5 0x1000
60#define RC_F6 0x2000
61#define RC_F7 0x4000
62#endif
4df5bd2e bellard2003-10-14 22:15:56 +000063#define RC_IRET RC_R0 /* function return: integer register */
64#define RC_LRET RC_R1 /* function return: second integer register */
65#define RC_FRET RC_F0 /* function return: float register */
66
67/* pretty names for the registers */
68enum {
69 TREG_R0 = 0,
70 TREG_R1,
71 TREG_R2,
72 TREG_R3,
73 TREG_R12,
74 TREG_F0,
75 TREG_F1,
76 TREG_F2,
77 TREG_F3,
f99d3de2 grischka2007-12-04 20:38:09 +000078#ifdef TCC_ARM_VFP
79 TREG_F4,
80 TREG_F5,
81 TREG_F6,
82 TREG_F7,
83#endif
4df5bd2e bellard2003-10-14 22:15:56 +000084};
85
f99d3de2 grischka2007-12-04 20:38:09 +000086#ifdef TCC_ARM_VFP
87#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)
88#endif
89
4df5bd2e bellard2003-10-14 22:15:56 +000090/* return registers for function */
91#define REG_IRET TREG_R0 /* single word int return register */
92#define REG_LRET TREG_R1 /* second word return register (for long long) */
93#define REG_FRET TREG_F0 /* float return register */
94
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +020095#ifdef TCC_ARM_EABI
96#define TOK___divdi3 TOK___aeabi_ldivmod
97#define TOK___moddi3 TOK___aeabi_ldivmod
98#define TOK___udivdi3 TOK___aeabi_uldivmod
99#define TOK___umoddi3 TOK___aeabi_uldivmod
100#endif
101
4df5bd2e bellard2003-10-14 22:15:56 +0000102/* defined if function parameters must be evaluated in reverse order */
103#define INVERT_FUNC_PARAMS
104
105/* defined if structures are passed as pointers. Otherwise structures
106 are directly pushed on stack. */
0bdbd49e Urs Janssen2013-02-17 00:48:51 +0100107/* #define FUNC_STRUCT_PARAM_AS_PTR */
4df5bd2e bellard2003-10-14 22:15:56 +0000108
109/* pointer size, in bytes */
110#define PTR_SIZE 4
111
112/* long double size and alignment, in bytes */
f99d3de2 grischka2007-12-04 20:38:09 +0000113#ifdef TCC_ARM_VFP
114#define LDOUBLE_SIZE 8
115#endif
116
117#ifndef LDOUBLE_SIZE
4df5bd2e bellard2003-10-14 22:15:56 +0000118#define LDOUBLE_SIZE 8
f99d3de2 grischka2007-12-04 20:38:09 +0000119#endif
120
121#ifdef TCC_ARM_EABI
122#define LDOUBLE_ALIGN 8
123#else
4df5bd2e bellard2003-10-14 22:15:56 +0000124#define LDOUBLE_ALIGN 4
f99d3de2 grischka2007-12-04 20:38:09 +0000125#endif
126
4df5bd2e bellard2003-10-14 22:15:56 +0000127/* maximum alignment (for aligned attribute support) */
128#define MAX_ALIGN 8
129
130#define CHAR_IS_UNSIGNED
131
132/******************************************************/
133/* ELF defines */
134
135#define EM_TCC_TARGET EM_ARM
136
137/* relocation type for 32 bit data relocation */
138#define R_DATA_32 R_ARM_ABS32
5dadff3d Shinichiro Hamaji2009-07-19 06:42:23 +0900139#define R_DATA_PTR R_ARM_ABS32
4df5bd2e bellard2003-10-14 22:15:56 +0000140#define R_JMP_SLOT R_ARM_JUMP_SLOT
141#define R_COPY R_ARM_COPY
142
143#define ELF_START_ADDR 0x00008000
144#define ELF_PAGE_SIZE 0x1000
145
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +0800146enum float_abi {
147 ARM_SOFTFP_FLOAT,
148 ARM_HARD_FLOAT,
149};
150
4df5bd2e bellard2003-10-14 22:15:56 +0000151/******************************************************/
88a3ccab grischka2009-12-20 01:53:49 +0100152#else /* ! TARGET_DEFS_ONLY */
153/******************************************************/
154#include "tcc.h"
155
c6017182
TP
Thomas Preud'homme2014-02-09 23:15:33 +0800156enum float_abi float_abi;
157
88a3ccab grischka2009-12-20 01:53:49 +0100158ST_DATA const int reg_classes[NB_REGS] = {
159 /* r0 */ RC_INT | RC_R0,
160 /* r1 */ RC_INT | RC_R1,
161 /* r2 */ RC_INT | RC_R2,
162 /* r3 */ RC_INT | RC_R3,
163 /* r12 */ RC_INT | RC_R12,
164 /* f0 */ RC_FLOAT | RC_F0,
165 /* f1 */ RC_FLOAT | RC_F1,
166 /* f2 */ RC_FLOAT | RC_F2,
167 /* f3 */ RC_FLOAT | RC_F3,
168#ifdef TCC_ARM_VFP
169 /* d4/s8 */ RC_FLOAT | RC_F4,
170/* d5/s10 */ RC_FLOAT | RC_F5,
171/* d6/s12 */ RC_FLOAT | RC_F6,
172/* d7/s14 */ RC_FLOAT | RC_F7,
173#endif
174};
175
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200176static int func_sub_sp_offset, last_itod_magic;
f99d3de2 grischka2007-12-04 20:38:09 +0000177static int leaffunc;
4df5bd2e bellard2003-10-14 22:15:56 +0000178
d6d7686b grischka2013-02-08 19:07:11 +0100179#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
180static CType float_type, double_type, func_float_type, func_double_type;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +0800181ST_FUNC void arm_init(struct TCCState *s)
d6d7686b grischka2013-02-08 19:07:11 +0100182{
183 float_type.t = VT_FLOAT;
184 double_type.t = VT_DOUBLE;
185 func_float_type.t = VT_FUNC;
186 func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD);
187 func_double_type.t = VT_FUNC;
188 func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD);
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +0800189
190 float_abi = s->float_abi;
6f6ed8ac
TP
Thomas Preud'homme2014-03-25 19:54:04 +0800191#ifndef TCC_ARM_HARDFLOAT
192 tcc_warning("soft float ABI currently not supported: default to softfp");
193#endif
d6d7686b grischka2013-02-08 19:07:11 +0100194}
195#else
196#define func_float_type func_old_type
197#define func_double_type func_old_type
198#define func_ldouble_type func_old_type
b8610f14
TP
Thomas Preud'homme2014-03-25 19:48:33 +0800199ST_FUNC void arm_init(struct TCCState *s)
200{
201#if !defined (TCC_ARM_VFP)
202 tcc_warning("Support for FPA is deprecated and will be removed in next"
203 " release");
204#endif
205#if !defined (TCC_ARM_EABI)
206 tcc_warning("Support for OABI is deprecated and will be removed in next"
207 " release");
208#endif
209}
d6d7686b grischka2013-02-08 19:07:11 +0100210#endif
211
88a3ccab grischka2009-12-20 01:53:49 +0100212static int two2mask(int a,int b) {
213 return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
214}
215
216static int regmask(int r) {
217 return reg_classes[r]&~(RC_INT|RC_FLOAT);
218}
219
220/******************************************************/
221
774f0611 seyko2015-03-03 17:16:52 +0300222#if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP)
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +0800223char *default_elfinterp(struct TCCState *s)
224{
225 if (s->float_abi == ARM_HARD_FLOAT)
226 return "/lib/ld-linux-armhf.so.3";
227 else
228 return "/lib/ld-linux.so.3";
229}
230#endif
231
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200232void o(uint32_t i)
4df5bd2e bellard2003-10-14 22:15:56 +0000233{
234 /* this is a good place to start adding big-endian support*/
235 int ind1;
236
237 ind1 = ind + 4;
6e5b1cc4 bellard2004-10-04 22:19:21 +0000238 if (!cur_text_section)
bf374a5f grischka2011-08-11 17:07:56 +0200239 tcc_error("compiler error! This happens f.ex. if the compiler\n"
6e5b1cc4 bellard2004-10-04 22:19:21 +0000240 "can't evaluate constant expressions outside of a function.");
4df5bd2e bellard2003-10-14 22:15:56 +0000241 if (ind1 > cur_text_section->data_allocated)
242 section_realloc(cur_text_section, ind1);
243 cur_text_section->data[ind++] = i&255;
244 i>>=8;
245 cur_text_section->data[ind++] = i&255;
0650ab01 Joseph Poirier2013-11-08 13:24:15 -0600246 i>>=8;
4df5bd2e bellard2003-10-14 22:15:56 +0000247 cur_text_section->data[ind++] = i&255;
248 i>>=8;
249 cur_text_section->data[ind++] = i;
250}
251
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200252static uint32_t stuff_const(uint32_t op, uint32_t c)
4df5bd2e bellard2003-10-14 22:15:56 +0000253{
254 int try_neg=0;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200255 uint32_t nc = 0, negop = 0;
6bbfb8f6 bellard2004-11-07 15:43:15 +0000256
4df5bd2e bellard2003-10-14 22:15:56 +0000257 switch(op&0x1F00000)
258 {
259 case 0x800000: //add
260 case 0x400000: //sub
261 try_neg=1;
262 negop=op^0xC00000;
263 nc=-c;
264 break;
265 case 0x1A00000: //mov
266 case 0x1E00000: //mvn
267 try_neg=1;
268 negop=op^0x400000;
269 nc=~c;
270 break;
271 case 0x200000: //xor
272 if(c==~0)
273 return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
274 break;
275 case 0x0: //and
276 if(c==~0)
277 return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
278 case 0x1C00000: //bic
279 try_neg=1;
280 negop=op^0x1C00000;
281 nc=~c;
282 break;
283 case 0x1800000: //orr
284 if(c==~0)
285 return (op&0xFFF0FFFF)|0x1E00000;
286 break;
287 }
288 do {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200289 uint32_t m;
4df5bd2e bellard2003-10-14 22:15:56 +0000290 int i;
291 if(c<256) /* catch undefined <<32 */
292 return op|c;
293 for(i=2;i<32;i+=2) {
294 m=(0xff>>i)|(0xff<<(32-i));
295 if(!(c&~m))
296 return op|(i<<7)|(c<<i)|(c>>(32-i));
297 }
298 op=negop;
299 c=nc;
300 } while(try_neg--);
301 return 0;
302}
303
304
305//only add,sub
3de023b6
DG
Daniel Glöckner2010-05-13 22:17:09 +0200306void stuff_const_harder(uint32_t op, uint32_t v) {
307 uint32_t x;
4df5bd2e bellard2003-10-14 22:15:56 +0000308 x=stuff_const(op,v);
309 if(x)
310 o(x);
311 else {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200312 uint32_t a[16], nv, no, o2, n2;
4df5bd2e bellard2003-10-14 22:15:56 +0000313 int i,j,k;
314 a[0]=0xff;
315 o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
316 for(i=1;i<16;i++)
317 a[i]=(a[i-1]>>2)|(a[i-1]<<30);
318 for(i=0;i<12;i++)
530b77e3 Daniel Glöckner2009-05-07 00:23:06 +0200319 for(j=i<4?i+12:15;j>=i+4;j--)
4df5bd2e bellard2003-10-14 22:15:56 +0000320 if((v&(a[i]|a[j]))==v) {
321 o(stuff_const(op,v&a[i]));
322 o(stuff_const(o2,v&a[j]));
323 return;
324 }
325 no=op^0xC00000;
326 n2=o2^0xC00000;
327 nv=-v;
328 for(i=0;i<12;i++)
530b77e3 Daniel Glöckner2009-05-07 00:23:06 +0200329 for(j=i<4?i+12:15;j>=i+4;j--)
4df5bd2e bellard2003-10-14 22:15:56 +0000330 if((nv&(a[i]|a[j]))==nv) {
331 o(stuff_const(no,nv&a[i]));
332 o(stuff_const(n2,nv&a[j]));
333 return;
334 }
335 for(i=0;i<8;i++)
530b77e3
DG
Daniel Glöckner2009-05-07 00:23:06 +0200336 for(j=i+4;j<12;j++)
337 for(k=i<4?i+12:15;k>=j+4;k--)
4df5bd2e bellard2003-10-14 22:15:56 +0000338 if((v&(a[i]|a[j]|a[k]))==v) {
339 o(stuff_const(op,v&a[i]));
340 o(stuff_const(o2,v&a[j]));
341 o(stuff_const(o2,v&a[k]));
342 return;
343 }
344 no=op^0xC00000;
345 nv=-v;
346 for(i=0;i<8;i++)
530b77e3
DG
Daniel Glöckner2009-05-07 00:23:06 +0200347 for(j=i+4;j<12;j++)
348 for(k=i<4?i+12:15;k>=j+4;k--)
4df5bd2e bellard2003-10-14 22:15:56 +0000349 if((nv&(a[i]|a[j]|a[k]))==nv) {
350 o(stuff_const(no,nv&a[i]));
351 o(stuff_const(n2,nv&a[j]));
352 o(stuff_const(n2,nv&a[k]));
353 return;
354 }
355 o(stuff_const(op,v&a[0]));
356 o(stuff_const(o2,v&a[4]));
357 o(stuff_const(o2,v&a[8]));
358 o(stuff_const(o2,v&a[12]));
359 }
360}
361
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200362ST_FUNC uint32_t encbranch(int pos, int addr, int fail)
4df5bd2e bellard2003-10-14 22:15:56 +0000363{
364 addr-=pos+8;
365 addr/=4;
366 if(addr>=0x1000000 || addr<-0x1000000) {
367 if(fail)
bf374a5f grischka2011-08-11 17:07:56 +0200368 tcc_error("FIXME: function bigger than 32MB");
4df5bd2e bellard2003-10-14 22:15:56 +0000369 return 0;
370 }
371 return 0x0A000000|(addr&0xffffff);
372}
373
374int decbranch(int pos)
375{
376 int x;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200377 x=*(uint32_t *)(cur_text_section->data + pos);
4df5bd2e bellard2003-10-14 22:15:56 +0000378 x&=0x00ffffff;
379 if(x&0x800000)
380 x-=0x1000000;
381 return x*4+pos+8;
382}
383
384/* output a symbol and patch all calls to it */
385void gsym_addr(int t, int a)
386{
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200387 uint32_t *x;
4df5bd2e bellard2003-10-14 22:15:56 +0000388 int lt;
389 while(t) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200390 x=(uint32_t *)(cur_text_section->data + t);
4df5bd2e bellard2003-10-14 22:15:56 +0000391 t=decbranch(lt=t);
392 if(a==lt+4)
393 *x=0xE1A00000; // nop
394 else {
395 *x &= 0xff000000;
396 *x |= encbranch(lt,a,1);
397 }
398 }
399}
400
401void gsym(int t)
402{
403 gsym_addr(t, ind);
404}
405
f99d3de2 grischka2007-12-04 20:38:09 +0000406#ifdef TCC_ARM_VFP
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200407static uint32_t vfpr(int r)
f99d3de2 grischka2007-12-04 20:38:09 +0000408{
409 if(r<TREG_F0 || r>TREG_F7)
bf374a5f grischka2011-08-11 17:07:56 +0200410 tcc_error("compiler error! register %i is no vfp register",r);
f99d3de2 grischka2007-12-04 20:38:09 +0000411 return r-5;
412}
413#else
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200414static uint32_t fpr(int r)
4df5bd2e bellard2003-10-14 22:15:56 +0000415{
6e5b1cc4 bellard2004-10-04 22:19:21 +0000416 if(r<TREG_F0 || r>TREG_F3)
bf374a5f grischka2011-08-11 17:07:56 +0200417 tcc_error("compiler error! register %i is no fpa register",r);
4df5bd2e bellard2003-10-14 22:15:56 +0000418 return r-5;
419}
f99d3de2 grischka2007-12-04 20:38:09 +0000420#endif
4df5bd2e bellard2003-10-14 22:15:56 +0000421
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200422static uint32_t intr(int r)
4df5bd2e bellard2003-10-14 22:15:56 +0000423{
6e5b1cc4 bellard2004-10-04 22:19:21 +0000424 if(r==4)
425 return 12;
426 if((r<0 || r>4) && r!=14)
bf374a5f grischka2011-08-11 17:07:56 +0200427 tcc_error("compiler error! register %i is no int register",r);
6e5b1cc4 bellard2004-10-04 22:19:21 +0000428 return r;
4df5bd2e bellard2003-10-14 22:15:56 +0000429}
430
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200431static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift)
4df5bd2e bellard2003-10-14 22:15:56 +0000432{
433 if(*off>maxoff || *off&((1<<shift)-1)) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200434 uint32_t x, y;
4df5bd2e bellard2003-10-14 22:15:56 +0000435 x=0xE280E000;
436 if(*sgn)
437 x=0xE240E000;
438 x|=(*base)<<16;
439 *base=14; // lr
440 y=stuff_const(x,*off&~maxoff);
441 if(y) {
442 o(y);
443 *off&=maxoff;
444 return;
445 }
446 y=stuff_const(x,(*off+maxoff)&~maxoff);
447 if(y) {
448 o(y);
449 *sgn=!*sgn;
450 *off=((*off+maxoff)&~maxoff)-*off;
451 return;
452 }
453 stuff_const_harder(x,*off&~maxoff);
454 *off&=maxoff;
455 }
456}
457
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200458static uint32_t mapcc(int cc)
4df5bd2e bellard2003-10-14 22:15:56 +0000459{
460 switch(cc)
461 {
462 case TOK_ULT:
f99d3de2 grischka2007-12-04 20:38:09 +0000463 return 0x30000000; /* CC/LO */
4df5bd2e bellard2003-10-14 22:15:56 +0000464 case TOK_UGE:
f99d3de2 grischka2007-12-04 20:38:09 +0000465 return 0x20000000; /* CS/HS */
4df5bd2e bellard2003-10-14 22:15:56 +0000466 case TOK_EQ:
f99d3de2 grischka2007-12-04 20:38:09 +0000467 return 0x00000000; /* EQ */
4df5bd2e bellard2003-10-14 22:15:56 +0000468 case TOK_NE:
f99d3de2 grischka2007-12-04 20:38:09 +0000469 return 0x10000000; /* NE */
4df5bd2e bellard2003-10-14 22:15:56 +0000470 case TOK_ULE:
f99d3de2 grischka2007-12-04 20:38:09 +0000471 return 0x90000000; /* LS */
4df5bd2e bellard2003-10-14 22:15:56 +0000472 case TOK_UGT:
f99d3de2 grischka2007-12-04 20:38:09 +0000473 return 0x80000000; /* HI */
474 case TOK_Nset:
475 return 0x40000000; /* MI */
476 case TOK_Nclear:
477 return 0x50000000; /* PL */
4df5bd2e bellard2003-10-14 22:15:56 +0000478 case TOK_LT:
f99d3de2 grischka2007-12-04 20:38:09 +0000479 return 0xB0000000; /* LT */
4df5bd2e bellard2003-10-14 22:15:56 +0000480 case TOK_GE:
f99d3de2 grischka2007-12-04 20:38:09 +0000481 return 0xA0000000; /* GE */
4df5bd2e bellard2003-10-14 22:15:56 +0000482 case TOK_LE:
f99d3de2 grischka2007-12-04 20:38:09 +0000483 return 0xD0000000; /* LE */
4df5bd2e bellard2003-10-14 22:15:56 +0000484 case TOK_GT:
f99d3de2 grischka2007-12-04 20:38:09 +0000485 return 0xC0000000; /* GT */
4df5bd2e bellard2003-10-14 22:15:56 +0000486 }
bf374a5f grischka2011-08-11 17:07:56 +0200487 tcc_error("unexpected condition code");
f99d3de2 grischka2007-12-04 20:38:09 +0000488 return 0xE0000000; /* AL */
4df5bd2e bellard2003-10-14 22:15:56 +0000489}
490
491static int negcc(int cc)
492{
493 switch(cc)
494 {
495 case TOK_ULT:
496 return TOK_UGE;
497 case TOK_UGE:
498 return TOK_ULT;
499 case TOK_EQ:
500 return TOK_NE;
501 case TOK_NE:
502 return TOK_EQ;
503 case TOK_ULE:
504 return TOK_UGT;
505 case TOK_UGT:
506 return TOK_ULE;
f99d3de2 grischka2007-12-04 20:38:09 +0000507 case TOK_Nset:
508 return TOK_Nclear;
509 case TOK_Nclear:
510 return TOK_Nset;
4df5bd2e bellard2003-10-14 22:15:56 +0000511 case TOK_LT:
512 return TOK_GE;
513 case TOK_GE:
514 return TOK_LT;
515 case TOK_LE:
516 return TOK_GT;
517 case TOK_GT:
518 return TOK_LE;
519 }
bf374a5f grischka2011-08-11 17:07:56 +0200520 tcc_error("unexpected condition code");
4df5bd2e bellard2003-10-14 22:15:56 +0000521 return TOK_NE;
522}
523
524/* load 'r' from value 'sv' */
525void load(int r, SValue *sv)
526{
527 int v, ft, fc, fr, sign;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200528 uint32_t op;
4df5bd2e bellard2003-10-14 22:15:56 +0000529 SValue v1;
530
531 fr = sv->r;
532 ft = sv->type.t;
533 fc = sv->c.ul;
534
535 if(fc>=0)
536 sign=0;
537 else {
538 sign=1;
539 fc=-fc;
540 }
0650ab01 Joseph Poirier2013-11-08 13:24:15 -0600541
4df5bd2e bellard2003-10-14 22:15:56 +0000542 v = fr & VT_VALMASK;
543 if (fr & VT_LVAL) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200544 uint32_t base = 0xB; // fp
4df5bd2e bellard2003-10-14 22:15:56 +0000545 if(v == VT_LLOCAL) {
546 v1.type.t = VT_PTR;
547 v1.r = VT_LOCAL | VT_LVAL;
548 v1.c.ul = sv->c.ul;
549 load(base=14 /* lr */, &v1);
550 fc=sign=0;
551 v=VT_LOCAL;
552 } else if(v == VT_CONST) {
553 v1.type.t = VT_PTR;
554 v1.r = fr&~VT_LVAL;
555 v1.c.ul = sv->c.ul;
556 v1.sym=sv->sym;
557 load(base=14, &v1);
558 fc=sign=0;
559 v=VT_LOCAL;
560 } else if(v < VT_CONST) {
561 base=intr(v);
562 fc=sign=0;
563 v=VT_LOCAL;
564 }
565 if(v == VT_LOCAL) {
566 if(is_float(ft)) {
567 calcaddr(&base,&fc,&sign,1020,2);
f99d3de2 grischka2007-12-04 20:38:09 +0000568#ifdef TCC_ARM_VFP
569 op=0xED100A00; /* flds */
570 if(!sign)
571 op|=0x800000;
572 if ((ft & VT_BTYPE) != VT_FLOAT)
573 op|=0x100; /* flds -> fldd */
574 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
575#else
4df5bd2e bellard2003-10-14 22:15:56 +0000576 op=0xED100100;
577 if(!sign)
578 op|=0x800000;
6e5b1cc4 bellard2004-10-04 22:19:21 +0000579#if LDOUBLE_SIZE == 8
4df5bd2e bellard2003-10-14 22:15:56 +0000580 if ((ft & VT_BTYPE) != VT_FLOAT)
581 op|=0x8000;
6e5b1cc4 bellard2004-10-04 22:19:21 +0000582#else
583 if ((ft & VT_BTYPE) == VT_DOUBLE)
584 op|=0x8000;
585 else if ((ft & VT_BTYPE) == VT_LDOUBLE)
586 op|=0x400000;
587#endif
4df5bd2e bellard2003-10-14 22:15:56 +0000588 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
f99d3de2 grischka2007-12-04 20:38:09 +0000589#endif
590 } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE
591 || (ft & VT_BTYPE) == VT_SHORT) {
4df5bd2e bellard2003-10-14 22:15:56 +0000592 calcaddr(&base,&fc,&sign,255,0);
593 op=0xE1500090;
594 if ((ft & VT_BTYPE) == VT_SHORT)
595 op|=0x20;
596 if ((ft & VT_UNSIGNED) == 0)
597 op|=0x40;
598 if(!sign)
599 op|=0x800000;
600 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
601 } else {
602 calcaddr(&base,&fc,&sign,4095,0);
603 op=0xE5100000;
604 if(!sign)
605 op|=0x800000;
f6b50558 Thomas Preud'homme2013-06-14 16:18:16 +0200606 if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL)
4df5bd2e bellard2003-10-14 22:15:56 +0000607 op|=0x400000;
608 o(op|(intr(r)<<12)|fc|(base<<16));
609 }
610 return;
611 }
612 } else {
613 if (v == VT_CONST) {
614 op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
615 if (fr & VT_SYM || !op) {
616 o(0xE59F0000|(intr(r)<<12));
617 o(0xEA000000);
618 if(fr & VT_SYM)
619 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
620 o(sv->c.ul);
621 } else
622 o(op);
623 return;
624 } else if (v == VT_LOCAL) {
625 op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
626 if (fr & VT_SYM || !op) {
627 o(0xE59F0000|(intr(r)<<12));
628 o(0xEA000000);
629 if(fr & VT_SYM) // needed ?
630 greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
631 o(sv->c.ul);
632 o(0xE08B0000|(intr(r)<<12)|intr(r));
633 } else
634 o(op);
635 return;
636 } else if(v == VT_CMP) {
637 o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
638 o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
639 return;
640 } else if (v == VT_JMP || v == VT_JMPI) {
641 int t;
642 t = v & 1;
643 o(0xE3A00000|(intr(r)<<12)|t);
644 o(0xEA000000);
645 gsym(sv->c.ul);
646 o(0xE3A00000|(intr(r)<<12)|(t^1));
647 return;
648 } else if (v < VT_CONST) {
649 if(is_float(ft))
f99d3de2 grischka2007-12-04 20:38:09 +0000650#ifdef TCC_ARM_VFP
651 o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */
652#else
4df5bd2e bellard2003-10-14 22:15:56 +0000653 o(0xEE008180|(fpr(r)<<12)|fpr(v));
f99d3de2 grischka2007-12-04 20:38:09 +0000654#endif
4df5bd2e bellard2003-10-14 22:15:56 +0000655 else
656 o(0xE1A00000|(intr(r)<<12)|intr(v));
657 return;
658 }
659 }
bf374a5f grischka2011-08-11 17:07:56 +0200660 tcc_error("load unimplemented!");
4df5bd2e bellard2003-10-14 22:15:56 +0000661}
662
663/* store register 'r' in lvalue 'v' */
664void store(int r, SValue *sv)
665{
666 SValue v1;
667 int v, ft, fc, fr, sign;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200668 uint32_t op;
4df5bd2e bellard2003-10-14 22:15:56 +0000669
670 fr = sv->r;
671 ft = sv->type.t;
672 fc = sv->c.ul;
673
674 if(fc>=0)
675 sign=0;
676 else {
677 sign=1;
678 fc=-fc;
679 }
0650ab01
JP
Joseph Poirier2013-11-08 13:24:15 -0600680
681 v = fr & VT_VALMASK;
4df5bd2e bellard2003-10-14 22:15:56 +0000682 if (fr & VT_LVAL || fr == VT_LOCAL) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200683 uint32_t base = 0xb;
4df5bd2e bellard2003-10-14 22:15:56 +0000684 if(v < VT_CONST) {
685 base=intr(v);
686 v=VT_LOCAL;
687 fc=sign=0;
688 } else if(v == VT_CONST) {
689 v1.type.t = ft;
690 v1.r = fr&~VT_LVAL;
691 v1.c.ul = sv->c.ul;
692 v1.sym=sv->sym;
693 load(base=14, &v1);
694 fc=sign=0;
0650ab01 Joseph Poirier2013-11-08 13:24:15 -0600695 v=VT_LOCAL;
4df5bd2e bellard2003-10-14 22:15:56 +0000696 }
697 if(v == VT_LOCAL) {
698 if(is_float(ft)) {
699 calcaddr(&base,&fc,&sign,1020,2);
f99d3de2 grischka2007-12-04 20:38:09 +0000700#ifdef TCC_ARM_VFP
701 op=0xED000A00; /* fsts */
0650ab01
JP
Joseph Poirier2013-11-08 13:24:15 -0600702 if(!sign)
703 op|=0x800000;
704 if ((ft & VT_BTYPE) != VT_FLOAT)
f99d3de2 grischka2007-12-04 20:38:09 +0000705 op|=0x100; /* fsts -> fstd */
706 o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16));
707#else
4df5bd2e bellard2003-10-14 22:15:56 +0000708 op=0xED000100;
709 if(!sign)
710 op|=0x800000;
6e5b1cc4 bellard2004-10-04 22:19:21 +0000711#if LDOUBLE_SIZE == 8
4df5bd2e bellard2003-10-14 22:15:56 +0000712 if ((ft & VT_BTYPE) != VT_FLOAT)
713 op|=0x8000;
6e5b1cc4 bellard2004-10-04 22:19:21 +0000714#else
715 if ((ft & VT_BTYPE) == VT_DOUBLE)
716 op|=0x8000;
717 if ((ft & VT_BTYPE) == VT_LDOUBLE)
718 op|=0x400000;
719#endif
4df5bd2e bellard2003-10-14 22:15:56 +0000720 o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
f99d3de2 grischka2007-12-04 20:38:09 +0000721#endif
4df5bd2e bellard2003-10-14 22:15:56 +0000722 return;
723 } else if((ft & VT_BTYPE) == VT_SHORT) {
724 calcaddr(&base,&fc,&sign,255,0);
725 op=0xE14000B0;
726 if(!sign)
727 op|=0x800000;
728 o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
729 } else {
730 calcaddr(&base,&fc,&sign,4095,0);
731 op=0xE5000000;
732 if(!sign)
733 op|=0x800000;
f6b50558 Thomas Preud'homme2013-06-14 16:18:16 +0200734 if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL)
4df5bd2e bellard2003-10-14 22:15:56 +0000735 op|=0x400000;
736 o(op|(intr(r)<<12)|fc|(base<<16));
737 }
738 return;
739 }
740 }
bf374a5f grischka2011-08-11 17:07:56 +0200741 tcc_error("store unimplemented");
4df5bd2e bellard2003-10-14 22:15:56 +0000742}
743
744static void gadd_sp(int val)
745{
746 stuff_const_harder(0xE28DD000,val);
747}
748
749/* 'is_jmp' is '1' if it is a jump */
750static void gcall_or_jmp(int is_jmp)
751{
752 int r;
753 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +0200754 uint32_t x;
4df5bd2e bellard2003-10-14 22:15:56 +0000755 /* constant case */
756 x=encbranch(ind,ind+vtop->c.ul,0);
757 if(x) {
758 if (vtop->r & VT_SYM) {
759 /* relocation case */
760 greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
761 } else
762 put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
763 o(x|(is_jmp?0xE0000000:0xE1000000));
764 } else {
765 if(!is_jmp)
766 o(0xE28FE004); // add lr,pc,#4
767 o(0xE51FF004); // ldr pc,[pc,#-4]
768 if (vtop->r & VT_SYM)
769 greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
770 o(vtop->c.ul);
771 }
772 } else {
773 /* otherwise, indirect call */
774 r = gv(RC_INT);
775 if(!is_jmp)
776 o(0xE1A0E00F); // mov lr,pc
777 o(0xE1A0F000|intr(r)); // mov pc,r
778 }
779}
780
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100781/* Return whether a structure is an homogeneous float aggregate or not.
782 The answer is true if all the elements of the structure are of the same
783 primitive float type and there is less than 4 elements.
784
785 type: the type corresponding to the structure to be tested */
786static int is_hgen_float_aggr(CType *type)
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100787{
788 if ((type->t & VT_BTYPE) == VT_STRUCT) {
789 struct Sym *ref;
790 int btype, nb_fields = 0;
791
63a84713 Thomas Preud'homme2013-11-22 00:13:05 +0800792 ref = type->ref->next;
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100793 btype = ref->type.t & VT_BTYPE;
794 if (btype == VT_FLOAT || btype == VT_DOUBLE) {
795 for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++);
796 return !ref && nb_fields <= 4;
797 }
798 }
799 return 0;
800}
801
802struct avail_regs {
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100803 signed char avail[3]; /* 3 holes max with only float and double alignments */
804 int first_hole; /* first available hole */
805 int last_hole; /* last available hole (none if equal to first_hole) */
806 int first_free_reg; /* next free register in the sequence, hole excluded */
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100807};
808
809#define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 }
810
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100811/* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC
812 param) according to the rules described in the procedure call standard for
813 the ARM architecture (AAPCS). If found, the registers are assigned to this
814 VFP CPRC parameter. Registers are allocated in sequence unless a hole exists
815 and the parameter is a single float.
816
817 avregs: opaque structure to keep track of available VFP co-processor regs
818 align: alignment contraints for the param, as returned by type_size()
819 size: size of the parameter, as returned by type_size() */
820int assign_vfpreg(struct avail_regs *avregs, int align, int size)
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100821{
822 int first_reg = 0;
823
824 if (avregs->first_free_reg == -1)
825 return -1;
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100826 if (align >> 3) { /* double alignment */
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +0100827 first_reg = avregs->first_free_reg;
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100828 /* alignment contraint not respected so use next reg and record hole */
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100829 if (first_reg & 1)
830 avregs->avail[avregs->last_hole++] = first_reg++;
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100831 } else { /* no special alignment (float or array of float) */
832 /* if single float and a hole is available, assign the param to it */
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100833 if (size == 4 && avregs->first_hole != avregs->last_hole)
834 return avregs->avail[avregs->first_hole++];
835 else
836 first_reg = avregs->first_free_reg;
837 }
838 if (first_reg + size / 4 <= 16) {
839 avregs->first_free_reg = first_reg + size / 4;
840 return first_reg;
841 }
842 avregs->first_free_reg = -1;
843 return -1;
844}
389c25c4
TP
Thomas Preud'homme2013-12-11 09:01:28 +0800845
846/* Returns whether all params need to be passed in core registers or not.
847 This is the case for function part of the runtime ABI. */
848int floats_in_core_regs(SValue *sval)
849{
850 if (!sval->sym)
851 return 0;
852
853 switch (sval->sym->v) {
854 case TOK___floatundisf:
855 case TOK___floatundidf:
856 case TOK___fixunssfdi:
857 case TOK___fixunsdfdi:
858#ifndef TCC_ARM_VFP
859 case TOK___fixunsxfdi:
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +0100860#endif
389c25c4
TP
Thomas Preud'homme2013-12-11 09:01:28 +0800861 case TOK___floatdisf:
862 case TOK___floatdidf:
863 case TOK___fixsfdi:
864 case TOK___fixdfdi:
865 return 1;
866
867 default:
868 return 0;
869 }
870}
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +0100871
4e04f67c seyko2015-05-14 07:32:24 +0300872ST_FUNC int regargs_nregs(RegArgs *args)
873{
874 return *args;
875}
876
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800877/* Return the number of registers needed to return the struct, or 0 if
878 returning via struct pointer. */
4e04f67c seyko2015-05-14 07:32:24 +0300879ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args) {
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800880#ifdef TCC_ARM_EABI
881 int size, align;
882 size = type_size(vt, &align);
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +0800883 if (float_abi == ARM_HARD_FLOAT && !variadic &&
884 (is_float(vt->t) || is_hgen_float_aggr(vt))) {
dcec8673 Thomas Preud'homme2013-11-22 09:27:15 +0800885 *ret_align = 8;
50899e30 Michael Matz2015-03-09 00:19:59 +0100886 *regsize = 8;
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800887 ret->ref = NULL;
888 ret->t = VT_DOUBLE;
4e04f67c seyko2015-05-14 07:32:24 +0300889 *args = (size + 7) >> 3;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +0800890 } else if (size <= 4) {
dcec8673 Thomas Preud'homme2013-11-22 09:27:15 +0800891 *ret_align = 4;
50899e30 Michael Matz2015-03-09 00:19:59 +0100892 *regsize = 4;
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800893 ret->ref = NULL;
894 ret->t = VT_INT;
4e04f67c seyko2015-05-14 07:32:24 +0300895 *args = 1;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +0800896 } else
4e04f67c seyko2015-05-14 07:32:24 +0300897 *args = 0;
dcec8673 Thomas Preud'homme2013-11-22 09:27:15 +0800898#else
4e04f67c seyko2015-05-14 07:32:24 +0300899 *args = 0;
dcec8673 Thomas Preud'homme2013-11-22 09:27:15 +0800900#endif
4e04f67c seyko2015-05-14 07:32:24 +0300901
902 return *args != 0;
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800903}
904
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100905/* Parameters are classified according to how they are copied to their final
906 destination for the function call. Because the copying is performed class
907 after class according to the order in the union below, it is important that
908 some constraints about the order of the members of this union are respected:
909 - CORE_STRUCT_CLASS must come after STACK_CLASS;
910 - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and
911 VFP_STRUCT_CLASS;
912 - VFP_STRUCT_CLASS must come after VFP_CLASS.
913 See the comment for the main loop in copy_params() for the reason. */
914enum reg_class {
915 STACK_CLASS = 0,
916 CORE_STRUCT_CLASS,
917 VFP_CLASS,
918 VFP_STRUCT_CLASS,
919 CORE_CLASS,
920 NB_CLASSES
921};
2bbfaf43 James Lyon2013-04-18 17:27:34 +0100922
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100923struct param_plan {
924 int start; /* first reg or addr used depending on the class */
925 int end; /* last reg used or next free addr depending on the class */
926 SValue *sval; /* pointer to SValue on the value stack */
927 struct param_plan *prev; /* previous element in this class */
928};
929
930struct plan {
931 struct param_plan *pplans; /* array of all the param plans */
932 struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */
933};
934
935#define add_param_plan(plan,pplan,class) \
936 do { \
937 pplan.prev = plan->clsplans[class]; \
938 plan->pplans[plan ## _nb] = pplan; \
939 plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \
940 } while(0)
941
942/* Assign parameters to registers and stack with alignment according to the
943 rules in the procedure call standard for the ARM architecture (AAPCS).
944 The overall assignment is recorded in an array of per parameter structures
945 called parameter plans. The parameter plans are also further organized in a
946 number of linked lists, one per class of parameter (see the comment for the
947 definition of union reg_class).
948
949 nb_args: number of parameters of the function for which a call is generated
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +0800950 float_abi: float ABI in use for this function call
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100951 plan: the structure where the overall assignment is recorded
952 todo: a bitmap that record which core registers hold a parameter
953
954 Returns the amount of stack space needed for parameter passing
955
956 Note: this function allocated an array in plan->pplans with tcc_malloc. It
3e9a7e9d Vincent Lefevre2014-04-07 13:31:00 +0200957 is the responsibility of the caller to free this array once used (ie not
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100958 before copy_params). */
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +0800959static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo)
4df5bd2e bellard2003-10-14 22:15:56 +0000960{
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100961 int i, size, align;
962 int ncrn /* next core register number */, nsaa /* next stacked argument address*/;
963 int plan_nb = 0;
964 struct param_plan pplan;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +0100965 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
4df5bd2e bellard2003-10-14 22:15:56 +0000966
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100967 ncrn = nsaa = 0;
968 *todo = 0;
969 plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans));
970 memset(plan->clsplans, 0, sizeof(plan->clsplans));
8d90205f Thomas Preud'homme2012-11-28 22:13:02 +0100971 for(i = nb_args; i-- ;) {
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100972 int j, start_vfpreg = 0;
10750872
DG
Daniel Glöckner2014-03-29 17:50:40 +0100973 CType type = vtop[-i].type;
974 type.t &= ~VT_ARRAY;
975 size = type_size(&type, &align);
4760804d
TP
Thomas Preud'homme2014-02-03 11:13:42 +0800976 size = (size + 3) & ~3;
977 align = (align + 3) & ~3;
f99d3de2 grischka2007-12-04 20:38:09 +0000978 switch(vtop[-i].type.t & VT_BTYPE) {
979 case VT_STRUCT:
980 case VT_FLOAT:
981 case VT_DOUBLE:
982 case VT_LDOUBLE:
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +0800983 if (float_abi == ARM_HARD_FLOAT) {
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100984 int is_hfa = 0; /* Homogeneous float aggregate */
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +0100985
986 if (is_float(vtop[-i].type.t)
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +0100987 || (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) {
988 int end_vfpreg;
989
990 start_vfpreg = assign_vfpreg(&avregs, align, size);
991 end_vfpreg = start_vfpreg + ((size - 1) >> 2);
992 if (start_vfpreg >= 0) {
993 pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]};
994 if (is_hfa)
995 add_param_plan(plan, pplan, VFP_STRUCT_CLASS);
996 else
997 add_param_plan(plan, pplan, VFP_CLASS);
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +0100998 continue;
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +0100999 } else
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001000 break;
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001001 }
1002 }
4760804d Thomas Preud'homme2014-02-03 11:13:42 +08001003 ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1);
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001004 if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) {
1005 /* The parameter is allocated both in core register and on stack. As
1006 * such, it can be of either class: it would either be the last of
1007 * CORE_STRUCT_CLASS or the first of STACK_CLASS. */
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001008 for (j = ncrn; j < 4 && j < ncrn + size / 4; j++)
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001009 *todo|=(1<<j);
1010 pplan = (struct param_plan) {ncrn, j, &vtop[-i]};
1011 add_param_plan(plan, pplan, CORE_STRUCT_CLASS);
1012 ncrn += size/4;
1013 if (ncrn > 4)
1014 nsaa = (ncrn - 4) * 4;
b7d017de Thomas Preud'homme2013-11-05 17:50:30 +08001015 } else {
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001016 ncrn = 4;
f99d3de2 grischka2007-12-04 20:38:09 +00001017 break;
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001018 }
1019 continue;
f99d3de2 grischka2007-12-04 20:38:09 +00001020 default:
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001021 if (ncrn < 4) {
1022 int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG;
1023
1024 if (is_long) {
1025 ncrn = (ncrn + 1) & -2;
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001026 if (ncrn == 4)
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001027 break;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001028 }
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001029 pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]};
1030 ncrn++;
1031 if (is_long)
1032 pplan.end = ncrn++;
1033 add_param_plan(plan, pplan, CORE_CLASS);
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001034 continue;
1035 }
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001036 }
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001037 nsaa = (nsaa + (align - 1)) & ~(align - 1);
1038 pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]};
1039 add_param_plan(plan, pplan, STACK_CLASS);
1040 nsaa += size; /* size already rounded up before */
6e5b1cc4 bellard2004-10-04 22:19:21 +00001041 }
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001042 return nsaa;
1043}
1044
1045#undef add_param_plan
1046
1047/* Copy parameters to their final destination (core reg, VFP reg or stack) for
1048 function call.
1049
1050 nb_args: number of parameters the function take
1051 plan: the overall assignment plan for parameters
41ce391c
TP
Thomas Preud'homme2013-11-21 21:09:44 +08001052 todo: a bitmap indicating what core reg will hold a parameter
1053
1054 Returns the number of SValue added by this function on the value stack */
1055static int copy_params(int nb_args, struct plan *plan, int todo)
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001056{
41ce391c Thomas Preud'homme2013-11-21 21:09:44 +08001057 int size, align, r, i, nb_extra_sval = 0;
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001058 struct param_plan *pplan;
1059
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001060 /* Several constraints require parameters to be copied in a specific order:
1061 - structures are copied to the stack before being loaded in a reg;
1062 - floats loaded to an odd numbered VFP reg are first copied to the
1063 preceding even numbered VFP reg and then moved to the next VFP reg.
1064
1065 It is thus important that:
1066 - structures assigned to core regs must be copied after parameters
1067 assigned to the stack but before structures assigned to VFP regs because
1068 a structure can lie partly in core registers and partly on the stack;
1069 - parameters assigned to the stack and all structures be copied before
1070 parameters assigned to a core reg since copying a parameter to the stack
1071 require using a core reg;
1072 - parameters assigned to VFP regs be copied before structures assigned to
1073 VFP regs as the copy might use an even numbered VFP reg that already
1074 holds part of a structure. */
1075 for(i = 0; i < NB_CLASSES; i++) {
1076 for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) {
1077 vpushv(pplan->sval);
1078 pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */
1079 switch(i) {
1080 case STACK_CLASS:
1081 case CORE_STRUCT_CLASS:
1082 case VFP_STRUCT_CLASS:
1083 if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) {
48fc7466 Thomas Preud'homme2013-11-25 10:51:39 +08001084 int padding = 0;
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001085 size = type_size(&pplan->sval->type, &align);
1086 /* align to stack align size */
1087 size = (size + 3) & ~3;
1088 if (i == STACK_CLASS && pplan->prev)
48fc7466
TP
Thomas Preud'homme2013-11-25 10:51:39 +08001089 padding = pplan->start - pplan->prev->end;
1090 size += padding; /* Add padding if any */
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001091 /* allocate the necessary size on stack */
1092 gadd_sp(-size);
1093 /* generate structure store */
1094 r = get_reg(RC_INT);
48fc7466 Thomas Preud'homme2013-11-25 10:51:39 +08001095 o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001096 vset(&vtop->type, r | VT_LVAL, 0);
1097 vswap();
48fc7466
TP
Thomas Preud'homme2013-11-25 10:51:39 +08001098 vstore(); /* memcpy to current sp + potential padding */
1099
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001100 /* Homogeneous float aggregate are loaded to VFP registers
1101 immediately since there is no way of loading data in multiple
1102 non consecutive VFP registers as what is done for other
1103 structures (see the use of todo). */
1104 if (i == VFP_STRUCT_CLASS) {
1105 int first = pplan->start, nb = pplan->end - first + 1;
1106 /* vpop.32 {pplan->start, ..., pplan->end} */
1107 o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb);
1108 /* No need to write the register used to a SValue since VFP regs
1109 cannot be used for gcall_or_jmp */
1110 }
1111 } else {
1112 if (is_float(pplan->sval->type.t)) {
f99d3de2 grischka2007-12-04 20:38:09 +00001113#ifdef TCC_ARM_VFP
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001114 r = vfpr(gv(RC_FLOAT)) << 12;
1115 if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT)
1116 size = 4;
1117 else {
1118 size = 8;
1119 r |= 0x101; /* vpush.32 -> vpush.64 */
1120 }
1121 o(0xED2D0A01 + r); /* vpush */
f99d3de2 grischka2007-12-04 20:38:09 +00001122#else
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001123 r = fpr(gv(RC_FLOAT)) << 12;
1124 if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT)
1125 size = 4;
1126 else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE)
1127 size = 8;
1128 else
1129 size = LDOUBLE_SIZE;
1130
1131 if (size == 12)
1132 r |= 0x400000;
1133 else if(size == 8)
1134 r|=0x8000;
1135
1136 o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001137#endif
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001138 } else {
1139 /* simple type (currently always same size) */
1140 /* XXX: implicit cast ? */
1141 size=4;
1142 if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
1143 lexpand_nr();
1144 size = 8;
1145 r = gv(RC_INT);
1146 o(0xE52D0004|(intr(r)<<12)); /* push r */
1147 vtop--;
1148 }
1149 r = gv(RC_INT);
1150 o(0xE52D0004|(intr(r)<<12)); /* push r */
1151 }
1152 if (i == STACK_CLASS && pplan->prev)
1153 gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */
1154 }
1155 break;
1156
1157 case VFP_CLASS:
1158 gv(regmask(TREG_F0 + (pplan->start >> 1)));
1159 if (pplan->start & 1) { /* Must be in upper part of double register */
1160 o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */
1161 vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */
1162 }
1163 break;
1164
1165 case CORE_CLASS:
1166 if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) {
1167 lexpand_nr();
1168 gv(regmask(pplan->end));
1169 pplan->sval->r2 = vtop->r;
1170 vtop--;
1171 }
1172 gv(regmask(pplan->start));
1173 /* Mark register as used so that gcall_or_jmp use another one
1174 (regs >=4 are free as never used to pass parameters) */
1175 pplan->sval->r = vtop->r;
1176 break;
4df5bd2e bellard2003-10-14 22:15:56 +00001177 }
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001178 vtop--;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001179 }
6e5b1cc4 bellard2004-10-04 22:19:21 +00001180 }
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001181
1182 /* Manually free remaining registers since next parameters are loaded
1183 * manually, without the help of gv(int). */
1184 save_regs(nb_args);
1185
1186 if(todo) {
1187 o(0xE8BD0000|todo); /* pop {todo} */
1188 for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) {
41ce391c Thomas Preud'homme2013-11-21 21:09:44 +08001189 int r;
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001190 pplan->sval->r = pplan->start;
82b257c2
TP
Thomas Preud'homme2013-11-25 11:00:51 +08001191 /* An SValue can only pin 2 registers at best (r and r2) but a structure
1192 can occupy more than 2 registers. Thus, we need to push on the value
1193 stack some fake parameter to have on SValue for each registers used
1194 by a structure (r2 is not used). */
41ce391c
TP
Thomas Preud'homme2013-11-21 21:09:44 +08001195 for (r = pplan->start + 1; r <= pplan->end; r++) {
1196 if (todo & (1 << r)) {
1197 nb_extra_sval++;
1198 vpushi(0);
1199 vtop->r = r;
1200 }
1201 }
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001202 }
4df5bd2e bellard2003-10-14 22:15:56 +00001203 }
41ce391c Thomas Preud'homme2013-11-21 21:09:44 +08001204 return nb_extra_sval;
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001205}
1206
1207/* Generate function call. The function address is pushed first, then
1208 all the parameters in call order. This functions pops all the
1209 parameters and the function address. */
1210void gfunc_call(int nb_args)
1211{
d9d60a1e Thomas Preud'homme2013-11-22 00:15:34 +08001212 int r, args_size;
774f0611 seyko2015-03-03 17:16:52 +03001213 int def_float_abi = float_abi;
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001214 int todo;
1215 struct plan plan;
1216
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001217#ifdef TCC_ARM_EABI
774f0611 seyko2015-03-03 17:16:52 +03001218 int variadic;
1219
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001220 if (float_abi == ARM_HARD_FLOAT) {
1221 variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS);
9fc57302
TP
Thomas Preud'homme2014-02-02 20:29:24 +08001222 if (variadic || floats_in_core_regs(&vtop[-nb_args]))
1223 float_abi = ARM_SOFTFP_FLOAT;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001224 }
389c25c4 Thomas Preud'homme2013-12-11 09:01:28 +08001225#endif
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001226 /* cannot let cpu flags if other instruction are generated. Also avoid leaving
1227 VT_JMP anywhere except on the top of the stack because it would complicate
1228 the code generator. */
1229 r = vtop->r & VT_VALMASK;
1230 if (r == VT_CMP || (r & ~1) == VT_JMP)
1231 gv(RC_INT);
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001232
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +08001233 args_size = assign_regs(nb_args, float_abi, &plan, &todo);
0c40bc89
TP
Thomas Preud'homme2013-11-17 18:26:56 +08001234
1235#ifdef TCC_ARM_EABI
1236 if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */
1237 args_size = (args_size + 7) & ~7;
1238 o(0xE24DD004); /* sub sp, sp, #4 */
1239 }
1240#endif
1241
41ce391c Thomas Preud'homme2013-11-21 21:09:44 +08001242 nb_args += copy_params(nb_args, &plan, todo);
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001243 tcc_free(plan.pplans);
1244
1245 /* Move fct SValue on top as required by gcall_or_jmp */
1246 vrotb(nb_args + 1);
4df5bd2e bellard2003-10-14 22:15:56 +00001247 gcall_or_jmp(0);
1248 if (args_size)
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001249 gadd_sp(args_size); /* pop all parameters passed on the stack */
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001250#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +08001251 if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) {
f99d3de2 grischka2007-12-04 20:38:09 +00001252 if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) {
1528a085 Thomas Preud'homme2013-02-04 20:02:38 +01001253 o(0xEE000A10); /*vmov s0, r0 */
f99d3de2 grischka2007-12-04 20:38:09 +00001254 } else {
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001255 o(0xEE000B10); /* vmov.32 d0[0], r0 */
1256 o(0xEE201B10); /* vmov.32 d0[1], r1 */
f99d3de2 grischka2007-12-04 20:38:09 +00001257 }
1258 }
1259#endif
1528a085
TP
Thomas Preud'homme2013-02-04 20:02:38 +01001260 vtop -= nb_args + 1; /* Pop all params and fct address from value stack */
1261 leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */
9fc57302 Thomas Preud'homme2014-02-02 20:29:24 +08001262 float_abi = def_float_abi;
4df5bd2e bellard2003-10-14 22:15:56 +00001263}
1264
1265/* generate function prolog of type 't' */
1266void gfunc_prolog(CType *func_type)
1267{
1268 Sym *sym,*sym2;
50899e30 Michael Matz2015-03-09 00:19:59 +01001269 int n, nf, size, align, rs, struct_ret = 0;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001270 int addr, pn, sn; /* pn=core, sn=stack */
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +08001271 CType ret_type;
4e04f67c seyko2015-05-14 07:32:24 +03001272 RegArgs dummy;
4df5bd2e bellard2003-10-14 22:15:56 +00001273
774f0611 seyko2015-03-03 17:16:52 +03001274#ifdef TCC_ARM_EABI
1275 struct avail_regs avregs = AVAIL_REGS_INITIALIZER;
1276#endif
1277
4df5bd2e bellard2003-10-14 22:15:56 +00001278 sym = func_type->ref;
1279 func_vt = sym->type;
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +08001280 func_var = (func_type->ref->c == FUNC_ELLIPSIS);
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001281
1282 n = nf = 0;
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +08001283 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
4e04f67c seyko2015-05-14 07:32:24 +03001284 !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs, &dummy))
f99d3de2 grischka2007-12-04 20:38:09 +00001285 {
4df5bd2e bellard2003-10-14 22:15:56 +00001286 n++;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001287 struct_ret = 1;
f63c7509 Thomas Preud'homme2013-01-26 20:09:04 +01001288 func_vc = 12; /* Offset from fp of the place to store the result */
4df5bd2e bellard2003-10-14 22:15:56 +00001289 }
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001290 for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) {
4df5bd2e bellard2003-10-14 22:15:56 +00001291 size = type_size(&sym2->type, &align);
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001292#ifdef TCC_ARM_EABI
1293 if (float_abi == ARM_HARD_FLOAT && !func_var &&
1294 (is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) {
c3e7c725
TP
Thomas Preud'homme2013-11-21 21:14:25 +08001295 int tmpnf = assign_vfpreg(&avregs, align, size);
1296 tmpnf += (size + 3) / 4;
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001297 nf = (tmpnf > nf) ? tmpnf : nf;
1298 } else
1299#endif
1300 if (n < 4)
1301 n += (size + 3) / 4;
4df5bd2e bellard2003-10-14 22:15:56 +00001302 }
1303 o(0xE1A0C00D); /* mov ip,sp */
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +08001304 if (func_var)
4df5bd2e bellard2003-10-14 22:15:56 +00001305 n=4;
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +08001306 if (n) {
4df5bd2e bellard2003-10-14 22:15:56 +00001307 if(n>4)
1308 n=4;
f99d3de2 grischka2007-12-04 20:38:09 +00001309#ifdef TCC_ARM_EABI
1310 n=(n+1)&-2;
1311#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001312 o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
1313 }
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001314 if (nf) {
1315 if (nf>16)
1316 nf=16;
1317 nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */
1318 o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */
1319 }
f99d3de2 grischka2007-12-04 20:38:09 +00001320 o(0xE92D5800); /* save fp, ip, lr */
f63c7509 Thomas Preud'homme2013-01-26 20:09:04 +01001321 o(0xE1A0B00D); /* mov fp, sp */
4df5bd2e bellard2003-10-14 22:15:56 +00001322 func_sub_sp_offset = ind;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001323 o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001324
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001325#ifdef TCC_ARM_EABI
1326 if (float_abi == ARM_HARD_FLOAT) {
4d86b207 Daniel Glöckner2013-05-01 16:17:54 +02001327 func_vc += nf * 4;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001328 avregs = AVAIL_REGS_INITIALIZER;
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001329 }
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001330#endif
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001331 pn = struct_ret, sn = 0;
1332 while ((sym = sym->next)) {
1333 CType *type;
1334 type = &sym->type;
1335 size = type_size(type, &align);
1336 size = (size + 3) >> 2;
1337 align = (align + 3) & ~3;
1338#ifdef TCC_ARM_EABI
1339 if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t)
1340 || is_hgen_float_aggr(&sym->type))) {
1341 int fpn = assign_vfpreg(&avregs, align, size << 2);
1342 if (fpn >= 0)
1343 addr = fpn * 4;
1344 else
1345 goto from_stack;
1346 } else
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001347#endif
b6247d1f Thomas Preud'homme2014-01-07 15:23:54 +08001348 if (pn < 4) {
7f6095bf
TP
Thomas Preud'homme2011-12-10 07:22:09 +01001349#ifdef TCC_ARM_EABI
1350 pn = (pn + (align-1)/4) & -(align/4);
1351#endif
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001352 addr = (nf + pn) * 4;
1353 pn += size;
1354 if (!sn && pn > 4)
1355 sn = (pn - 4);
1356 } else {
f99d3de2 grischka2007-12-04 20:38:09 +00001357#ifdef TCC_ARM_EABI
774f0611 seyko2015-03-03 17:16:52 +03001358from_stack:
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001359 sn = (sn + (align-1)/4) & -(align/4);
f99d3de2 grischka2007-12-04 20:38:09 +00001360#endif
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001361 addr = (n + nf + sn) * 4;
1362 sn += size;
7f6095bf Thomas Preud'homme2011-12-10 07:22:09 +01001363 }
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001364 sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t),
1365 addr + 12);
4df5bd2e bellard2003-10-14 22:15:56 +00001366 }
1367 last_itod_magic=0;
f99d3de2 grischka2007-12-04 20:38:09 +00001368 leaffunc = 1;
0f81512d Thomas Preud'homme2013-01-27 01:08:01 +01001369 loc = 0;
4df5bd2e bellard2003-10-14 22:15:56 +00001370}
1371
1372/* generate function epilog */
1373void gfunc_epilog(void)
1374{
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001375 uint32_t x;
f99d3de2 grischka2007-12-04 20:38:09 +00001376 int diff;
8efaa711
TP
Thomas Preud'homme2014-01-06 22:27:39 +08001377 /* Copy float return value to core register if base standard is used and
1378 float computation is made with VFP */
b6247d1f
TP
Thomas Preud'homme2014-01-07 15:23:54 +08001379#if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)
1380 if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) {
f99d3de2 grischka2007-12-04 20:38:09 +00001381 if((func_vt.t & VT_BTYPE) == VT_FLOAT)
1382 o(0xEE100A10); /* fmrs r0, s0 */
1383 else {
1384 o(0xEE100B10); /* fmrdl r0, d0 */
1385 o(0xEE301B10); /* fmrdh r1, d0 */
1386 }
1387 }
1388#endif
f63c7509 Thomas Preud'homme2013-01-26 20:09:04 +01001389 o(0xE89BA800); /* restore fp, sp, pc */
f99d3de2 grischka2007-12-04 20:38:09 +00001390 diff = (-loc + 3) & -4;
1391#ifdef TCC_ARM_EABI
1392 if(!leaffunc)
0f81512d Thomas Preud'homme2013-01-27 01:08:01 +01001393 diff = ((diff + 11) & -8) - 4;
f99d3de2 grischka2007-12-04 20:38:09 +00001394#endif
0f81512d Thomas Preud'homme2013-01-27 01:08:01 +01001395 if(diff > 0) {
f99d3de2 grischka2007-12-04 20:38:09 +00001396 x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */
4df5bd2e bellard2003-10-14 22:15:56 +00001397 if(x)
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001398 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x;
4df5bd2e bellard2003-10-14 22:15:56 +00001399 else {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001400 int addr;
4df5bd2e bellard2003-10-14 22:15:56 +00001401 addr=ind;
1402 o(0xE59FC004); /* ldr ip,[pc+4] */
f99d3de2 grischka2007-12-04 20:38:09 +00001403 o(0xE04BD00C); /* sub sp,fp,ip */
4df5bd2e bellard2003-10-14 22:15:56 +00001404 o(0xE1A0F00E); /* mov pc,lr */
f99d3de2 grischka2007-12-04 20:38:09 +00001405 o(diff);
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001406 *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
4df5bd2e bellard2003-10-14 22:15:56 +00001407 }
1408 }
1409}
1410
1411/* generate a jump to a label */
1412int gjmp(int t)
1413{
1414 int r;
1415 r=ind;
1416 o(0xE0000000|encbranch(r,t,1));
1417 return r;
1418}
1419
1420/* generate a jump to a fixed address */
1421void gjmp_addr(int a)
1422{
1423 gjmp(a);
1424}
1425
1426/* generate a test. set 'inv' to invert test. Stack entry is popped */
1427int gtst(int inv, int t)
1428{
1429 int v, r;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001430 uint32_t op;
4df5bd2e bellard2003-10-14 22:15:56 +00001431 v = vtop->r & VT_VALMASK;
1432 r=ind;
1433 if (v == VT_CMP) {
1434 op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
1435 op|=encbranch(r,t,1);
1436 o(op);
1437 t=r;
2437ccdc seyko2015-03-03 15:51:09 +03001438 } else if (v == VT_JMP || v == VT_JMPI) {
4df5bd2e bellard2003-10-14 22:15:56 +00001439 if ((v & 1) == inv) {
1440 if(!vtop->c.i)
1441 vtop->c.i=t;
1442 else {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001443 uint32_t *x;
4df5bd2e bellard2003-10-14 22:15:56 +00001444 int p,lp;
1445 if(t) {
1446 p = vtop->c.i;
1447 do {
1448 p = decbranch(lp=p);
1449 } while(p);
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001450 x = (uint32_t *)(cur_text_section->data + lp);
4df5bd2e bellard2003-10-14 22:15:56 +00001451 *x &= 0xff000000;
1452 *x |= encbranch(lp,t,1);
1453 }
1454 t = vtop->c.i;
1455 }
1456 } else {
1457 t = gjmp(t);
1458 gsym(vtop->c.i);
1459 }
4df5bd2e bellard2003-10-14 22:15:56 +00001460 }
1461 vtop--;
1462 return t;
1463}
1464
1465/* generate an integer binary operation */
1466void gen_opi(int op)
1467{
6bbfb8f6 bellard2004-11-07 15:43:15 +00001468 int c, func = 0;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001469 uint32_t opc = 0, r, fr;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001470 unsigned short retreg = REG_IRET;
4df5bd2e bellard2003-10-14 22:15:56 +00001471
1472 c=0;
1473 switch(op) {
1474 case '+':
1475 opc = 0x8;
1476 c=1;
1477 break;
1478 case TOK_ADDC1: /* add with carry generation */
1479 opc = 0x9;
1480 c=1;
1481 break;
1482 case '-':
1483 opc = 0x4;
1484 c=1;
1485 break;
1486 case TOK_SUBC1: /* sub with carry generation */
1487 opc = 0x5;
1488 c=1;
1489 break;
1490 case TOK_ADDC2: /* add with carry use */
1491 opc = 0xA;
1492 c=1;
1493 break;
1494 case TOK_SUBC2: /* sub with carry use */
1495 opc = 0xC;
1496 c=1;
1497 break;
1498 case '&':
1499 opc = 0x0;
1500 c=1;
1501 break;
1502 case '^':
1503 opc = 0x2;
1504 c=1;
1505 break;
1506 case '|':
1507 opc = 0x18;
1508 c=1;
1509 break;
1510 case '*':
1511 gv2(RC_INT, RC_INT);
1512 r = vtop[-1].r;
1513 fr = vtop[0].r;
1514 vtop--;
1515 o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
1516 return;
1517 case TOK_SHL:
1518 opc = 0;
1519 c=2;
1520 break;
1521 case TOK_SHR:
1522 opc = 1;
1523 c=2;
1524 break;
1525 case TOK_SAR:
1526 opc = 2;
1527 c=2;
1528 break;
1529 case '/':
1530 case TOK_PDIV:
1531 func=TOK___divsi3;
1532 c=3;
1533 break;
1534 case TOK_UDIV:
1535 func=TOK___udivsi3;
1536 c=3;
1537 break;
1538 case '%':
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02001539#ifdef TCC_ARM_EABI
1540 func=TOK___aeabi_idivmod;
1541 retreg=REG_LRET;
1542#else
4df5bd2e bellard2003-10-14 22:15:56 +00001543 func=TOK___modsi3;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001544#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001545 c=3;
1546 break;
1547 case TOK_UMOD:
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02001548#ifdef TCC_ARM_EABI
1549 func=TOK___aeabi_uidivmod;
1550 retreg=REG_LRET;
1551#else
4df5bd2e bellard2003-10-14 22:15:56 +00001552 func=TOK___umodsi3;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001553#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001554 c=3;
1555 break;
1556 case TOK_UMULL:
1557 gv2(RC_INT, RC_INT);
1558 r=intr(vtop[-1].r2=get_reg(RC_INT));
1559 c=vtop[-1].r;
1560 vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
1561 vtop--;
1562 o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
1563 return;
1564 default:
1565 opc = 0x15;
1566 c=1;
6bbfb8f6 bellard2004-11-07 15:43:15 +00001567 break;
4df5bd2e bellard2003-10-14 22:15:56 +00001568 }
1569 switch(c) {
1570 case 1:
1571 if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1572 if(opc == 4 || opc == 5 || opc == 0xc) {
1573 vswap();
1574 opc|=2; // sub -> rsb
1575 }
1576 }
6e5b1cc4 bellard2004-10-04 22:19:21 +00001577 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1578 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1579 gv(RC_INT);
4df5bd2e bellard2003-10-14 22:15:56 +00001580 vswap();
1581 c=intr(gv(RC_INT));
1582 vswap();
1583 opc=0xE0000000|(opc<<20)|(c<<16);
1584 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001585 uint32_t x;
4df5bd2e bellard2003-10-14 22:15:56 +00001586 x=stuff_const(opc|0x2000000,vtop->c.i);
1587 if(x) {
1588 r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1589 o(x|(r<<12));
1590 goto done;
1591 }
1592 }
1593 fr=intr(gv(RC_INT));
1594 r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1595 o(opc|(r<<12)|fr);
1596done:
1597 vtop--;
1598 if (op >= TOK_ULT && op <= TOK_GT) {
1599 vtop->r = VT_CMP;
1600 vtop->c.i = op;
1601 }
1602 break;
1603 case 2:
1604 opc=0xE1A00000|(opc<<5);
6e5b1cc4 bellard2004-10-04 22:19:21 +00001605 if ((vtop->r & VT_VALMASK) == VT_CMP ||
1606 (vtop->r & (VT_VALMASK & ~1)) == VT_JMP)
1607 gv(RC_INT);
4df5bd2e bellard2003-10-14 22:15:56 +00001608 vswap();
1609 r=intr(gv(RC_INT));
1610 vswap();
1611 opc|=r;
1612 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
1613 fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
1614 c = vtop->c.i & 0x1f;
1615 o(opc|(c<<7)|(fr<<12));
1616 } else {
1617 fr=intr(gv(RC_INT));
1618 c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
1619 o(opc|(c<<12)|(fr<<8)|0x10);
1620 }
1621 vtop--;
1622 break;
1623 case 3:
1624 vpush_global_sym(&func_old_type, func);
1625 vrott(3);
1626 gfunc_call(2);
1627 vpushi(0);
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001628 vtop->r = retreg;
4df5bd2e bellard2003-10-14 22:15:56 +00001629 break;
1630 default:
bf374a5f grischka2011-08-11 17:07:56 +02001631 tcc_error("gen_opi %i unimplemented!",op);
4df5bd2e bellard2003-10-14 22:15:56 +00001632 }
1633}
1634
f99d3de2 grischka2007-12-04 20:38:09 +00001635#ifdef TCC_ARM_VFP
1636static int is_zero(int i)
1637{
1638 if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1639 return 0;
1640 if (vtop[i].type.t == VT_FLOAT)
1641 return (vtop[i].c.f == 0.f);
1642 else if (vtop[i].type.t == VT_DOUBLE)
1643 return (vtop[i].c.d == 0.0);
1644 return (vtop[i].c.ld == 0.l);
1645}
1646
1647/* generate a floating point operation 'v = t1 op t2' instruction. The
1648 * two operands are guaranted to have the same floating point type */
1649void gen_opf(int op)
1650{
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001651 uint32_t x;
f99d3de2 grischka2007-12-04 20:38:09 +00001652 int fneg=0,r;
1653 x=0xEE000A00|T2CPR(vtop->type.t);
1654 switch(op) {
1655 case '+':
1656 if(is_zero(-1))
1657 vswap();
1658 if(is_zero(0)) {
1659 vtop--;
1660 return;
1661 }
1662 x|=0x300000;
1663 break;
1664 case '-':
1665 x|=0x300040;
1666 if(is_zero(0)) {
1667 vtop--;
1668 return;
1669 }
1670 if(is_zero(-1)) {
1671 x|=0x810000; /* fsubX -> fnegX */
1672 vswap();
1673 vtop--;
1674 fneg=1;
1675 }
1676 break;
1677 case '*':
1678 x|=0x200000;
1679 break;
1680 case '/':
1681 x|=0x800000;
1682 break;
1683 default:
05b02a55 Thomas Preud'homme2012-11-23 23:45:30 +01001684 if(op < TOK_ULT || op > TOK_GT) {
bf374a5f grischka2011-08-11 17:07:56 +02001685 tcc_error("unknown fp op %x!",op);
f99d3de2 grischka2007-12-04 20:38:09 +00001686 return;
1687 }
1688 if(is_zero(-1)) {
1689 vswap();
1690 switch(op) {
1691 case TOK_LT: op=TOK_GT; break;
1692 case TOK_GE: op=TOK_ULE; break;
1693 case TOK_LE: op=TOK_GE; break;
1694 case TOK_GT: op=TOK_ULT; break;
1695 }
1696 }
1697 x|=0xB40040; /* fcmpX */
1698 if(op!=TOK_EQ && op!=TOK_NE)
1699 x|=0x80; /* fcmpX -> fcmpeX */
1700 if(is_zero(0)) {
1701 vtop--;
1702 o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */
1703 } else {
1704 x|=vfpr(gv(RC_FLOAT));
1705 vswap();
1706 o(x|(vfpr(gv(RC_FLOAT))<<12));
1707 vtop--;
1708 }
1709 o(0xEEF1FA10); /* fmstat */
1710
1711 switch(op) {
1712 case TOK_LE: op=TOK_ULE; break;
1713 case TOK_LT: op=TOK_ULT; break;
1714 case TOK_UGE: op=TOK_GE; break;
1715 case TOK_UGT: op=TOK_GT; break;
1716 }
0650ab01 Joseph Poirier2013-11-08 13:24:15 -06001717
f99d3de2 grischka2007-12-04 20:38:09 +00001718 vtop->r = VT_CMP;
1719 vtop->c.i = op;
1720 return;
1721 }
1722 r=gv(RC_FLOAT);
1723 x|=vfpr(r);
1724 r=regmask(r);
1725 if(!fneg) {
1726 int r2;
1727 vswap();
1728 r2=gv(RC_FLOAT);
1729 x|=vfpr(r2)<<16;
1730 r|=regmask(r2);
1731 }
1732 vtop->r=get_reg_ex(RC_FLOAT,r);
1733 if(!fneg)
1734 vtop--;
1735 o(x|(vfpr(vtop->r)<<12));
1736}
1737
1738#else
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001739static uint32_t is_fconst()
4df5bd2e bellard2003-10-14 22:15:56 +00001740{
1741 long double f;
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001742 uint32_t r;
4df5bd2e bellard2003-10-14 22:15:56 +00001743 if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
1744 return 0;
1745 if (vtop->type.t == VT_FLOAT)
1746 f = vtop->c.f;
1747 else if (vtop->type.t == VT_DOUBLE)
1748 f = vtop->c.d;
1749 else
1750 f = vtop->c.ld;
1751 if(!ieee_finite(f))
1752 return 0;
1753 r=0x8;
1754 if(f<0.0) {
1755 r=0x18;
1756 f=-f;
1757 }
1758 if(f==0.0)
1759 return r;
1760 if(f==1.0)
1761 return r|1;
1762 if(f==2.0)
1763 return r|2;
1764 if(f==3.0)
1765 return r|3;
1766 if(f==4.0)
1767 return r|4;
1768 if(f==5.0)
1769 return r|5;
1770 if(f==0.5)
1771 return r|6;
1772 if(f==10.0)
1773 return r|7;
1774 return 0;
1775}
1776
1777/* generate a floating point operation 'v = t1 op t2' instruction. The
1778 two operands are guaranted to have the same floating point type */
1779void gen_opf(int op)
1780{
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001781 uint32_t x, r, r2, c1, c2;
4df5bd2e bellard2003-10-14 22:15:56 +00001782 //fputs("gen_opf\n",stderr);
1783 vswap();
1784 c1 = is_fconst();
1785 vswap();
1786 c2 = is_fconst();
6e5b1cc4 bellard2004-10-04 22:19:21 +00001787 x=0xEE000100;
1788#if LDOUBLE_SIZE == 8
1789 if ((vtop->type.t & VT_BTYPE) != VT_FLOAT)
1790 x|=0x80;
1791#else
1792 if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
1793 x|=0x80;
1794 else if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE)
1795 x|=0x80000;
1796#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001797 switch(op)
1798 {
1799 case '+':
1800 if(!c2) {
1801 vswap();
1802 c2=c1;
1803 }
1804 vswap();
1805 r=fpr(gv(RC_FLOAT));
1806 vswap();
1807 if(c2) {
1808 if(c2>0xf)
1809 x|=0x200000; // suf
1810 r2=c2&0xf;
1811 } else {
1812 r2=fpr(gv(RC_FLOAT));
1813 }
1814 break;
1815 case '-':
1816 if(c2) {
1817 if(c2<=0xf)
1818 x|=0x200000; // suf
1819 r2=c2&0xf;
1820 vswap();
1821 r=fpr(gv(RC_FLOAT));
1822 vswap();
1823 } else if(c1 && c1<=0xf) {
1824 x|=0x300000; // rsf
1825 r2=c1;
1826 r=fpr(gv(RC_FLOAT));
1827 vswap();
1828 } else {
1829 x|=0x200000; // suf
1830 vswap();
1831 r=fpr(gv(RC_FLOAT));
1832 vswap();
1833 r2=fpr(gv(RC_FLOAT));
1834 }
1835 break;
1836 case '*':
1837 if(!c2 || c2>0xf) {
1838 vswap();
1839 c2=c1;
1840 }
1841 vswap();
1842 r=fpr(gv(RC_FLOAT));
1843 vswap();
1844 if(c2 && c2<=0xf)
1845 r2=c2;
1846 else
1847 r2=fpr(gv(RC_FLOAT));
1848 x|=0x100000; // muf
1849 break;
1850 case '/':
1851 if(c2 && c2<=0xf) {
1852 x|=0x400000; // dvf
1853 r2=c2;
1854 vswap();
1855 r=fpr(gv(RC_FLOAT));
1856 vswap();
1857 } else if(c1 && c1<=0xf) {
1858 x|=0x500000; // rdf
1859 r2=c1;
1860 r=fpr(gv(RC_FLOAT));
1861 vswap();
1862 } else {
1863 x|=0x400000; // dvf
1864 vswap();
1865 r=fpr(gv(RC_FLOAT));
1866 vswap();
1867 r2=fpr(gv(RC_FLOAT));
0650ab01 Joseph Poirier2013-11-08 13:24:15 -06001868 }
4df5bd2e bellard2003-10-14 22:15:56 +00001869 break;
1870 default:
1871 if(op >= TOK_ULT && op <= TOK_GT) {
6e5b1cc4 bellard2004-10-04 22:19:21 +00001872 x|=0xd0f110; // cmfe
f99d3de2 grischka2007-12-04 20:38:09 +00001873/* bug (intention?) in Linux FPU emulator
1874 doesn't set carry if equal */
4df5bd2e bellard2003-10-14 22:15:56 +00001875 switch(op) {
1876 case TOK_ULT:
1877 case TOK_UGE:
1878 case TOK_ULE:
1879 case TOK_UGT:
3e9a7e9d Vincent Lefevre2014-04-07 13:31:00 +02001880 tcc_error("unsigned comparison on floats?");
4df5bd2e bellard2003-10-14 22:15:56 +00001881 break;
1882 case TOK_LT:
f99d3de2 grischka2007-12-04 20:38:09 +00001883 op=TOK_Nset;
4df5bd2e bellard2003-10-14 22:15:56 +00001884 break;
1885 case TOK_LE:
f99d3de2 grischka2007-12-04 20:38:09 +00001886 op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */
4df5bd2e bellard2003-10-14 22:15:56 +00001887 break;
6e5b1cc4 bellard2004-10-04 22:19:21 +00001888 case TOK_EQ:
1889 case TOK_NE:
1890 x&=~0x400000; // cmfe -> cmf
1891 break;
4df5bd2e bellard2003-10-14 22:15:56 +00001892 }
4df5bd2e bellard2003-10-14 22:15:56 +00001893 if(c1 && !c2) {
1894 c2=c1;
1895 vswap();
1896 switch(op) {
f99d3de2 grischka2007-12-04 20:38:09 +00001897 case TOK_Nset:
1898 op=TOK_GT;
4df5bd2e bellard2003-10-14 22:15:56 +00001899 break;
f99d3de2 grischka2007-12-04 20:38:09 +00001900 case TOK_GE:
4df5bd2e bellard2003-10-14 22:15:56 +00001901 op=TOK_ULE;
1902 break;
1903 case TOK_ULE:
f99d3de2 grischka2007-12-04 20:38:09 +00001904 op=TOK_GE;
4df5bd2e bellard2003-10-14 22:15:56 +00001905 break;
f99d3de2 grischka2007-12-04 20:38:09 +00001906 case TOK_GT:
1907 op=TOK_Nset;
4df5bd2e bellard2003-10-14 22:15:56 +00001908 break;
1909 }
1910 }
1911 vswap();
1912 r=fpr(gv(RC_FLOAT));
1913 vswap();
1914 if(c2) {
1915 if(c2>0xf)
1916 x|=0x200000;
1917 r2=c2&0xf;
1918 } else {
1919 r2=fpr(gv(RC_FLOAT));
1920 }
1921 vtop[-1].r = VT_CMP;
1922 vtop[-1].c.i = op;
1923 } else {
bf374a5f grischka2011-08-11 17:07:56 +02001924 tcc_error("unknown fp op %x!",op);
4df5bd2e bellard2003-10-14 22:15:56 +00001925 return;
1926 }
1927 }
1928 if(vtop[-1].r == VT_CMP)
1929 c1=15;
1930 else {
1931 c1=vtop->r;
1932 if(r2&0x8)
1933 c1=vtop[-1].r;
1934 vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1935 c1=fpr(vtop[-1].r);
1936 }
1937 vtop--;
1938 o(x|(r<<16)|(c1<<12)|r2);
1939}
f99d3de2 grischka2007-12-04 20:38:09 +00001940#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001941
1942/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1943 and 'long long' cases. */
88a3ccab grischka2009-12-20 01:53:49 +01001944ST_FUNC void gen_cvt_itof1(int t)
4df5bd2e bellard2003-10-14 22:15:56 +00001945{
3de023b6
DG
Daniel Glöckner2010-05-13 22:17:09 +02001946 uint32_t r, r2;
1947 int bt;
4df5bd2e bellard2003-10-14 22:15:56 +00001948 bt=vtop->type.t & VT_BTYPE;
1949 if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001950#ifndef TCC_ARM_VFP
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001951 uint32_t dsize = 0;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001952#endif
6e5b1cc4 bellard2004-10-04 22:19:21 +00001953 r=intr(gv(RC_INT));
f99d3de2 grischka2007-12-04 20:38:09 +00001954#ifdef TCC_ARM_VFP
1955 r2=vfpr(vtop->r=get_reg(RC_FLOAT));
1956 o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */
50619372 Daniel Glöckner2013-02-03 17:51:33 +01001957 r2|=r2<<12;
f99d3de2 grischka2007-12-04 20:38:09 +00001958 if(!(vtop->type.t & VT_UNSIGNED))
1959 r2|=0x80; /* fuitoX -> fsituX */
1960 o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/
1961#else
6e5b1cc4 bellard2004-10-04 22:19:21 +00001962 r2=fpr(vtop->r=get_reg(RC_FLOAT));
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02001963 if((t & VT_BTYPE) != VT_FLOAT)
1964 dsize=0x80; /* flts -> fltd */
1965 o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */
4df5bd2e bellard2003-10-14 22:15:56 +00001966 if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02001967 uint32_t off = 0;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001968 o(0xE3500000|(r<<12)); /* cmp */
4df5bd2e bellard2003-10-14 22:15:56 +00001969 r=fpr(get_reg(RC_FLOAT));
1970 if(last_itod_magic) {
1971 off=ind+8-last_itod_magic;
1972 off/=4;
1973 if(off>255)
1974 off=0;
1975 }
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001976 o(0xBD1F0100|(r<<12)|off); /* ldflts */
4df5bd2e bellard2003-10-14 22:15:56 +00001977 if(!off) {
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001978 o(0xEA000000); /* b */
4df5bd2e bellard2003-10-14 22:15:56 +00001979 last_itod_magic=ind;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001980 o(0x4F800000); /* 4294967296.0f */
4df5bd2e bellard2003-10-14 22:15:56 +00001981 }
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001982 o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */
4df5bd2e bellard2003-10-14 22:15:56 +00001983 }
f99d3de2 grischka2007-12-04 20:38:09 +00001984#endif
4df5bd2e bellard2003-10-14 22:15:56 +00001985 return;
1986 } else if(bt == VT_LLONG) {
6e5b1cc4 bellard2004-10-04 22:19:21 +00001987 int func;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001988 CType *func_type = 0;
f99d3de2 grischka2007-12-04 20:38:09 +00001989 if((t & VT_BTYPE) == VT_FLOAT) {
f99d3de2 grischka2007-12-04 20:38:09 +00001990 func_type = &func_float_type;
f99d3de2 grischka2007-12-04 20:38:09 +00001991 if(vtop->type.t & VT_UNSIGNED)
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02001992 func=TOK___floatundisf;
f99d3de2 grischka2007-12-04 20:38:09 +00001993 else
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02001994 func=TOK___floatdisf;
1995#if LDOUBLE_SIZE != 8
1996 } else if((t & VT_BTYPE) == VT_LDOUBLE) {
1997 func_type = &func_ldouble_type;
1998 if(vtop->type.t & VT_UNSIGNED)
1999 func=TOK___floatundixf;
2000 else
2001 func=TOK___floatdixf;
2002 } else if((t & VT_BTYPE) == VT_DOUBLE) {
2003#else
2004 } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) {
f99d3de2 grischka2007-12-04 20:38:09 +00002005#endif
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02002006 func_type = &func_double_type;
2007 if(vtop->type.t & VT_UNSIGNED)
2008 func=TOK___floatundidf;
2009 else
2010 func=TOK___floatdidf;
2011 }
2012 if(func_type) {
2013 vpush_global_sym(func_type, func);
2014 vswap();
2015 gfunc_call(1);
2016 vpushi(0);
2017 vtop->r=TREG_F0;
2018 return;
2019 }
4df5bd2e bellard2003-10-14 22:15:56 +00002020 }
bf374a5f grischka2011-08-11 17:07:56 +02002021 tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t);
4df5bd2e bellard2003-10-14 22:15:56 +00002022}
2023
2024/* convert fp to int 't' type */
2025void gen_cvt_ftoi(int t)
2026{
3de023b6
DG
Daniel Glöckner2010-05-13 22:17:09 +02002027 uint32_t r, r2;
2028 int u, func = 0;
4df5bd2e bellard2003-10-14 22:15:56 +00002029 u=t&VT_UNSIGNED;
2030 t&=VT_BTYPE;
6e5b1cc4 bellard2004-10-04 22:19:21 +00002031 r2=vtop->type.t & VT_BTYPE;
4df5bd2e bellard2003-10-14 22:15:56 +00002032 if(t==VT_INT) {
f99d3de2 grischka2007-12-04 20:38:09 +00002033#ifdef TCC_ARM_VFP
2034 r=vfpr(gv(RC_FLOAT));
2035 u=u?0:0x10000;
61a4fd1d Daniel Glöckner2013-02-04 09:17:01 +01002036 o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */
f99d3de2 grischka2007-12-04 20:38:09 +00002037 r2=intr(vtop->r=get_reg(RC_INT));
2038 o(0xEE100A10|(r<<16)|(r2<<12));
2039 return;
2040#else
4df5bd2e bellard2003-10-14 22:15:56 +00002041 if(u) {
6e5b1cc4 bellard2004-10-04 22:19:21 +00002042 if(r2 == VT_FLOAT)
2043 func=TOK___fixunssfsi;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02002044#if LDOUBLE_SIZE != 8
6e5b1cc4 bellard2004-10-04 22:19:21 +00002045 else if(r2 == VT_LDOUBLE)
6e5b1cc4 bellard2004-10-04 22:19:21 +00002046 func=TOK___fixunsxfsi;
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02002047 else if(r2 == VT_DOUBLE)
2048#else
2049 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
6e5b1cc4 bellard2004-10-04 22:19:21 +00002050#endif
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02002051 func=TOK___fixunsdfsi;
6e5b1cc4 bellard2004-10-04 22:19:21 +00002052 } else {
2053 r=fpr(gv(RC_FLOAT));
2054 r2=intr(vtop->r=get_reg(RC_INT));
2055 o(0xEE100170|(r2<<12)|r);
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02002056 return;
4df5bd2e bellard2003-10-14 22:15:56 +00002057 }
f99d3de2 grischka2007-12-04 20:38:09 +00002058#endif
6e5b1cc4 bellard2004-10-04 22:19:21 +00002059 } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1
2060 if(r2 == VT_FLOAT)
2061 func=TOK___fixsfdi;
12265da6 Daniel Glöckner2008-09-05 21:07:46 +02002062#if LDOUBLE_SIZE != 8
6e5b1cc4 bellard2004-10-04 22:19:21 +00002063 else if(r2 == VT_LDOUBLE)
6e5b1cc4 bellard2004-10-04 22:19:21 +00002064 func=TOK___fixxfdi;
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02002065 else if(r2 == VT_DOUBLE)
2066#else
2067 else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE)
6e5b1cc4 bellard2004-10-04 22:19:21 +00002068#endif
12265da6
DG
Daniel Glöckner2008-09-05 21:07:46 +02002069 func=TOK___fixdfdi;
2070 }
6e5b1cc4 bellard2004-10-04 22:19:21 +00002071 if(func) {
2072 vpush_global_sym(&func_old_type, func);
2073 vswap();
2074 gfunc_call(1);
2075 vpushi(0);
2076 if(t == VT_LLONG)
2077 vtop->r2 = REG_LRET;
2078 vtop->r = REG_IRET;
4df5bd2e bellard2003-10-14 22:15:56 +00002079 return;
2080 }
bf374a5f grischka2011-08-11 17:07:56 +02002081 tcc_error("unimplemented gen_cvt_ftoi!");
4df5bd2e bellard2003-10-14 22:15:56 +00002082}
2083
2084/* convert from one floating point type to another */
2085void gen_cvt_ftof(int t)
2086{
f99d3de2 grischka2007-12-04 20:38:09 +00002087#ifdef TCC_ARM_VFP
2088 if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) {
3de023b6 Daniel Glöckner2010-05-13 22:17:09 +02002089 uint32_t r = vfpr(gv(RC_FLOAT));
f99d3de2 grischka2007-12-04 20:38:09 +00002090 o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t));
2091 }
2092#else
2093 /* all we have to do on i386 and FPA ARM is to put the float in a register */
4df5bd2e bellard2003-10-14 22:15:56 +00002094 gv(RC_FLOAT);
f99d3de2 grischka2007-12-04 20:38:09 +00002095#endif
4df5bd2e bellard2003-10-14 22:15:56 +00002096}
2097
2098/* computed goto support */
2099void ggoto(void)
2100{
2101 gcall_or_jmp(1);
2102 vtop--;
2103}
2104
41b3c7a5
JL
James Lyon2013-04-27 20:39:34 +01002105/* Save the stack pointer onto the stack and return the location of its address */
2106ST_FUNC void gen_vla_sp_save(int addr) {
2107 tcc_error("variable length arrays unsupported for this target");
2108}
2109
2110/* Restore the SP from a location on the stack */
2111ST_FUNC void gen_vla_sp_restore(int addr) {
2112 tcc_error("variable length arrays unsupported for this target");
2113}
2114
2115/* Subtract from the stack pointer, and push the resulting value onto the stack */
2116ST_FUNC void gen_vla_alloc(CType *type, int align) {
2117 tcc_error("variable length arrays unsupported for this target");
2118}
2119
4df5bd2e bellard2003-10-14 22:15:56 +00002120/* end of ARM code generator */
2121/*************************************************************/
88a3ccab grischka2009-12-20 01:53:49 +01002122#endif
2123/*************************************************************/