Rev 647 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 647 | Rev 6429 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* |
1 | /* |
2 | * ARMv4 code generator for TCC |
2 | * ARMv4 code generator for TCC |
3 | * |
3 | * |
4 | * Copyright (c) 2003 Daniel Glöckner |
4 | * Copyright (c) 2003 Daniel Glöckner |
- | 5 | * Copyright (c) 2012 Thomas Preud'homme |
|
5 | * |
6 | * |
6 | * Based on i386-gen.c by Fabrice Bellard |
7 | * Based on i386-gen.c by Fabrice Bellard |
7 | * |
8 | * |
8 | * This library is free software; you can redistribute it and/or |
9 | * This library is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * modify it under the terms of the GNU Lesser General Public |
Line 18... | Line 19... | ||
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with this library; if not, write to the Free Software |
20 | * License along with this library; if not, write to the Free Software |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ |
22 | */ |
Line -... | Line 23... | ||
- | 23 | ||
- | 24 | #ifdef TARGET_DEFS_ONLY |
|
- | 25 | ||
- | 26 | #if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP) |
|
- | 27 | #error "Currently TinyCC only supports float computation with VFP instructions" |
|
- | 28 | #endif |
|
22 | 29 | ||
- | 30 | /* number of available registers */ |
|
- | 31 | #ifdef TCC_ARM_VFP |
|
- | 32 | #define NB_REGS 13 |
|
23 | /* number of available registers */ |
33 | #else |
- | 34 | #define NB_REGS 9 |
|
- | 35 | #endif |
|
- | 36 | ||
- | 37 | #ifndef TCC_ARM_VERSION |
|
- | 38 | # define TCC_ARM_VERSION 5 |
|
Line 24... | Line 39... | ||
24 | #define NB_REGS 9 |
39 | #endif |
25 | 40 | ||
26 | /* a register can belong to several classes. The classes must be |
41 | /* a register can belong to several classes. The classes must be |
27 | sorted from more general to more precise (see gv2() code which does |
42 | sorted from more general to more precise (see gv2() code which does |
Line 35... | Line 50... | ||
35 | #define RC_R12 0x0040 |
50 | #define RC_R12 0x0040 |
36 | #define RC_F0 0x0080 |
51 | #define RC_F0 0x0080 |
37 | #define RC_F1 0x0100 |
52 | #define RC_F1 0x0100 |
38 | #define RC_F2 0x0200 |
53 | #define RC_F2 0x0200 |
39 | #define RC_F3 0x0400 |
54 | #define RC_F3 0x0400 |
- | 55 | #ifdef TCC_ARM_VFP |
|
- | 56 | #define RC_F4 0x0800 |
|
- | 57 | #define RC_F5 0x1000 |
|
- | 58 | #define RC_F6 0x2000 |
|
- | 59 | #define RC_F7 0x4000 |
|
- | 60 | #endif |
|
40 | #define RC_IRET RC_R0 /* function return: integer register */ |
61 | #define RC_IRET RC_R0 /* function return: integer register */ |
41 | #define RC_LRET RC_R1 /* function return: second integer register */ |
62 | #define RC_LRET RC_R1 /* function return: second integer register */ |
42 | #define RC_FRET RC_F0 /* function return: float register */ |
63 | #define RC_FRET RC_F0 /* function return: float register */ |
Line 43... | Line 64... | ||
43 | 64 | ||
Line 50... | Line 71... | ||
50 | TREG_R12, |
71 | TREG_R12, |
51 | TREG_F0, |
72 | TREG_F0, |
52 | TREG_F1, |
73 | TREG_F1, |
53 | TREG_F2, |
74 | TREG_F2, |
54 | TREG_F3, |
75 | TREG_F3, |
- | 76 | #ifdef TCC_ARM_VFP |
|
- | 77 | TREG_F4, |
|
- | 78 | TREG_F5, |
|
- | 79 | TREG_F6, |
|
- | 80 | TREG_F7, |
|
- | 81 | #endif |
|
55 | }; |
82 | }; |
Line 56... | Line -... | ||
56 | - | ||
57 | int reg_classes[NB_REGS] = { |
- | |
58 | /* r0 */ RC_INT | RC_R0, |
- | |
59 | /* r1 */ RC_INT | RC_R1, |
- | |
60 | /* r2 */ RC_INT | RC_R2, |
- | |
61 | /* r3 */ RC_INT | RC_R3, |
- | |
62 | /* r12 */ RC_INT | RC_R12, |
83 | |
63 | /* f0 */ RC_FLOAT | RC_F0, |
- | |
64 | /* f1 */ RC_FLOAT | RC_F1, |
- | |
65 | /* f2 */ RC_FLOAT | RC_F2, |
84 | #ifdef TCC_ARM_VFP |
66 | /* f3 */ RC_FLOAT | RC_F3, |
85 | #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) |
67 | }; |
- | |
68 | - | ||
69 | static int two2mask(int a,int b) { |
- | |
70 | return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); |
- | |
71 | } |
- | |
72 | - | ||
73 | static int regmask(int r) { |
- | |
74 | return reg_classes[r]&~(RC_INT|RC_FLOAT); |
- | |
Line 75... | Line 86... | ||
75 | } |
86 | #endif |
76 | 87 | ||
77 | /* return registers for function */ |
88 | /* return registers for function */ |
78 | #define REG_IRET TREG_R0 /* single word int return register */ |
89 | #define REG_IRET TREG_R0 /* single word int return register */ |
Line -... | Line 90... | ||
- | 90 | #define REG_LRET TREG_R1 /* second word return register (for long long) */ |
|
- | 91 | #define REG_FRET TREG_F0 /* float return register */ |
|
- | 92 | ||
- | 93 | #ifdef TCC_ARM_EABI |
|
- | 94 | #define TOK___divdi3 TOK___aeabi_ldivmod |
|
- | 95 | #define TOK___moddi3 TOK___aeabi_ldivmod |
|
- | 96 | #define TOK___udivdi3 TOK___aeabi_uldivmod |
|
79 | #define REG_LRET TREG_R1 /* second word return register (for long long) */ |
97 | #define TOK___umoddi3 TOK___aeabi_uldivmod |
80 | #define REG_FRET TREG_F0 /* float return register */ |
98 | #endif |
Line 81... | Line 99... | ||
81 | 99 | ||
82 | /* defined if function parameters must be evaluated in reverse order */ |
100 | /* defined if function parameters must be evaluated in reverse order */ |
83 | #define INVERT_FUNC_PARAMS |
101 | #define INVERT_FUNC_PARAMS |
Line 84... | Line 102... | ||
84 | 102 | ||
85 | /* defined if structures are passed as pointers. Otherwise structures |
103 | /* defined if structures are passed as pointers. Otherwise structures |
Line 86... | Line 104... | ||
86 | are directly pushed on stack. */ |
104 | are directly pushed on stack. */ |
- | 105 | /* #define FUNC_STRUCT_PARAM_AS_PTR */ |
|
- | 106 | ||
- | 107 | /* pointer size, in bytes */ |
|
- | 108 | #define PTR_SIZE 4 |
|
- | 109 | ||
87 | //#define FUNC_STRUCT_PARAM_AS_PTR |
110 | /* long double size and alignment, in bytes */ |
- | 111 | #ifdef TCC_ARM_VFP |
|
- | 112 | #define LDOUBLE_SIZE 8 |
|
- | 113 | #endif |
|
- | 114 | ||
- | 115 | #ifndef LDOUBLE_SIZE |
|
88 | 116 | #define LDOUBLE_SIZE 8 |
|
- | 117 | #endif |
|
- | 118 | ||
89 | /* pointer size, in bytes */ |
119 | #ifdef TCC_ARM_EABI |
90 | #define PTR_SIZE 4 |
120 | #define LDOUBLE_ALIGN 8 |
Line 91... | Line 121... | ||
91 | 121 | #else |
|
Line 102... | Line 132... | ||
102 | 132 | ||
Line 103... | Line 133... | ||
103 | #define EM_TCC_TARGET EM_ARM |
133 | #define EM_TCC_TARGET EM_ARM |
104 | 134 | ||
- | 135 | /* relocation type for 32 bit data relocation */ |
|
105 | /* relocation type for 32 bit data relocation */ |
136 | #define R_DATA_32 R_ARM_ABS32 |
106 | #define R_DATA_32 R_ARM_ABS32 |
137 | #define R_DATA_PTR R_ARM_ABS32 |
Line 107... | Line 138... | ||
107 | #define R_JMP_SLOT R_ARM_JUMP_SLOT |
138 | #define R_JMP_SLOT R_ARM_JUMP_SLOT |
108 | #define R_COPY R_ARM_COPY |
139 | #define R_COPY R_ARM_COPY |
Line -... | Line 140... | ||
- | 140 | ||
- | 141 | #define ELF_START_ADDR 0x00008000 |
|
- | 142 | #define ELF_PAGE_SIZE 0x1000 |
|
- | 143 | ||
- | 144 | enum float_abi { |
|
- | 145 | ARM_SOFTFP_FLOAT, |
|
- | 146 | ARM_HARD_FLOAT, |
|
109 | 147 | }; |
|
- | 148 | ||
- | 149 | /******************************************************/ |
|
110 | #define ELF_START_ADDR 0x00008000 |
150 | #else /* ! TARGET_DEFS_ONLY */ |
Line -... | Line 151... | ||
- | 151 | /******************************************************/ |
|
- | 152 | #include "tcc.h" |
|
- | 153 | ||
- | 154 | enum float_abi float_abi; |
|
- | 155 | ||
- | 156 | ST_DATA const int reg_classes[NB_REGS] = { |
|
- | 157 | /* r0 */ RC_INT | RC_R0, |
|
- | 158 | /* r1 */ RC_INT | RC_R1, |
|
- | 159 | /* r2 */ RC_INT | RC_R2, |
|
- | 160 | /* r3 */ RC_INT | RC_R3, |
|
- | 161 | /* r12 */ RC_INT | RC_R12, |
|
- | 162 | /* f0 */ RC_FLOAT | RC_F0, |
|
- | 163 | /* f1 */ RC_FLOAT | RC_F1, |
|
- | 164 | /* f2 */ RC_FLOAT | RC_F2, |
|
- | 165 | /* f3 */ RC_FLOAT | RC_F3, |
|
- | 166 | #ifdef TCC_ARM_VFP |
|
- | 167 | /* d4/s8 */ RC_FLOAT | RC_F4, |
|
- | 168 | /* d5/s10 */ RC_FLOAT | RC_F5, |
|
- | 169 | /* d6/s12 */ RC_FLOAT | RC_F6, |
|
- | 170 | /* d7/s14 */ RC_FLOAT | RC_F7, |
|
- | 171 | #endif |
|
- | 172 | }; |
|
- | 173 | ||
- | 174 | static int func_sub_sp_offset, last_itod_magic; |
|
- | 175 | static int leaffunc; |
|
- | 176 | ||
- | 177 | #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
|
- | 178 | static CType float_type, double_type, func_float_type, func_double_type; |
|
- | 179 | ST_FUNC void arm_init(struct TCCState *s) |
|
- | 180 | { |
|
- | 181 | float_type.t = VT_FLOAT; |
|
- | 182 | double_type.t = VT_DOUBLE; |
|
- | 183 | func_float_type.t = VT_FUNC; |
|
- | 184 | func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); |
|
- | 185 | func_double_type.t = VT_FUNC; |
|
- | 186 | func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); |
|
- | 187 | ||
- | 188 | float_abi = s->float_abi; |
|
- | 189 | #ifndef TCC_ARM_HARDFLOAT |
|
- | 190 | tcc_warning("soft float ABI currently not supported: default to softfp"); |
|
- | 191 | #endif |
|
- | 192 | } |
|
- | 193 | #else |
|
- | 194 | #define func_float_type func_old_type |
|
- | 195 | #define func_double_type func_old_type |
|
- | 196 | #define func_ldouble_type func_old_type |
|
- | 197 | ST_FUNC void arm_init(struct TCCState *s) |
|
- | 198 | { |
|
- | 199 | #if !defined (TCC_ARM_VFP) |
|
- | 200 | tcc_warning("Support for FPA is deprecated and will be removed in next" |
|
- | 201 | " release"); |
|
- | 202 | #endif |
|
- | 203 | #if !defined (TCC_ARM_EABI) |
|
- | 204 | tcc_warning("Support for OABI is deprecated and will be removed in next" |
|
- | 205 | " release"); |
|
- | 206 | #endif |
|
- | 207 | } |
|
- | 208 | #endif |
|
- | 209 | ||
- | 210 | static int two2mask(int a,int b) { |
|
- | 211 | return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); |
|
- | 212 | } |
|
- | 213 | ||
- | 214 | static int regmask(int r) { |
|
- | 215 | return reg_classes[r]&~(RC_INT|RC_FLOAT); |
|
- | 216 | } |
|
- | 217 | ||
- | 218 | /******************************************************/ |
|
- | 219 | ||
- | 220 | #if defined(TCC_ARM_EABI) && !defined(CONFIG_TCC_ELFINTERP) |
|
- | 221 | char *default_elfinterp(struct TCCState *s) |
|
- | 222 | { |
|
- | 223 | if (s->float_abi == ARM_HARD_FLOAT) |
|
- | 224 | return "/lib/ld-linux-armhf.so.3"; |
|
111 | #define ELF_PAGE_SIZE 0x1000 |
225 | else |
112 | 226 | return "/lib/ld-linux.so.3"; |
|
113 | /******************************************************/ |
227 | } |
114 | static unsigned long func_sub_sp_offset,last_itod_magic; |
228 | #endif |
Line 115... | Line 229... | ||
115 | 229 | ||
116 | void o(unsigned long i) |
230 | void o(uint32_t i) |
117 | { |
231 | { |
118 | /* this is a good place to start adding big-endian support*/ |
232 | /* this is a good place to start adding big-endian support*/ |
119 | int ind1; |
233 | int ind1; |
120 | 234 | ||
121 | ind1 = ind + 4; |
235 | ind1 = ind + 4; |
122 | if (!cur_text_section) |
236 | if (!cur_text_section) |
Line 131... | Line 245... | ||
131 | cur_text_section->data[ind++] = i&255; |
245 | cur_text_section->data[ind++] = i&255; |
132 | i>>=8; |
246 | i>>=8; |
133 | cur_text_section->data[ind++] = i; |
247 | cur_text_section->data[ind++] = i; |
134 | } |
248 | } |
Line 135... | Line 249... | ||
135 | 249 | ||
136 | static unsigned long stuff_const(unsigned long op,unsigned long c) |
250 | static uint32_t stuff_const(uint32_t op, uint32_t c) |
137 | { |
251 | { |
138 | int try_neg=0; |
252 | int try_neg=0; |
Line 139... | Line 253... | ||
139 | unsigned long nc = 0,negop = 0; |
253 | uint32_t nc = 0, negop = 0; |
140 | 254 | ||
141 | switch(op&0x1F00000) |
255 | switch(op&0x1F00000) |
142 | { |
256 | { |
Line 168... | Line 282... | ||
168 | if(c==~0) |
282 | if(c==~0) |
169 | return (op&0xFFF0FFFF)|0x1E00000; |
283 | return (op&0xFFF0FFFF)|0x1E00000; |
170 | break; |
284 | break; |
171 | } |
285 | } |
172 | do { |
286 | do { |
173 | unsigned long m; |
287 | uint32_t m; |
174 | int i; |
288 | int i; |
175 | if(c<256) /* catch undefined <<32 */ |
289 | if(c<256) /* catch undefined <<32 */ |
176 | return op|c; |
290 | return op|c; |
177 | for(i=2;i<32;i+=2) { |
291 | for(i=2;i<32;i+=2) { |
178 | m=(0xff>>i)|(0xff<<(32-i)); |
292 | m=(0xff>>i)|(0xff<<(32-i)); |
Line 185... | Line 299... | ||
185 | return 0; |
299 | return 0; |
186 | } |
300 | } |
Line 187... | Line 301... | ||
187 | 301 | ||
188 | 302 | ||
189 | //only add,sub |
303 | //only add,sub |
190 | void stuff_const_harder(unsigned long op,unsigned long v) { |
304 | void stuff_const_harder(uint32_t op, uint32_t v) { |
191 | unsigned long x; |
305 | uint32_t x; |
192 | x=stuff_const(op,v); |
306 | x=stuff_const(op,v); |
193 | if(x) |
307 | if(x) |
194 | o(x); |
308 | o(x); |
195 | else { |
309 | else { |
196 | unsigned long a[16],nv,no,o2,n2; |
310 | uint32_t a[16], nv, no, o2, n2; |
197 | int i,j,k; |
311 | int i,j,k; |
198 | a[0]=0xff; |
312 | a[0]=0xff; |
199 | o2=(op&0xfff0ffff)|((op&0xf000)<<4);; |
313 | o2=(op&0xfff0ffff)|((op&0xf000)<<4);; |
200 | for(i=1;i<16;i++) |
314 | for(i=1;i<16;i++) |
201 | a[i]=(a[i-1]>>2)|(a[i-1]<<30); |
315 | a[i]=(a[i-1]>>2)|(a[i-1]<<30); |
202 | for(i=0;i<12;i++) |
316 | for(i=0;i<12;i++) |
203 | for(j=i+4;i<13+i;i++) |
317 | for(j=i<4?i+12:15;j>=i+4;j--) |
204 | if((v&(a[i]|a[j]))==v) { |
318 | if((v&(a[i]|a[j]))==v) { |
205 | o(stuff_const(op,v&a[i])); |
319 | o(stuff_const(op,v&a[i])); |
206 | o(stuff_const(o2,v&a[j])); |
320 | o(stuff_const(o2,v&a[j])); |
207 | return; |
321 | return; |
208 | } |
322 | } |
209 | no=op^0xC00000; |
323 | no=op^0xC00000; |
210 | n2=o2^0xC00000; |
324 | n2=o2^0xC00000; |
211 | nv=-v; |
325 | nv=-v; |
212 | for(i=0;i<12;i++) |
326 | for(i=0;i<12;i++) |
213 | for(j=i+4;i<13+i;i++) |
327 | for(j=i<4?i+12:15;j>=i+4;j--) |
214 | if((nv&(a[i]|a[j]))==nv) { |
328 | if((nv&(a[i]|a[j]))==nv) { |
215 | o(stuff_const(no,nv&a[i])); |
329 | o(stuff_const(no,nv&a[i])); |
216 | o(stuff_const(n2,nv&a[j])); |
330 | o(stuff_const(n2,nv&a[j])); |
217 | return; |
331 | return; |
218 | } |
332 | } |
219 | for(i=0;i<8;i++) |
333 | for(i=0;i<8;i++) |
220 | for(j=i+4;i<12;i++) |
334 | for(j=i+4;j<12;j++) |
221 | for(k=j+4;k<13+i;i++) |
335 | for(k=i<4?i+12:15;k>=j+4;k--) |
222 | if((v&(a[i]|a[j]|a[k]))==v) { |
336 | if((v&(a[i]|a[j]|a[k]))==v) { |
223 | o(stuff_const(op,v&a[i])); |
337 | o(stuff_const(op,v&a[i])); |
224 | o(stuff_const(o2,v&a[j])); |
338 | o(stuff_const(o2,v&a[j])); |
225 | o(stuff_const(o2,v&a[k])); |
339 | o(stuff_const(o2,v&a[k])); |
226 | return; |
340 | return; |
227 | } |
341 | } |
228 | no=op^0xC00000; |
342 | no=op^0xC00000; |
229 | nv=-v; |
343 | nv=-v; |
230 | for(i=0;i<8;i++) |
344 | for(i=0;i<8;i++) |
231 | for(j=i+4;i<12;i++) |
345 | for(j=i+4;j<12;j++) |
232 | for(k=j+4;k<13+i;i++) |
346 | for(k=i<4?i+12:15;k>=j+4;k--) |
233 | if((nv&(a[i]|a[j]|a[k]))==nv) { |
347 | if((nv&(a[i]|a[j]|a[k]))==nv) { |
234 | o(stuff_const(no,nv&a[i])); |
348 | o(stuff_const(no,nv&a[i])); |
235 | o(stuff_const(n2,nv&a[j])); |
349 | o(stuff_const(n2,nv&a[j])); |
Line 241... | Line 355... | ||
241 | o(stuff_const(o2,v&a[8])); |
355 | o(stuff_const(o2,v&a[8])); |
242 | o(stuff_const(o2,v&a[12])); |
356 | o(stuff_const(o2,v&a[12])); |
243 | } |
357 | } |
244 | } |
358 | } |
Line 245... | Line 359... | ||
245 | 359 | ||
246 | unsigned long encbranch(int pos,int addr,int fail) |
360 | ST_FUNC uint32_t encbranch(int pos, int addr, int fail) |
247 | { |
361 | { |
248 | addr-=pos+8; |
362 | addr-=pos+8; |
249 | addr/=4; |
363 | addr/=4; |
250 | if(addr>=0x1000000 || addr<-0x1000000) { |
364 | if(addr>=0x1000000 || addr<-0x1000000) { |
251 | if(fail) |
365 | if(fail) |
252 | error("FIXME: function bigger than 32MB"); |
366 | tcc_error("FIXME: function bigger than 32MB"); |
253 | return 0; |
367 | return 0; |
254 | } |
368 | } |
255 | return 0x0A000000|(addr&0xffffff); |
369 | return 0x0A000000|(addr&0xffffff); |
Line 256... | Line 370... | ||
256 | } |
370 | } |
257 | 371 | ||
258 | int decbranch(int pos) |
372 | int decbranch(int pos) |
259 | { |
373 | { |
260 | int x; |
374 | int x; |
261 | x=*(int *)(cur_text_section->data + pos); |
375 | x=*(uint32_t *)(cur_text_section->data + pos); |
262 | x&=0x00ffffff; |
376 | x&=0x00ffffff; |
263 | if(x&0x800000) |
377 | if(x&0x800000) |
264 | x-=0x1000000; |
378 | x-=0x1000000; |
Line 265... | Line 379... | ||
265 | return x*4+pos+8; |
379 | return x*4+pos+8; |
266 | } |
380 | } |
267 | 381 | ||
268 | /* output a symbol and patch all calls to it */ |
382 | /* output a symbol and patch all calls to it */ |
269 | void gsym_addr(int t, int a) |
383 | void gsym_addr(int t, int a) |
270 | { |
384 | { |
271 | unsigned long *x; |
385 | uint32_t *x; |
272 | int lt; |
386 | int lt; |
273 | while(t) { |
387 | while(t) { |
274 | x=(unsigned long *)(cur_text_section->data + t); |
388 | x=(uint32_t *)(cur_text_section->data + t); |
275 | t=decbranch(lt=t); |
389 | t=decbranch(lt=t); |
276 | if(a==lt+4) |
390 | if(a==lt+4) |
Line 285... | Line 399... | ||
285 | void gsym(int t) |
399 | void gsym(int t) |
286 | { |
400 | { |
287 | gsym_addr(t, ind); |
401 | gsym_addr(t, ind); |
288 | } |
402 | } |
Line -... | Line 403... | ||
- | 403 | ||
- | 404 | #ifdef TCC_ARM_VFP |
|
- | 405 | static uint32_t vfpr(int r) |
|
- | 406 | { |
|
- | 407 | if(r |
|
- | 408 | tcc_error("compiler error! register %i is no vfp register",r); |
|
- | 409 | return r-5; |
|
- | 410 | } |
|
289 | 411 | #else |
|
290 | static unsigned long fpr(int r) |
412 | static uint32_t fpr(int r) |
291 | { |
413 | { |
292 | if(r |
414 | if(r |
293 | error("compiler error! register %i is no fp register\n",r); |
415 | tcc_error("compiler error! register %i is no fpa register",r); |
294 | return r-5; |
416 | return r-5; |
- | 417 | } |
|
Line 295... | Line 418... | ||
295 | } |
418 | #endif |
296 | 419 | ||
297 | static unsigned long intr(int r) |
420 | static uint32_t intr(int r) |
298 | { |
421 | { |
299 | if(r==4) |
422 | if(r==4) |
300 | return 12; |
423 | return 12; |
301 | if((r<0 || r>4) && r!=14) |
424 | if((r<0 || r>4) && r!=14) |
302 | error("compiler error! register %i is no int register\n",r); |
425 | tcc_error("compiler error! register %i is no int register",r); |
Line 303... | Line 426... | ||
303 | return r; |
426 | return r; |
304 | } |
427 | } |
305 | 428 | ||
306 | static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift) |
429 | static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift) |
307 | { |
430 | { |
308 | if(*off>maxoff || *off&((1< |
431 | if(*off>maxoff || *off&((1< |
309 | unsigned long x,y; |
432 | uint32_t x, y; |
310 | x=0xE280E000; |
433 | x=0xE280E000; |
311 | if(*sgn) |
434 | if(*sgn) |
Line 328... | Line 451... | ||
328 | stuff_const_harder(x,*off&~maxoff); |
451 | stuff_const_harder(x,*off&~maxoff); |
329 | *off&=maxoff; |
452 | *off&=maxoff; |
330 | } |
453 | } |
331 | } |
454 | } |
Line 332... | Line 455... | ||
332 | 455 | ||
333 | static unsigned long mapcc(int cc) |
456 | static uint32_t mapcc(int cc) |
334 | { |
457 | { |
335 | switch(cc) |
458 | switch(cc) |
336 | { |
459 | { |
337 | case TOK_ULT: |
460 | case TOK_ULT: |
338 | return 0x30000000; |
461 | return 0x30000000; /* CC/LO */ |
339 | case TOK_UGE: |
462 | case TOK_UGE: |
340 | return 0x20000000; |
463 | return 0x20000000; /* CS/HS */ |
341 | case TOK_EQ: |
464 | case TOK_EQ: |
342 | return 0x00000000; |
465 | return 0x00000000; /* EQ */ |
343 | case TOK_NE: |
466 | case TOK_NE: |
344 | return 0x10000000; |
467 | return 0x10000000; /* NE */ |
345 | case TOK_ULE: |
468 | case TOK_ULE: |
346 | return 0x90000000; |
469 | return 0x90000000; /* LS */ |
347 | case TOK_UGT: |
470 | case TOK_UGT: |
- | 471 | return 0x80000000; /* HI */ |
|
- | 472 | case TOK_Nset: |
|
- | 473 | return 0x40000000; /* MI */ |
|
- | 474 | case TOK_Nclear: |
|
348 | return 0x80000000; |
475 | return 0x50000000; /* PL */ |
349 | case TOK_LT: |
476 | case TOK_LT: |
350 | return 0xB0000000; |
477 | return 0xB0000000; /* LT */ |
351 | case TOK_GE: |
478 | case TOK_GE: |
352 | return 0xA0000000; |
479 | return 0xA0000000; /* GE */ |
353 | case TOK_LE: |
480 | case TOK_LE: |
354 | return 0xD0000000; |
481 | return 0xD0000000; /* LE */ |
355 | case TOK_GT: |
482 | case TOK_GT: |
356 | return 0xC0000000; |
483 | return 0xC0000000; /* GT */ |
357 | } |
484 | } |
358 | error("unexpected condition code"); |
485 | tcc_error("unexpected condition code"); |
359 | return 0xE0000000; |
486 | return 0xE0000000; /* AL */ |
Line 360... | Line 487... | ||
360 | } |
487 | } |
361 | 488 | ||
362 | static int negcc(int cc) |
489 | static int negcc(int cc) |
Line 373... | Line 500... | ||
373 | return TOK_EQ; |
500 | return TOK_EQ; |
374 | case TOK_ULE: |
501 | case TOK_ULE: |
375 | return TOK_UGT; |
502 | return TOK_UGT; |
376 | case TOK_UGT: |
503 | case TOK_UGT: |
377 | return TOK_ULE; |
504 | return TOK_ULE; |
- | 505 | case TOK_Nset: |
|
- | 506 | return TOK_Nclear; |
|
- | 507 | case TOK_Nclear: |
|
- | 508 | return TOK_Nset; |
|
378 | case TOK_LT: |
509 | case TOK_LT: |
379 | return TOK_GE; |
510 | return TOK_GE; |
380 | case TOK_GE: |
511 | case TOK_GE: |
381 | return TOK_LT; |
512 | return TOK_LT; |
382 | case TOK_LE: |
513 | case TOK_LE: |
383 | return TOK_GT; |
514 | return TOK_GT; |
384 | case TOK_GT: |
515 | case TOK_GT: |
385 | return TOK_LE; |
516 | return TOK_LE; |
386 | } |
517 | } |
387 | error("unexpected condition code"); |
518 | tcc_error("unexpected condition code"); |
388 | return TOK_NE; |
519 | return TOK_NE; |
389 | } |
520 | } |
Line 390... | Line 521... | ||
390 | 521 | ||
391 | /* load 'r' from value 'sv' */ |
522 | /* load 'r' from value 'sv' */ |
392 | void load(int r, SValue *sv) |
523 | void load(int r, SValue *sv) |
393 | { |
524 | { |
394 | int v, ft, fc, fr, sign; |
525 | int v, ft, fc, fr, sign; |
395 | unsigned long op; |
526 | uint32_t op; |
Line 396... | Line 527... | ||
396 | SValue v1; |
527 | SValue v1; |
397 | 528 | ||
398 | fr = sv->r; |
529 | fr = sv->r; |
Line 399... | Line 530... | ||
399 | ft = sv->type.t; |
530 | ft = sv->type.t; |
400 | fc = sv->c.ul; |
531 | fc = sv->c.i; |
401 | 532 | ||
402 | if(fc>=0) |
533 | if(fc>=0) |
403 | sign=0; |
534 | sign=0; |
404 | else { |
535 | else { |
Line 405... | Line 536... | ||
405 | sign=1; |
536 | sign=1; |
406 | fc=-fc; |
537 | fc=-fc; |
407 | } |
538 | } |
408 | 539 | ||
409 | v = fr & VT_VALMASK; |
540 | v = fr & VT_VALMASK; |
410 | if (fr & VT_LVAL) { |
541 | if (fr & VT_LVAL) { |
411 | unsigned long base=0xB; // fp |
542 | uint32_t base = 0xB; // fp |
412 | if(v == VT_LLOCAL) { |
543 | if(v == VT_LLOCAL) { |
413 | v1.type.t = VT_PTR; |
544 | v1.type.t = VT_PTR; |
414 | v1.r = VT_LOCAL | VT_LVAL; |
545 | v1.r = VT_LOCAL | VT_LVAL; |
415 | v1.c.ul = sv->c.ul; |
546 | v1.c.i = sv->c.i; |
416 | load(base=14 /* lr */, &v1); |
547 | load(base=14 /* lr */, &v1); |
417 | fc=sign=0; |
548 | fc=sign=0; |
418 | v=VT_LOCAL; |
549 | v=VT_LOCAL; |
419 | } else if(v == VT_CONST) { |
550 | } else if(v == VT_CONST) { |
420 | v1.type.t = VT_PTR; |
551 | v1.type.t = VT_PTR; |
421 | v1.r = fr&~VT_LVAL; |
552 | v1.r = fr&~VT_LVAL; |
422 | v1.c.ul = sv->c.ul; |
553 | v1.c.i = sv->c.i; |
423 | v1.sym=sv->sym; |
554 | v1.sym=sv->sym; |
Line 430... | Line 561... | ||
430 | v=VT_LOCAL; |
561 | v=VT_LOCAL; |
431 | } |
562 | } |
432 | if(v == VT_LOCAL) { |
563 | if(v == VT_LOCAL) { |
433 | if(is_float(ft)) { |
564 | if(is_float(ft)) { |
434 | calcaddr(&base,&fc,&sign,1020,2); |
565 | calcaddr(&base,&fc,&sign,1020,2); |
- | 566 | #ifdef TCC_ARM_VFP |
|
- | 567 | op=0xED100A00; /* flds */ |
|
- | 568 | if(!sign) |
|
- | 569 | op|=0x800000; |
|
- | 570 | if ((ft & VT_BTYPE) != VT_FLOAT) |
|
- | 571 | op|=0x100; /* flds -> fldd */ |
|
- | 572 | o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
|
- | 573 | #else |
|
435 | op=0xED100100; |
574 | op=0xED100100; |
436 | if(!sign) |
575 | if(!sign) |
437 | op|=0x800000; |
576 | op|=0x800000; |
438 | #if LDOUBLE_SIZE == 8 |
577 | #if LDOUBLE_SIZE == 8 |
439 | if ((ft & VT_BTYPE) != VT_FLOAT) |
578 | if ((ft & VT_BTYPE) != VT_FLOAT) |
Line 443... | Line 582... | ||
443 | op|=0x8000; |
582 | op|=0x8000; |
444 | else if ((ft & VT_BTYPE) == VT_LDOUBLE) |
583 | else if ((ft & VT_BTYPE) == VT_LDOUBLE) |
445 | op|=0x400000; |
584 | op|=0x400000; |
446 | #endif |
585 | #endif |
447 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
586 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
- | 587 | #endif |
|
- | 588 | } else if((ft & (VT_BTYPE|VT_UNSIGNED)) == VT_BYTE |
|
448 | } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) { |
589 | || (ft & VT_BTYPE) == VT_SHORT) { |
449 | calcaddr(&base,&fc,&sign,255,0); |
590 | calcaddr(&base,&fc,&sign,255,0); |
450 | op=0xE1500090; |
591 | op=0xE1500090; |
451 | if ((ft & VT_BTYPE) == VT_SHORT) |
592 | if ((ft & VT_BTYPE) == VT_SHORT) |
452 | op|=0x20; |
593 | op|=0x20; |
453 | if ((ft & VT_UNSIGNED) == 0) |
594 | if ((ft & VT_UNSIGNED) == 0) |
Line 458... | Line 599... | ||
458 | } else { |
599 | } else { |
459 | calcaddr(&base,&fc,&sign,4095,0); |
600 | calcaddr(&base,&fc,&sign,4095,0); |
460 | op=0xE5100000; |
601 | op=0xE5100000; |
461 | if(!sign) |
602 | if(!sign) |
462 | op|=0x800000; |
603 | op|=0x800000; |
463 | if ((ft & VT_BTYPE) == VT_BYTE) |
604 | if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) |
464 | op|=0x400000; |
605 | op|=0x400000; |
465 | o(op|(intr(r)<<12)|fc|(base<<16)); |
606 | o(op|(intr(r)<<12)|fc|(base<<16)); |
466 | } |
607 | } |
467 | return; |
608 | return; |
468 | } |
609 | } |
469 | } else { |
610 | } else { |
470 | if (v == VT_CONST) { |
611 | if (v == VT_CONST) { |
471 | op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul); |
612 | op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.i); |
472 | if (fr & VT_SYM || !op) { |
613 | if (fr & VT_SYM || !op) { |
473 | o(0xE59F0000|(intr(r)<<12)); |
614 | o(0xE59F0000|(intr(r)<<12)); |
474 | o(0xEA000000); |
615 | o(0xEA000000); |
475 | if(fr & VT_SYM) |
616 | if(fr & VT_SYM) |
476 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
617 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
477 | o(sv->c.ul); |
618 | o(sv->c.i); |
478 | } else |
619 | } else |
479 | o(op); |
620 | o(op); |
480 | return; |
621 | return; |
481 | } else if (v == VT_LOCAL) { |
622 | } else if (v == VT_LOCAL) { |
482 | op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul); |
623 | op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.i); |
483 | if (fr & VT_SYM || !op) { |
624 | if (fr & VT_SYM || !op) { |
484 | o(0xE59F0000|(intr(r)<<12)); |
625 | o(0xE59F0000|(intr(r)<<12)); |
485 | o(0xEA000000); |
626 | o(0xEA000000); |
486 | if(fr & VT_SYM) // needed ? |
627 | if(fr & VT_SYM) // needed ? |
487 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
628 | greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); |
488 | o(sv->c.ul); |
629 | o(sv->c.i); |
489 | o(0xE08B0000|(intr(r)<<12)|intr(r)); |
630 | o(0xE08B0000|(intr(r)<<12)|intr(r)); |
490 | } else |
631 | } else |
491 | o(op); |
632 | o(op); |
492 | return; |
633 | return; |
493 | } else if(v == VT_CMP) { |
634 | } else if(v == VT_CMP) { |
494 | o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12)); |
635 | o(mapcc(sv->c.i)|0x3A00001|(intr(r)<<12)); |
495 | o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12)); |
636 | o(mapcc(negcc(sv->c.i))|0x3A00000|(intr(r)<<12)); |
496 | return; |
637 | return; |
497 | } else if (v == VT_JMP || v == VT_JMPI) { |
638 | } else if (v == VT_JMP || v == VT_JMPI) { |
498 | int t; |
639 | int t; |
499 | t = v & 1; |
640 | t = v & 1; |
500 | o(0xE3A00000|(intr(r)<<12)|t); |
641 | o(0xE3A00000|(intr(r)<<12)|t); |
501 | o(0xEA000000); |
642 | o(0xEA000000); |
502 | gsym(sv->c.ul); |
643 | gsym(sv->c.i); |
503 | o(0xE3A00000|(intr(r)<<12)|(t^1)); |
644 | o(0xE3A00000|(intr(r)<<12)|(t^1)); |
504 | return; |
645 | return; |
505 | } else if (v < VT_CONST) { |
646 | } else if (v < VT_CONST) { |
506 | if(is_float(ft)) |
647 | if(is_float(ft)) |
- | 648 | #ifdef TCC_ARM_VFP |
|
- | 649 | o(0xEEB00A40|(vfpr(r)<<12)|vfpr(v)|T2CPR(ft)); /* fcpyX */ |
|
- | 650 | #else |
|
507 | o(0xEE008180|(fpr(r)<<12)|fpr(v)); |
651 | o(0xEE008180|(fpr(r)<<12)|fpr(v)); |
- | 652 | #endif |
|
508 | else |
653 | else |
509 | o(0xE1A00000|(intr(r)<<12)|intr(v)); |
654 | o(0xE1A00000|(intr(r)<<12)|intr(v)); |
510 | return; |
655 | return; |
511 | } |
656 | } |
512 | } |
657 | } |
513 | error("load unimplemented!"); |
658 | tcc_error("load unimplemented!"); |
514 | } |
659 | } |
Line 515... | Line 660... | ||
515 | 660 | ||
516 | /* store register 'r' in lvalue 'v' */ |
661 | /* store register 'r' in lvalue 'v' */ |
517 | void store(int r, SValue *sv) |
662 | void store(int r, SValue *sv) |
518 | { |
663 | { |
519 | SValue v1; |
664 | SValue v1; |
520 | int v, ft, fc, fr, sign; |
665 | int v, ft, fc, fr, sign; |
Line 521... | Line 666... | ||
521 | unsigned long op; |
666 | uint32_t op; |
522 | 667 | ||
523 | fr = sv->r; |
668 | fr = sv->r; |
Line 524... | Line 669... | ||
524 | ft = sv->type.t; |
669 | ft = sv->type.t; |
525 | fc = sv->c.ul; |
670 | fc = sv->c.i; |
526 | 671 | ||
527 | if(fc>=0) |
672 | if(fc>=0) |
528 | sign=0; |
673 | sign=0; |
529 | else { |
674 | else { |
Line 530... | Line 675... | ||
530 | sign=1; |
675 | sign=1; |
531 | fc=-fc; |
676 | fc=-fc; |
532 | } |
677 | } |
533 | 678 | ||
534 | v = fr & VT_VALMASK; |
679 | v = fr & VT_VALMASK; |
535 | if (fr & VT_LVAL || fr == VT_LOCAL) { |
680 | if (fr & VT_LVAL || fr == VT_LOCAL) { |
536 | unsigned long base=0xb; |
681 | uint32_t base = 0xb; |
537 | if(v < VT_CONST) { |
682 | if(v < VT_CONST) { |
538 | base=intr(v); |
683 | base=intr(v); |
539 | v=VT_LOCAL; |
684 | v=VT_LOCAL; |
540 | fc=sign=0; |
685 | fc=sign=0; |
541 | } else if(v == VT_CONST) { |
686 | } else if(v == VT_CONST) { |
542 | v1.type.t = ft; |
687 | v1.type.t = ft; |
543 | v1.r = fr&~VT_LVAL; |
688 | v1.r = fr&~VT_LVAL; |
544 | v1.c.ul = sv->c.ul; |
689 | v1.c.i = sv->c.i; |
545 | v1.sym=sv->sym; |
690 | v1.sym=sv->sym; |
546 | load(base=14, &v1); |
691 | load(base=14, &v1); |
547 | fc=sign=0; |
692 | fc=sign=0; |
548 | v=VT_LOCAL; |
693 | v=VT_LOCAL; |
- | 694 | } |
|
- | 695 | if(v == VT_LOCAL) { |
|
- | 696 | if(is_float(ft)) { |
|
- | 697 | calcaddr(&base,&fc,&sign,1020,2); |
|
- | 698 | #ifdef TCC_ARM_VFP |
|
- | 699 | op=0xED000A00; /* fsts */ |
|
- | 700 | if(!sign) |
|
- | 701 | op|=0x800000; |
|
549 | } |
702 | if ((ft & VT_BTYPE) != VT_FLOAT) |
550 | if(v == VT_LOCAL) { |
703 | op|=0x100; /* fsts -> fstd */ |
551 | if(is_float(ft)) { |
704 | o(op|(vfpr(r)<<12)|(fc>>2)|(base<<16)); |
552 | calcaddr(&base,&fc,&sign,1020,2); |
705 | #else |
553 | op=0xED000100; |
706 | op=0xED000100; |
Line 561... | Line 714... | ||
561 | op|=0x8000; |
714 | op|=0x8000; |
562 | if ((ft & VT_BTYPE) == VT_LDOUBLE) |
715 | if ((ft & VT_BTYPE) == VT_LDOUBLE) |
563 | op|=0x400000; |
716 | op|=0x400000; |
564 | #endif |
717 | #endif |
565 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
718 | o(op|(fpr(r)<<12)|(fc>>2)|(base<<16)); |
- | 719 | #endif |
|
566 | return; |
720 | return; |
567 | } else if((ft & VT_BTYPE) == VT_SHORT) { |
721 | } else if((ft & VT_BTYPE) == VT_SHORT) { |
568 | calcaddr(&base,&fc,&sign,255,0); |
722 | calcaddr(&base,&fc,&sign,255,0); |
569 | op=0xE14000B0; |
723 | op=0xE14000B0; |
570 | if(!sign) |
724 | if(!sign) |
Line 573... | Line 727... | ||
573 | } else { |
727 | } else { |
574 | calcaddr(&base,&fc,&sign,4095,0); |
728 | calcaddr(&base,&fc,&sign,4095,0); |
575 | op=0xE5000000; |
729 | op=0xE5000000; |
576 | if(!sign) |
730 | if(!sign) |
577 | op|=0x800000; |
731 | op|=0x800000; |
578 | if ((ft & VT_BTYPE) == VT_BYTE) |
732 | if ((ft & VT_BTYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_BOOL) |
579 | op|=0x400000; |
733 | op|=0x400000; |
580 | o(op|(intr(r)<<12)|fc|(base<<16)); |
734 | o(op|(intr(r)<<12)|fc|(base<<16)); |
581 | } |
735 | } |
582 | return; |
736 | return; |
583 | } |
737 | } |
584 | } |
738 | } |
585 | error("store unimplemented"); |
739 | tcc_error("store unimplemented"); |
586 | } |
740 | } |
Line 587... | Line 741... | ||
587 | 741 | ||
588 | static void gadd_sp(int val) |
742 | static void gadd_sp(int val) |
589 | { |
743 | { |
Line 593... | Line 747... | ||
593 | /* 'is_jmp' is '1' if it is a jump */ |
747 | /* 'is_jmp' is '1' if it is a jump */ |
594 | static void gcall_or_jmp(int is_jmp) |
748 | static void gcall_or_jmp(int is_jmp) |
595 | { |
749 | { |
596 | int r; |
750 | int r; |
597 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
751 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
598 | unsigned long x; |
752 | uint32_t x; |
599 | /* constant case */ |
753 | /* constant case */ |
600 | x=encbranch(ind,ind+vtop->c.ul,0); |
754 | x=encbranch(ind,ind+vtop->c.i,0); |
601 | if(x) { |
755 | if(x) { |
602 | if (vtop->r & VT_SYM) { |
756 | if (vtop->r & VT_SYM) { |
603 | /* relocation case */ |
757 | /* relocation case */ |
604 | greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); |
758 | greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24); |
605 | } else |
759 | } else |
Line 609... | Line 763... | ||
609 | if(!is_jmp) |
763 | if(!is_jmp) |
610 | o(0xE28FE004); // add lr,pc,#4 |
764 | o(0xE28FE004); // add lr,pc,#4 |
611 | o(0xE51FF004); // ldr pc,[pc,#-4] |
765 | o(0xE51FF004); // ldr pc,[pc,#-4] |
612 | if (vtop->r & VT_SYM) |
766 | if (vtop->r & VT_SYM) |
613 | greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); |
767 | greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32); |
614 | o(vtop->c.ul); |
768 | o(vtop->c.i); |
615 | } |
769 | } |
616 | } else { |
770 | } else { |
617 | /* otherwise, indirect call */ |
771 | /* otherwise, indirect call */ |
618 | r = gv(RC_INT); |
772 | r = gv(RC_INT); |
619 | if(!is_jmp) |
773 | if(!is_jmp) |
620 | o(0xE1A0E00F); // mov lr,pc |
774 | o(0xE1A0E00F); // mov lr,pc |
621 | o(0xE1A0F000|intr(r)); // mov pc,r |
775 | o(0xE1A0F000|intr(r)); // mov pc,r |
622 | } |
776 | } |
623 | } |
777 | } |
Line -... | Line 778... | ||
- | 778 | ||
624 | 779 | /* Return whether a structure is an homogeneous float aggregate or not. |
|
- | 780 | The answer is true if all the elements of the structure are of the same |
|
- | 781 | primitive float type and there is less than 4 elements. |
|
- | 782 | ||
- | 783 | type: the type corresponding to the structure to be tested */ |
|
- | 784 | static int is_hgen_float_aggr(CType *type) |
|
- | 785 | { |
|
- | 786 | if ((type->t & VT_BTYPE) == VT_STRUCT) { |
|
- | 787 | struct Sym *ref; |
|
- | 788 | int btype, nb_fields = 0; |
|
- | 789 | ||
- | 790 | ref = type->ref->next; |
|
- | 791 | btype = ref->type.t & VT_BTYPE; |
|
- | 792 | if (btype == VT_FLOAT || btype == VT_DOUBLE) { |
|
- | 793 | for(; ref && btype == (ref->type.t & VT_BTYPE); ref = ref->next, nb_fields++); |
|
- | 794 | return !ref && nb_fields <= 4; |
|
- | 795 | } |
|
- | 796 | } |
|
- | 797 | return 0; |
|
- | 798 | } |
|
- | 799 | ||
- | 800 | struct avail_regs { |
|
- | 801 | signed char avail[3]; /* 3 holes max with only float and double alignments */ |
|
- | 802 | int first_hole; /* first available hole */ |
|
- | 803 | int last_hole; /* last available hole (none if equal to first_hole) */ |
|
- | 804 | int first_free_reg; /* next free register in the sequence, hole excluded */ |
|
- | 805 | }; |
|
- | 806 | ||
- | 807 | #define AVAIL_REGS_INITIALIZER (struct avail_regs) { { 0, 0, 0}, 0, 0, 0 } |
|
- | 808 | ||
- | 809 | /* Find suitable registers for a VFP Co-Processor Register Candidate (VFP CPRC |
|
- | 810 | param) according to the rules described in the procedure call standard for |
|
625 | /* Generate function call. The function address is pushed first, then |
811 | the ARM architecture (AAPCS). If found, the registers are assigned to this |
626 | all the parameters in call order. This functions pops all the |
812 | VFP CPRC parameter. Registers are allocated in sequence unless a hole exists |
- | 813 | and the parameter is a single float. |
|
- | 814 | ||
- | 815 | avregs: opaque structure to keep track of available VFP co-processor regs |
|
- | 816 | align: alignment contraints for the param, as returned by type_size() |
|
- | 817 | size: size of the parameter, as returned by type_size() */ |
|
- | 818 | int assign_vfpreg(struct avail_regs *avregs, int align, int size) |
|
- | 819 | { |
|
- | 820 | int first_reg = 0; |
|
- | 821 | ||
- | 822 | if (avregs->first_free_reg == -1) |
|
- | 823 | return -1; |
|
- | 824 | if (align >> 3) { /* double alignment */ |
|
- | 825 | first_reg = avregs->first_free_reg; |
|
- | 826 | /* alignment contraint not respected so use next reg and record hole */ |
|
- | 827 | if (first_reg & 1) |
|
- | 828 | avregs->avail[avregs->last_hole++] = first_reg++; |
|
- | 829 | } else { /* no special alignment (float or array of float) */ |
|
- | 830 | /* if single float and a hole is available, assign the param to it */ |
|
- | 831 | if (size == 4 && avregs->first_hole != avregs->last_hole) |
|
- | 832 | return avregs->avail[avregs->first_hole++]; |
|
- | 833 | else |
|
- | 834 | first_reg = avregs->first_free_reg; |
|
627 | parameters and the function address. */ |
835 | } |
- | 836 | if (first_reg + size / 4 <= 16) { |
|
- | 837 | avregs->first_free_reg = first_reg + size / 4; |
|
- | 838 | return first_reg; |
|
- | 839 | } |
|
- | 840 | avregs->first_free_reg = -1; |
|
- | 841 | return -1; |
|
- | 842 | } |
|
- | 843 | ||
- | 844 | /* Returns whether all params need to be passed in core registers or not. |
|
- | 845 | This is the case for function part of the runtime ABI. */ |
|
628 | void gfunc_call(int nb_args) |
846 | int floats_in_core_regs(SValue *sval) |
629 | { |
847 | { |
630 | int size, align, r, args_size, i; |
848 | if (!sval->sym) |
631 | Sym *func_sym; |
- | |
632 | signed char plan[4][2]={{-1,-1},{-1,-1},{-1,-1},{-1,-1}}; |
- | |
Line -... | Line 849... | ||
- | 849 | return 0; |
|
- | 850 | ||
- | 851 | switch (sval->sym->v) { |
|
- | 852 | case TOK___floatundisf: |
|
- | 853 | case TOK___floatundidf: |
|
- | 854 | case TOK___fixunssfdi: |
|
- | 855 | case TOK___fixunsdfdi: |
|
- | 856 | #ifndef TCC_ARM_VFP |
|
- | 857 | case TOK___fixunsxfdi: |
|
- | 858 | #endif |
|
- | 859 | case TOK___floatdisf: |
|
- | 860 | case TOK___floatdidf: |
|
- | 861 | case TOK___fixsfdi: |
|
- | 862 | case TOK___fixdfdi: |
|
- | 863 | return 1; |
|
- | 864 | ||
- | 865 | default: |
|
- | 866 | return 0; |
|
- | 867 | } |
|
- | 868 | } |
|
- | 869 | ||
- | 870 | /* Return the number of registers needed to return the struct, or 0 if |
|
- | 871 | returning via struct pointer. */ |
|
- | 872 | ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) { |
|
- | 873 | #ifdef TCC_ARM_EABI |
|
- | 874 | int size, align; |
|
- | 875 | size = type_size(vt, &align); |
|
- | 876 | if (float_abi == ARM_HARD_FLOAT && !variadic && |
|
- | 877 | (is_float(vt->t) || is_hgen_float_aggr(vt))) { |
|
- | 878 | *ret_align = 8; |
|
633 | int todo=0xf, keep, plan2[4]={0,0,0,0}; |
879 | *regsize = 8; |
- | 880 | ret->ref = NULL; |
|
- | 881 | ret->t = VT_DOUBLE; |
|
- | 882 | return (size + 7) >> 3; |
|
- | 883 | } else if (size <= 4) { |
|
- | 884 | *ret_align = 4; |
|
634 | 885 | *regsize = 4; |
|
- | 886 | ret->ref = NULL; |
|
- | 887 | ret->t = VT_INT; |
|
- | 888 | return 1; |
|
- | 889 | } else |
|
- | 890 | return 0; |
|
- | 891 | #else |
|
- | 892 | return 0; |
|
- | 893 | #endif |
|
- | 894 | } |
|
- | 895 | ||
- | 896 | /* Parameters are classified according to how they are copied to their final |
|
- | 897 | destination for the function call. Because the copying is performed class |
|
- | 898 | after class according to the order in the union below, it is important that |
|
- | 899 | some constraints about the order of the members of this union are respected: |
|
- | 900 | - CORE_STRUCT_CLASS must come after STACK_CLASS; |
|
- | 901 | - CORE_CLASS must come after STACK_CLASS, CORE_STRUCT_CLASS and |
|
- | 902 | VFP_STRUCT_CLASS; |
|
- | 903 | - VFP_STRUCT_CLASS must come after VFP_CLASS. |
|
- | 904 | See the comment for the main loop in copy_params() for the reason. */ |
|
- | 905 | enum reg_class { |
|
- | 906 | STACK_CLASS = 0, |
|
- | 907 | CORE_STRUCT_CLASS, |
|
- | 908 | VFP_CLASS, |
|
- | 909 | VFP_STRUCT_CLASS, |
|
- | 910 | CORE_CLASS, |
|
- | 911 | NB_CLASSES |
|
- | 912 | }; |
|
- | 913 | ||
- | 914 | struct param_plan { |
|
- | 915 | int start; /* first reg or addr used depending on the class */ |
|
- | 916 | int end; /* last reg used or next free addr depending on the class */ |
|
- | 917 | SValue *sval; /* pointer to SValue on the value stack */ |
|
- | 918 | struct param_plan *prev; /* previous element in this class */ |
|
- | 919 | }; |
|
- | 920 | ||
- | 921 | struct plan { |
|
- | 922 | struct param_plan *pplans; /* array of all the param plans */ |
|
- | 923 | struct param_plan *clsplans[NB_CLASSES]; /* per class lists of param plans */ |
|
- | 924 | }; |
|
- | 925 | ||
- | 926 | #define add_param_plan(plan,pplan,class) \ |
|
- | 927 | do { \ |
|
- | 928 | pplan.prev = plan->clsplans[class]; \ |
|
635 | r = vtop->r & VT_VALMASK; |
929 | plan->pplans[plan ## _nb] = pplan; \ |
- | 930 | plan->clsplans[class] = &plan->pplans[plan ## _nb++]; \ |
|
- | 931 | } while(0) |
|
- | 932 | ||
- | 933 | /* Assign parameters to registers and stack with alignment according to the |
|
- | 934 | rules in the procedure call standard for the ARM architecture (AAPCS). |
|
- | 935 | The overall assignment is recorded in an array of per parameter structures |
|
- | 936 | called parameter plans. The parameter plans are also further organized in a |
|
- | 937 | number of linked lists, one per class of parameter (see the comment for the |
|
- | 938 | definition of union reg_class). |
|
- | 939 | ||
- | 940 | nb_args: number of parameters of the function for which a call is generated |
|
- | 941 | float_abi: float ABI in use for this function call |
|
- | 942 | plan: the structure where the overall assignment is recorded |
|
- | 943 | todo: a bitmap that record which core registers hold a parameter |
|
- | 944 | ||
- | 945 | Returns the amount of stack space needed for parameter passing |
|
- | 946 | ||
- | 947 | Note: this function allocated an array in plan->pplans with tcc_malloc. It |
|
- | 948 | is the responsibility of the caller to free this array once used (ie not |
|
- | 949 | before copy_params). */ |
|
- | 950 | static int assign_regs(int nb_args, int float_abi, struct plan *plan, int *todo) |
|
- | 951 | { |
|
- | 952 | int i, size, align; |
|
- | 953 | int ncrn /* next core register number */, nsaa /* next stacked argument address*/; |
|
- | 954 | int plan_nb = 0; |
|
- | 955 | struct param_plan pplan; |
|
636 | if (r == VT_CMP || (r & ~1) == VT_JMP) |
956 | struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
- | 957 | ||
- | 958 | ncrn = nsaa = 0; |
|
- | 959 | *todo = 0; |
|
637 | gv(RC_INT); |
960 | plan->pplans = tcc_malloc(nb_args * sizeof(*plan->pplans)); |
- | 961 | memset(plan->clsplans, 0, sizeof(plan->clsplans)); |
|
- | 962 | for(i = nb_args; i-- ;) { |
|
638 | args_size = 0; |
963 | int j, start_vfpreg = 0; |
639 | for(i = nb_args ; i-- && args_size < 16 ;) { |
964 | CType type = vtop[-i].type; |
640 | if ((vtop[-i].type.t & VT_BTYPE) == VT_STRUCT) { |
965 | type.t &= ~VT_ARRAY; |
641 | size = type_size(&vtop[-i].type, &align); |
966 | size = type_size(&type, &align); |
642 | size = (size + 3) & ~3; |
967 | size = (size + 3) & ~3; |
- | 968 | align = (align + 3) & ~3; |
|
643 | args_size += size; |
969 | switch(vtop[-i].type.t & VT_BTYPE) { |
644 | } else if ((vtop[-i].type.t & VT_BTYPE) == VT_FLOAT) |
970 | case VT_STRUCT: |
645 | args_size += 4; |
971 | case VT_FLOAT: |
646 | else if ((vtop[-i].type.t & VT_BTYPE) == VT_DOUBLE) |
972 | case VT_DOUBLE: |
- | 973 | case VT_LDOUBLE: |
|
- | 974 | if (float_abi == ARM_HARD_FLOAT) { |
|
647 | args_size += 8; |
975 | int is_hfa = 0; /* Homogeneous float aggregate */ |
- | 976 | ||
648 | else if ((vtop[-i].type.t & VT_BTYPE) == VT_LDOUBLE) |
977 | if (is_float(vtop[-i].type.t) |
- | 978 | || (is_hfa = is_hgen_float_aggr(&vtop[-i].type))) { |
|
- | 979 | int end_vfpreg; |
|
649 | args_size += LDOUBLE_SIZE; |
980 | |
- | 981 | start_vfpreg = assign_vfpreg(&avregs, align, size); |
|
- | 982 | end_vfpreg = start_vfpreg + ((size - 1) >> 2); |
|
650 | else { |
983 | if (start_vfpreg >= 0) { |
651 | plan[nb_args-1-i][0]=args_size/4; |
984 | pplan = (struct param_plan) {start_vfpreg, end_vfpreg, &vtop[-i]}; |
- | 985 | if (is_hfa) |
|
652 | args_size += 4; |
986 | add_param_plan(plan, pplan, VFP_STRUCT_CLASS); |
- | 987 | else |
|
- | 988 | add_param_plan(plan, pplan, VFP_CLASS); |
|
653 | if ((vtop[-i].type.t & VT_BTYPE) == VT_LLONG && args_size < 16) { |
989 | continue; |
654 | plan[nb_args-1-i][1]=args_size/4; |
990 | } else |
655 | args_size += 4; |
991 | break; |
- | 992 | } |
|
- | 993 | } |
|
- | 994 | ncrn = (ncrn + (align-1)/4) & ~((align/4) - 1); |
|
- | 995 | if (ncrn + size/4 <= 4 || (ncrn < 4 && start_vfpreg != -1)) { |
|
- | 996 | /* The parameter is allocated both in core register and on stack. As |
|
- | 997 | * such, it can be of either class: it would either be the last of |
|
- | 998 | * CORE_STRUCT_CLASS or the first of STACK_CLASS. */ |
|
- | 999 | for (j = ncrn; j < 4 && j < ncrn + size / 4; j++) |
|
- | 1000 | *todo|=(1< |
|
- | 1001 | pplan = (struct param_plan) {ncrn, j, &vtop[-i]}; |
|
- | 1002 | add_param_plan(plan, pplan, CORE_STRUCT_CLASS); |
|
- | 1003 | ncrn += size/4; |
|
- | 1004 | if (ncrn > 4) |
|
- | 1005 | nsaa = (ncrn - 4) * 4; |
|
- | 1006 | } else { |
|
656 | } |
1007 | ncrn = 4; |
- | 1008 | break; |
|
- | 1009 | } |
|
- | 1010 | continue; |
|
- | 1011 | default: |
|
- | 1012 | if (ncrn < 4) { |
|
- | 1013 | int is_long = (vtop[-i].type.t & VT_BTYPE) == VT_LLONG; |
|
- | 1014 | ||
657 | } |
1015 | if (is_long) { |
- | 1016 | ncrn = (ncrn + 1) & -2; |
|
- | 1017 | if (ncrn == 4) |
|
- | 1018 | break; |
|
- | 1019 | } |
|
- | 1020 | pplan = (struct param_plan) {ncrn, ncrn, &vtop[-i]}; |
|
- | 1021 | ncrn++; |
|
- | 1022 | if (is_long) |
|
- | 1023 | pplan.end = ncrn++; |
|
- | 1024 | add_param_plan(plan, pplan, CORE_CLASS); |
|
- | 1025 | continue; |
|
- | 1026 | } |
|
- | 1027 | } |
|
- | 1028 | nsaa = (nsaa + (align - 1)) & ~(align - 1); |
|
- | 1029 | pplan = (struct param_plan) {nsaa, nsaa + size, &vtop[-i]}; |
|
- | 1030 | add_param_plan(plan, pplan, STACK_CLASS); |
|
- | 1031 | nsaa += size; /* size already rounded up before */ |
|
- | 1032 | } |
|
- | 1033 | return nsaa; |
|
- | 1034 | } |
|
- | 1035 | ||
- | 1036 | #undef add_param_plan |
|
- | 1037 | ||
- | 1038 | /* Copy parameters to their final destination (core reg, VFP reg or stack) for |
|
- | 1039 | function call. |
|
- | 1040 | ||
- | 1041 | nb_args: number of parameters the function take |
|
- | 1042 | plan: the overall assignment plan for parameters |
|
- | 1043 | todo: a bitmap indicating what core reg will hold a parameter |
|
- | 1044 | ||
- | 1045 | Returns the number of SValue added by this function on the value stack */ |
|
- | 1046 | static int copy_params(int nb_args, struct plan *plan, int todo) |
|
- | 1047 | { |
|
- | 1048 | int size, align, r, i, nb_extra_sval = 0; |
|
- | 1049 | struct param_plan *pplan; |
|
- | 1050 | ||
- | 1051 | /* Several constraints require parameters to be copied in a specific order: |
|
- | 1052 | - structures are copied to the stack before being loaded in a reg; |
|
- | 1053 | - floats loaded to an odd numbered VFP reg are first copied to the |
|
- | 1054 | preceding even numbered VFP reg and then moved to the next VFP reg. |
|
- | 1055 | ||
- | 1056 | It is thus important that: |
|
- | 1057 | - structures assigned to core regs must be copied after parameters |
|
- | 1058 | assigned to the stack but before structures assigned to VFP regs because |
|
- | 1059 | a structure can lie partly in core registers and partly on the stack; |
|
- | 1060 | - parameters assigned to the stack and all structures be copied before |
|
- | 1061 | parameters assigned to a core reg since copying a parameter to the stack |
|
- | 1062 | require using a core reg; |
|
- | 1063 | - parameters assigned to VFP regs be copied before structures assigned to |
|
658 | } |
1064 | VFP regs as the copy might use an even numbered VFP reg that already |
- | 1065 | holds part of a structure. */ |
|
- | 1066 | for(i = 0; i < NB_CLASSES; i++) { |
|
- | 1067 | for(pplan = plan->clsplans[i]; pplan; pplan = pplan->prev) { |
|
659 | args_size = keep = 0; |
1068 | vpushv(pplan->sval); |
- | 1069 | pplan->sval->r = pplan->sval->r2 = VT_CONST; /* disable entry */ |
|
- | 1070 | switch(i) { |
|
- | 1071 | case STACK_CLASS: |
|
660 | for(i = 0;i < nb_args; i++) { |
1072 | case CORE_STRUCT_CLASS: |
- | 1073 | case VFP_STRUCT_CLASS: |
|
661 | vnrott(keep+1); |
1074 | if ((pplan->sval->type.t & VT_BTYPE) == VT_STRUCT) { |
662 | if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) { |
1075 | int padding = 0; |
663 | size = type_size(&vtop->type, &align); |
1076 | size = type_size(&pplan->sval->type, &align); |
- | 1077 | /* align to stack align size */ |
|
- | 1078 | size = (size + 3) & ~3; |
|
- | 1079 | if (i == STACK_CLASS && pplan->prev) |
|
664 | /* align to stack align size */ |
1080 | padding = pplan->start - pplan->prev->end; |
665 | size = (size + 3) & ~3; |
1081 | size += padding; /* Add padding if any */ |
666 | /* allocate the necessary size on stack */ |
1082 | /* allocate the necessary size on stack */ |
667 | gadd_sp(-size); |
1083 | gadd_sp(-size); |
668 | /* generate structure store */ |
1084 | /* generate structure store */ |
669 | r = get_reg(RC_INT); |
1085 | r = get_reg(RC_INT); |
670 | o(0xE1A0000D|(intr(r)<<12)); |
1086 | o(0xE28D0000|(intr(r)<<12)|padding); /* add r, sp, padding */ |
- | 1087 | vset(&vtop->type, r | VT_LVAL, 0); |
|
- | 1088 | vswap(); |
|
- | 1089 | vstore(); /* memcpy to current sp + potential padding */ |
|
- | 1090 | ||
- | 1091 | /* Homogeneous float aggregate are loaded to VFP registers |
|
- | 1092 | immediately since there is no way of loading data in multiple |
|
- | 1093 | non consecutive VFP registers as what is done for other |
|
- | 1094 | structures (see the use of todo). */ |
|
- | 1095 | if (i == VFP_STRUCT_CLASS) { |
|
- | 1096 | int first = pplan->start, nb = pplan->end - first + 1; |
|
- | 1097 | /* vpop.32 {pplan->start, ..., pplan->end} */ |
|
- | 1098 | o(0xECBD0A00|(first&1)<<22|(first>>1)<<12|nb); |
|
671 | vset(&vtop->type, r | VT_LVAL, 0); |
1099 | /* No need to write the register used to a SValue since VFP regs |
672 | vswap(); |
1100 | cannot be used for gcall_or_jmp */ |
- | 1101 | } |
|
- | 1102 | } else { |
|
- | 1103 | if (is_float(pplan->sval->type.t)) { |
|
- | 1104 | #ifdef TCC_ARM_VFP |
|
- | 1105 | r = vfpr(gv(RC_FLOAT)) << 12; |
|
- | 1106 | if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) |
|
673 | vstore(); |
1107 | size = 4; |
- | 1108 | else { |
|
- | 1109 | size = 8; |
|
674 | vtop--; |
1110 | r |= 0x101; /* vpush.32 -> vpush.64 */ |
- | 1111 | } |
|
675 | args_size += size; |
1112 | o(0xED2D0A01 + r); /* vpush */ |
676 | } else if (is_float(vtop->type.t)) { |
1113 | #else |
677 | r=fpr(gv(RC_FLOAT))<<12; |
1114 | r = fpr(gv(RC_FLOAT)) << 12; |
678 | if ((vtop->type.t & VT_BTYPE) == VT_FLOAT) |
1115 | if ((pplan->sval->type.t & VT_BTYPE) == VT_FLOAT) |
679 | size = 4; |
1116 | size = 4; |
680 | else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE) |
1117 | else if ((pplan->sval->type.t & VT_BTYPE) == VT_DOUBLE) |
681 | size = 8; |
1118 | size = 8; |
Line 682... | Line 1119... | ||
682 | else |
1119 | else |
683 | size = LDOUBLE_SIZE; |
1120 | size = LDOUBLE_SIZE; |
684 | 1121 | ||
685 | if (size == 12) |
1122 | if (size == 12) |
Line 686... | Line 1123... | ||
686 | r|=0x400000; |
1123 | r |= 0x400000; |
687 | else if(size == 8) |
1124 | else if(size == 8) |
688 | r|=0x8000; |
- | |
689 | 1125 | r|=0x8000; |
|
690 | o(0xED2D0100|r|(size>>2)); |
- | |
691 | vtop--; |
1126 | |
692 | args_size += size; |
1127 | o(0xED2D0100|r|(size>>2)); /* some kind of vpush for FPA */ |
693 | } else { |
1128 | #endif |
694 | int s; |
1129 | } else { |
695 | /* simple type (currently always same size) */ |
1130 | /* simple type (currently always same size) */ |
696 | /* XXX: implicit cast ? */ |
- | |
697 | size=4; |
- | |
698 | if ((vtop->type.t & VT_BTYPE) == VT_LLONG) { |
1131 | /* XXX: implicit cast ? */ |
699 | lexpand_nr(); |
- | |
700 | s=RC_INT; |
- | |
701 | if(nb_args-i<5 && plan[nb_args-i-1][1]!=-1) { |
- | |
702 | s=regmask(plan[nb_args-i-1][1]); |
1132 | size=4; |
703 | todo&=~(1< |
1133 | if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { |
704 | } |
1134 | lexpand_nr(); |
705 | if(s==RC_INT) { |
- | |
706 | r = gv(s); |
- | |
707 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
- | |
708 | vtop--; |
- | |
709 | } else { |
1135 | size = 8; |
- | 1136 | r = gv(RC_INT); |
|
- | 1137 | o(0xE52D0004|(intr(r)<<12)); /* push r */ |
|
710 | plan2[keep]=s; |
1138 | vtop--; |
- | 1139 | } |
|
- | 1140 | r = gv(RC_INT); |
|
711 | keep++; |
1141 | o(0xE52D0004|(intr(r)<<12)); /* push r */ |
712 | vswap(); |
1142 | } |
- | 1143 | if (i == STACK_CLASS && pplan->prev) |
|
713 | } |
1144 | gadd_sp(pplan->prev->end - pplan->start); /* Add padding if any */ |
714 | size = 8; |
1145 | } |
715 | } |
1146 | break; |
- | 1147 | ||
- | 1148 | case VFP_CLASS: |
|
716 | s=RC_INT; |
1149 | gv(regmask(TREG_F0 + (pplan->start >> 1))); |
- | 1150 | if (pplan->start & 1) { /* Must be in upper part of double register */ |
|
- | 1151 | o(0xEEF00A40|((pplan->start>>1)<<12)|(pplan->start>>1)); /* vmov.f32 s(n+1), sn */ |
|
717 | if(nb_args-i<5 && plan[nb_args-i-1][0]!=-1) { |
1152 | vtop->r = VT_CONST; /* avoid being saved on stack by gv for next float */ |
- | 1153 | } |
|
718 | s=regmask(plan[nb_args-i-1][0]); |
1154 | break; |
- | 1155 | ||
719 | todo&=~(1< |
1156 | case CORE_CLASS: |
720 | } |
1157 | if ((pplan->sval->type.t & VT_BTYPE) == VT_LLONG) { |
721 | if(s==RC_INT) { |
- | |
722 | r = gv(s); |
- | |
723 | o(0xE52D0004|(intr(r)<<12)); /* str r,[sp,#-4]! */ |
- | |
724 | vtop--; |
1158 | lexpand_nr(); |
- | 1159 | gv(regmask(pplan->end)); |
|
- | 1160 | pplan->sval->r2 = vtop->r; |
|
- | 1161 | vtop--; |
|
- | 1162 | } |
|
725 | } else { |
1163 | gv(regmask(pplan->start)); |
726 | plan2[keep]=s; |
1164 | /* Mark register as used so that gcall_or_jmp use another one |
- | 1165 | (regs >=4 are free as never used to pass parameters) */ |
|
727 | keep++; |
1166 | pplan->sval->r = vtop->r; |
728 | } |
- | |
729 | args_size += size; |
- | |
730 | } |
- | |
731 | } |
1167 | break; |
- | 1168 | } |
|
732 | for(i=keep;i--;) { |
1169 | vtop--; |
733 | gv(plan2[i]); |
- | |
734 | vrott(keep); |
1170 | } |
735 | } |
- | |
736 | save_regs(keep); /* save used temporary registers */ |
1171 | } |
737 | keep++; |
- | |
738 | if(args_size) { |
1172 | |
739 | int n; |
- | |
740 | n=args_size/4; |
1173 | /* Manually free remaining registers since next parameters are loaded |
- | 1174 | * manually, without the help of gv(int). */ |
|
- | 1175 | save_regs(nb_args); |
|
741 | if(n>4) |
1176 | |
742 | n=4; |
1177 | if(todo) { |
- | 1178 | o(0xE8BD0000|todo); /* pop {todo} */ |
|
- | 1179 | for(pplan = plan->clsplans[CORE_STRUCT_CLASS]; pplan; pplan = pplan->prev) { |
|
- | 1180 | int r; |
|
- | 1181 | pplan->sval->r = pplan->start; |
|
743 | todo&=((1< |
1182 | /* An SValue can only pin 2 registers at best (r and r2) but a structure |
744 | if(todo) { |
1183 | can occupy more than 2 registers. Thus, we need to push on the value |
- | 1184 | stack some fake parameter to have on SValue for each registers used |
|
745 | int i; |
1185 | by a structure (r2 is not used). */ |
746 | o(0xE8BD0000|todo); |
1186 | for (r = pplan->start + 1; r <= pplan->end; r++) { |
747 | for(i=0;i<4;i++) |
1187 | if (todo & (1 << r)) { |
- | 1188 | nb_extra_sval++; |
|
- | 1189 | vpushi(0); |
|
748 | if(todo&(1< |
1190 | vtop->r = r; |
- | 1191 | } |
|
- | 1192 | } |
|
- | 1193 | } |
|
- | 1194 | } |
|
- | 1195 | return nb_extra_sval; |
|
- | 1196 | } |
|
- | 1197 | ||
- | 1198 | /* Generate function call. The function address is pushed first, then |
|
- | 1199 | all the parameters in call order. This functions pops all the |
|
- | 1200 | parameters and the function address. */ |
|
- | 1201 | void gfunc_call(int nb_args) |
|
- | 1202 | { |
|
- | 1203 | int r, args_size; |
|
- | 1204 | int def_float_abi = float_abi; |
|
- | 1205 | int todo; |
|
- | 1206 | struct plan plan; |
|
- | 1207 | ||
- | 1208 | #ifdef TCC_ARM_EABI |
|
- | 1209 | int variadic; |
|
- | 1210 | ||
749 | vpushi(0); |
1211 | if (float_abi == ARM_HARD_FLOAT) { |
- | 1212 | variadic = (vtop[-nb_args].type.ref->c == FUNC_ELLIPSIS); |
|
- | 1213 | if (variadic || floats_in_core_regs(&vtop[-nb_args])) |
|
- | 1214 | float_abi = ARM_SOFTFP_FLOAT; |
|
- | 1215 | } |
|
- | 1216 | #endif |
|
- | 1217 | /* cannot let cpu flags if other instruction are generated. Also avoid leaving |
|
750 | vtop->r=i; |
1218 | VT_JMP anywhere except on the top of the stack because it would complicate |
- | 1219 | the code generator. */ |
|
- | 1220 | r = vtop->r & VT_VALMASK; |
|
- | 1221 | if (r == VT_CMP || (r & ~1) == VT_JMP) |
|
- | 1222 | gv(RC_INT); |
|
- | 1223 | ||
- | 1224 | args_size = assign_regs(nb_args, float_abi, &plan, &todo); |
|
- | 1225 | ||
751 | keep++; |
1226 | #ifdef TCC_ARM_EABI |
- | 1227 | if (args_size & 7) { /* Stack must be 8 byte aligned at fct call for EABI */ |
|
- | 1228 | args_size = (args_size + 7) & ~7; |
|
- | 1229 | o(0xE24DD004); /* sub sp, sp, #4 */ |
|
752 | } |
1230 | } |
- | 1231 | #endif |
|
- | 1232 | ||
753 | } |
1233 | nb_args += copy_params(nb_args, &plan, todo); |
754 | args_size-=n*4; |
1234 | tcc_free(plan.pplans); |
755 | } |
1235 | |
- | 1236 | /* Move fct SValue on top as required by gcall_or_jmp */ |
|
- | 1237 | vrotb(nb_args + 1); |
|
- | 1238 | gcall_or_jmp(0); |
|
- | 1239 | if (args_size) |
|
756 | vnrott(keep); |
1240 | gadd_sp(args_size); /* pop all parameters passed on the stack */ |
757 | func_sym = vtop->type.ref; |
1241 | #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
- | 1242 | if(float_abi == ARM_SOFTFP_FLOAT && is_float(vtop->type.ref->type.t)) { |
|
- | 1243 | if((vtop->type.ref->type.t & VT_BTYPE) == VT_FLOAT) { |
|
- | 1244 | o(0xEE000A10); /*vmov s0, r0 */ |
|
- | 1245 | } else { |
|
- | 1246 | o(0xEE000B10); /* vmov.32 d0[0], r0 */ |
|
- | 1247 | o(0xEE201B10); /* vmov.32 d0[1], r1 */ |
|
- | 1248 | } |
|
- | 1249 | } |
|
758 | gcall_or_jmp(0); |
1250 | #endif |
Line 759... | Line 1251... | ||
759 | if (args_size) |
1251 | vtop -= nb_args + 1; /* Pop all params and fct address from value stack */ |
760 | gadd_sp(args_size); |
1252 | leaffunc = 0; /* we are calling a function, so we aren't in a leaf function */ |
761 | vtop-=keep; |
1253 | float_abi = def_float_abi; |
762 | } |
1254 | } |
763 | 1255 | ||
- | 1256 | /* generate function prolog of type 't' */ |
|
- | 1257 | void gfunc_prolog(CType *func_type) |
|
- | 1258 | { |
|
- | 1259 | Sym *sym,*sym2; |
|
- | 1260 | int n, nf, size, align, rs, struct_ret = 0; |
|
- | 1261 | int addr, pn, sn; /* pn=core, sn=stack */ |
|
Line 764... | Line 1262... | ||
764 | /* generate function prolog of type 't' */ |
1262 | CType ret_type; |
765 | void gfunc_prolog(CType *func_type) |
1263 | |
- | 1264 | #ifdef TCC_ARM_EABI |
|
Line 766... | Line 1265... | ||
766 | { |
1265 | struct avail_regs avregs = AVAIL_REGS_INITIALIZER; |
767 | Sym *sym,*sym2; |
- | |
768 | int n,addr,size,align; |
1266 | #endif |
769 | 1267 | ||
770 | sym = func_type->ref; |
1268 | sym = func_type->ref; |
771 | func_vt = sym->type; |
1269 | func_vt = sym->type; |
- | 1270 | func_var = (func_type->ref->c == FUNC_ELLIPSIS); |
|
- | 1271 | ||
772 | 1272 | n = nf = 0; |
|
773 | n=0; |
1273 | if ((func_vt.t & VT_BTYPE) == VT_STRUCT && |
774 | addr=12; |
1274 | !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs)) |
- | 1275 | { |
|
- | 1276 | n++; |
|
- | 1277 | struct_ret = 1; |
|
- | 1278 | func_vc = 12; /* Offset from fp of the place to store the result */ |
|
775 | if((func_vt.t & VT_BTYPE) == VT_STRUCT) { |
1279 | } |
- | 1280 | for(sym2 = sym->next; sym2 && (n < 4 || nf < 16); sym2 = sym2->next) { |
|
- | 1281 | size = type_size(&sym2->type, &align); |
|
- | 1282 | #ifdef TCC_ARM_EABI |
|
- | 1283 | if (float_abi == ARM_HARD_FLOAT && !func_var && |
|
776 | func_vc = addr; |
1284 | (is_float(sym2->type.t) || is_hgen_float_aggr(&sym2->type))) { |
777 | addr += 4; |
1285 | int tmpnf = assign_vfpreg(&avregs, align, size); |
778 | n++; |
1286 | tmpnf += (size + 3) / 4; |
779 | } |
1287 | nf = (tmpnf > nf) ? tmpnf : nf; |
780 | for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) { |
1288 | } else |
781 | size = type_size(&sym2->type, &align); |
1289 | #endif |
782 | size = (size + 3) & ~3; |
1290 | if (n < 4) |
783 | n+=size/4; |
1291 | n += (size + 3) / 4; |
- | 1292 | } |
|
- | 1293 | o(0xE1A0C00D); /* mov ip,sp */ |
|
- | 1294 | if (func_var) |
|
784 | } |
1295 | n=4; |
785 | o(0xE1A0C00D); /* mov ip,sp */ |
1296 | if (n) { |
- | 1297 | if(n>4) |
|
- | 1298 | n=4; |
|
- | 1299 | #ifdef TCC_ARM_EABI |
|
- | 1300 | n=(n+1)&-2; |
|
- | 1301 | #endif |
|
- | 1302 | o(0xE92D0000|((1< |
|
786 | if(func_type->ref->c == FUNC_ELLIPSIS) |
1303 | } |
787 | n=4; |
1304 | if (nf) { |
788 | if(n) { |
1305 | if (nf>16) |
789 | if(n>4) |
1306 | nf=16; |
- | 1307 | nf=(nf+1)&-2; /* nf => HARDFLOAT => EABI */ |
|
- | 1308 | o(0xED2D0A00|nf); /* save s0-s15 on stack if needed */ |
|
- | 1309 | } |
|
- | 1310 | o(0xE92D5800); /* save fp, ip, lr */ |
|
- | 1311 | o(0xE1A0B00D); /* mov fp, sp */ |
|
- | 1312 | func_sub_sp_offset = ind; |
|
- | 1313 | o(0xE1A00000); /* nop, leave space for stack adjustment in epilog */ |
|
- | 1314 | ||
790 | n=4; |
1315 | #ifdef TCC_ARM_EABI |
791 | o(0xE92D0000|((1< |
1316 | if (float_abi == ARM_HARD_FLOAT) { |
792 | } |
1317 | func_vc += nf * 4; |
793 | o(0xE92D5800); /* save fp, ip, lr*/ |
- | |
794 | o(0xE1A0B00D); /* mov fp,sp */ |
1318 | avregs = AVAIL_REGS_INITIALIZER; |
795 | func_sub_sp_offset = ind; |
1319 | } |
- | 1320 | #endif |
|
- | 1321 | pn = struct_ret, sn = 0; |
|
- | 1322 | while ((sym = sym->next)) { |
|
- | 1323 | CType *type; |
|
- | 1324 | type = &sym->type; |
|
- | 1325 | size = type_size(type, &align); |
|
- | 1326 | size = (size + 3) >> 2; |
|
- | 1327 | align = (align + 3) & ~3; |
|
- | 1328 | #ifdef TCC_ARM_EABI |
|
- | 1329 | if (float_abi == ARM_HARD_FLOAT && !func_var && (is_float(sym->type.t) |
|
- | 1330 | || is_hgen_float_aggr(&sym->type))) { |
|
- | 1331 | int fpn = assign_vfpreg(&avregs, align, size << 2); |
|
- | 1332 | if (fpn >= 0) |
|
- | 1333 | addr = fpn * 4; |
|
- | 1334 | else |
|
- | 1335 | goto from_stack; |
|
- | 1336 | } else |
|
- | 1337 | #endif |
|
- | 1338 | if (pn < 4) { |
|
- | 1339 | #ifdef TCC_ARM_EABI |
|
- | 1340 | pn = (pn + (align-1)/4) & -(align/4); |
|
- | 1341 | #endif |
|
- | 1342 | addr = (nf + pn) * 4; |
|
- | 1343 | pn += size; |
|
- | 1344 | if (!sn && pn > 4) |
|
796 | o(0xE1A00000); /* nop, leave space for stack adjustment */ |
1345 | sn = (pn - 4); |
- | 1346 | } else { |
|
- | 1347 | #ifdef TCC_ARM_EABI |
|
- | 1348 | from_stack: |
|
797 | while ((sym = sym->next)) { |
1349 | sn = (sn + (align-1)/4) & -(align/4); |
798 | CType *type; |
1350 | #endif |
- | 1351 | addr = (n + nf + sn) * 4; |
|
799 | type = &sym->type; |
1352 | sn += size; |
800 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr); |
1353 | } |
Line 801... | Line 1354... | ||
801 | size = type_size(type, &align); |
1354 | sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | lvalue_type(type->t), |
802 | size = (size + 3) & ~3; |
1355 | addr + 12); |
803 | addr += size; |
1356 | } |
804 | } |
1357 | last_itod_magic=0; |
- | 1358 | leaffunc = 1; |
|
- | 1359 | loc = 0; |
|
- | 1360 | } |
|
- | 1361 | ||
- | 1362 | /* generate function epilog */ |
|
- | 1363 | void gfunc_epilog(void) |
|
- | 1364 | { |
|
- | 1365 | uint32_t x; |
|
- | 1366 | int diff; |
|
- | 1367 | /* Copy float return value to core register if base standard is used and |
|
- | 1368 | float computation is made with VFP */ |
|
- | 1369 | #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) |
|
- | 1370 | if ((float_abi == ARM_SOFTFP_FLOAT || func_var) && is_float(func_vt.t)) { |
|
805 | last_itod_magic=0; |
1371 | if((func_vt.t & VT_BTYPE) == VT_FLOAT) |
- | 1372 | o(0xEE100A10); /* fmrs r0, s0 */ |
|
- | 1373 | else { |
|
- | 1374 | o(0xEE100B10); /* fmrdl r0, d0 */ |
|
- | 1375 | o(0xEE301B10); /* fmrdh r1, d0 */ |
|
- | 1376 | } |
|
806 | loc = 0; |
1377 | } |
807 | } |
1378 | #endif |
808 | 1379 | o(0xE89BA800); /* restore fp, sp, pc */ |
|
809 | /* generate function epilog */ |
1380 | diff = (-loc + 3) & -4; |
810 | void gfunc_epilog(void) |
1381 | #ifdef TCC_ARM_EABI |
811 | { |
1382 | if(!leaffunc) |
812 | unsigned long x; |
1383 | diff = ((diff + 11) & -8) - 4; |
813 | o(0xE89BA800); /* restore fp, sp, pc */ |
1384 | #endif |
814 | if(loc) { |
1385 | if(diff > 0) { |
815 | x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */ |
1386 | x=stuff_const(0xE24BD000, diff); /* sub sp,fp,# */ |
816 | if(x) |
1387 | if(x) |
817 | *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x; |
1388 | *(uint32_t *)(cur_text_section->data + func_sub_sp_offset) = x; |
818 | else { |
1389 | else { |
819 | unsigned long addr; |
1390 | int addr; |
820 | addr=ind; |
1391 | addr=ind; |
Line 821... | Line 1392... | ||
821 | o(0xE59FC004); /* ldr ip,[pc+4] */ |
1392 | o(0xE59FC004); /* ldr ip,[pc+4] */ |
Line 844... | Line 1415... | ||
844 | 1415 | ||
845 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
1416 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
846 | int gtst(int inv, int t) |
1417 | int gtst(int inv, int t) |
847 | { |
1418 | { |
848 | int v, r; |
1419 | int v, r; |
849 | unsigned long op; |
1420 | uint32_t op; |
850 | v = vtop->r & VT_VALMASK; |
1421 | v = vtop->r & VT_VALMASK; |
851 | r=ind; |
1422 | r=ind; |
852 | if (v == VT_CMP) { |
1423 | if (v == VT_CMP) { |
853 | op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); |
1424 | op=mapcc(inv?negcc(vtop->c.i):vtop->c.i); |
Line 857... | Line 1428... | ||
857 | } else if (v == VT_JMP || v == VT_JMPI) { |
1428 | } else if (v == VT_JMP || v == VT_JMPI) { |
858 | if ((v & 1) == inv) { |
1429 | if ((v & 1) == inv) { |
859 | if(!vtop->c.i) |
1430 | if(!vtop->c.i) |
860 | vtop->c.i=t; |
1431 | vtop->c.i=t; |
861 | else { |
1432 | else { |
862 | unsigned long *x; |
1433 | uint32_t *x; |
863 | int p,lp; |
1434 | int p,lp; |
864 | if(t) { |
1435 | if(t) { |
865 | p = vtop->c.i; |
1436 | p = vtop->c.i; |
866 | do { |
1437 | do { |
867 | p = decbranch(lp=p); |
1438 | p = decbranch(lp=p); |
868 | } while(p); |
1439 | } while(p); |
869 | x = (unsigned long *)(cur_text_section->data + lp); |
1440 | x = (uint32_t *)(cur_text_section->data + lp); |
870 | *x &= 0xff000000; |
1441 | *x &= 0xff000000; |
871 | *x |= encbranch(lp,t,1); |
1442 | *x |= encbranch(lp,t,1); |
872 | } |
1443 | } |
873 | t = vtop->c.i; |
1444 | t = vtop->c.i; |
874 | } |
1445 | } |
875 | } else { |
1446 | } else { |
876 | t = gjmp(t); |
1447 | t = gjmp(t); |
877 | gsym(vtop->c.i); |
1448 | gsym(vtop->c.i); |
878 | } |
1449 | } |
879 | } else { |
- | |
880 | if (is_float(vtop->type.t)) { |
- | |
881 | r=gv(RC_FLOAT); |
- | |
882 | o(0xEE90F118|fpr(r)<<16); |
- | |
883 | vtop->r = VT_CMP; |
- | |
884 | vtop->c.i = TOK_NE; |
- | |
885 | return gtst(inv, t); |
- | |
886 | } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
- | |
887 | /* constant jmp optimization */ |
- | |
888 | if ((vtop->c.i != 0) != inv) |
- | |
889 | t = gjmp(t); |
- | |
890 | } else { |
- | |
891 | v = gv(RC_INT); |
- | |
892 | o(0xE3300000|(intr(v)<<16)); |
- | |
893 | vtop->r = VT_CMP; |
- | |
894 | vtop->c.i = TOK_NE; |
- | |
895 | return gtst(inv, t); |
- | |
896 | } |
- | |
897 | } |
1450 | } |
898 | vtop--; |
1451 | vtop--; |
899 | return t; |
1452 | return t; |
900 | } |
1453 | } |
Line 901... | Line 1454... | ||
901 | 1454 | ||
902 | /* generate an integer binary operation */ |
1455 | /* generate an integer binary operation */ |
903 | void gen_opi(int op) |
1456 | void gen_opi(int op) |
904 | { |
1457 | { |
905 | int c, func = 0; |
1458 | int c, func = 0; |
- | 1459 | uint32_t opc = 0, r, fr; |
|
Line 906... | Line 1460... | ||
906 | unsigned long opc = 0,r,fr; |
1460 | unsigned short retreg = REG_IRET; |
907 | 1461 | ||
908 | c=0; |
1462 | c=0; |
909 | switch(op) { |
1463 | switch(op) { |
Line 970... | Line 1524... | ||
970 | case TOK_UDIV: |
1524 | case TOK_UDIV: |
971 | func=TOK___udivsi3; |
1525 | func=TOK___udivsi3; |
972 | c=3; |
1526 | c=3; |
973 | break; |
1527 | break; |
974 | case '%': |
1528 | case '%': |
- | 1529 | #ifdef TCC_ARM_EABI |
|
- | 1530 | func=TOK___aeabi_idivmod; |
|
- | 1531 | retreg=REG_LRET; |
|
- | 1532 | #else |
|
975 | func=TOK___modsi3; |
1533 | func=TOK___modsi3; |
- | 1534 | #endif |
|
976 | c=3; |
1535 | c=3; |
977 | break; |
1536 | break; |
978 | case TOK_UMOD: |
1537 | case TOK_UMOD: |
- | 1538 | #ifdef TCC_ARM_EABI |
|
- | 1539 | func=TOK___aeabi_uidivmod; |
|
- | 1540 | retreg=REG_LRET; |
|
- | 1541 | #else |
|
979 | func=TOK___umodsi3; |
1542 | func=TOK___umodsi3; |
- | 1543 | #endif |
|
980 | c=3; |
1544 | c=3; |
981 | break; |
1545 | break; |
982 | case TOK_UMULL: |
1546 | case TOK_UMULL: |
983 | gv2(RC_INT, RC_INT); |
1547 | gv2(RC_INT, RC_INT); |
984 | r=intr(vtop[-1].r2=get_reg(RC_INT)); |
1548 | r=intr(vtop[-1].r2=get_reg(RC_INT)); |
Line 1006... | Line 1570... | ||
1006 | vswap(); |
1570 | vswap(); |
1007 | c=intr(gv(RC_INT)); |
1571 | c=intr(gv(RC_INT)); |
1008 | vswap(); |
1572 | vswap(); |
1009 | opc=0xE0000000|(opc<<20)|(c<<16); |
1573 | opc=0xE0000000|(opc<<20)|(c<<16); |
1010 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
1574 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) { |
1011 | unsigned long x; |
1575 | uint32_t x; |
1012 | x=stuff_const(opc|0x2000000,vtop->c.i); |
1576 | x=stuff_const(opc|0x2000000,vtop->c.i); |
1013 | if(x) { |
1577 | if(x) { |
1014 | r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); |
1578 | r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r))); |
1015 | o(x|(r<<12)); |
1579 | o(x|(r<<12)); |
1016 | goto done; |
1580 | goto done; |
Line 1049... | Line 1613... | ||
1049 | case 3: |
1613 | case 3: |
1050 | vpush_global_sym(&func_old_type, func); |
1614 | vpush_global_sym(&func_old_type, func); |
1051 | vrott(3); |
1615 | vrott(3); |
1052 | gfunc_call(2); |
1616 | gfunc_call(2); |
1053 | vpushi(0); |
1617 | vpushi(0); |
1054 | vtop->r = REG_IRET; |
1618 | vtop->r = retreg; |
1055 | break; |
1619 | break; |
1056 | default: |
1620 | default: |
1057 | error("gen_opi %i unimplemented!",op); |
1621 | tcc_error("gen_opi %i unimplemented!",op); |
1058 | } |
1622 | } |
1059 | } |
1623 | } |
Line -... | Line 1624... | ||
- | 1624 | ||
- | 1625 | #ifdef TCC_ARM_VFP |
|
- | 1626 | static int is_zero(int i) |
|
- | 1627 | { |
|
- | 1628 | if((vtop[i].r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
|
- | 1629 | return 0; |
|
- | 1630 | if (vtop[i].type.t == VT_FLOAT) |
|
- | 1631 | return (vtop[i].c.f == 0.f); |
|
- | 1632 | else if (vtop[i].type.t == VT_DOUBLE) |
|
- | 1633 | return (vtop[i].c.d == 0.0); |
|
- | 1634 | return (vtop[i].c.ld == 0.l); |
|
- | 1635 | } |
|
- | 1636 | ||
- | 1637 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
|
- | 1638 | * two operands are guaranted to have the same floating point type */ |
|
- | 1639 | void gen_opf(int op) |
|
- | 1640 | { |
|
- | 1641 | uint32_t x; |
|
- | 1642 | int fneg=0,r; |
|
- | 1643 | x=0xEE000A00|T2CPR(vtop->type.t); |
|
- | 1644 | switch(op) { |
|
- | 1645 | case '+': |
|
- | 1646 | if(is_zero(-1)) |
|
- | 1647 | vswap(); |
|
- | 1648 | if(is_zero(0)) { |
|
- | 1649 | vtop--; |
|
- | 1650 | return; |
|
- | 1651 | } |
|
- | 1652 | x|=0x300000; |
|
- | 1653 | break; |
|
- | 1654 | case '-': |
|
- | 1655 | x|=0x300040; |
|
- | 1656 | if(is_zero(0)) { |
|
- | 1657 | vtop--; |
|
- | 1658 | return; |
|
- | 1659 | } |
|
- | 1660 | if(is_zero(-1)) { |
|
- | 1661 | x|=0x810000; /* fsubX -> fnegX */ |
|
- | 1662 | vswap(); |
|
- | 1663 | vtop--; |
|
- | 1664 | fneg=1; |
|
- | 1665 | } |
|
- | 1666 | break; |
|
- | 1667 | case '*': |
|
- | 1668 | x|=0x200000; |
|
- | 1669 | break; |
|
- | 1670 | case '/': |
|
- | 1671 | x|=0x800000; |
|
- | 1672 | break; |
|
- | 1673 | default: |
|
- | 1674 | if(op < TOK_ULT || op > TOK_GT) { |
|
- | 1675 | tcc_error("unknown fp op %x!",op); |
|
- | 1676 | return; |
|
- | 1677 | } |
|
- | 1678 | if(is_zero(-1)) { |
|
- | 1679 | vswap(); |
|
- | 1680 | switch(op) { |
|
- | 1681 | case TOK_LT: op=TOK_GT; break; |
|
- | 1682 | case TOK_GE: op=TOK_ULE; break; |
|
- | 1683 | case TOK_LE: op=TOK_GE; break; |
|
- | 1684 | case TOK_GT: op=TOK_ULT; break; |
|
- | 1685 | } |
|
- | 1686 | } |
|
- | 1687 | x|=0xB40040; /* fcmpX */ |
|
- | 1688 | if(op!=TOK_EQ && op!=TOK_NE) |
|
- | 1689 | x|=0x80; /* fcmpX -> fcmpeX */ |
|
- | 1690 | if(is_zero(0)) { |
|
- | 1691 | vtop--; |
|
- | 1692 | o(x|0x10000|(vfpr(gv(RC_FLOAT))<<12)); /* fcmp(e)X -> fcmp(e)zX */ |
|
- | 1693 | } else { |
|
- | 1694 | x|=vfpr(gv(RC_FLOAT)); |
|
- | 1695 | vswap(); |
|
- | 1696 | o(x|(vfpr(gv(RC_FLOAT))<<12)); |
|
- | 1697 | vtop--; |
|
- | 1698 | } |
|
- | 1699 | o(0xEEF1FA10); /* fmstat */ |
|
- | 1700 | ||
- | 1701 | switch(op) { |
|
- | 1702 | case TOK_LE: op=TOK_ULE; break; |
|
- | 1703 | case TOK_LT: op=TOK_ULT; break; |
|
- | 1704 | case TOK_UGE: op=TOK_GE; break; |
|
- | 1705 | case TOK_UGT: op=TOK_GT; break; |
|
- | 1706 | } |
|
- | 1707 | ||
- | 1708 | vtop->r = VT_CMP; |
|
- | 1709 | vtop->c.i = op; |
|
- | 1710 | return; |
|
- | 1711 | } |
|
- | 1712 | r=gv(RC_FLOAT); |
|
- | 1713 | x|=vfpr(r); |
|
- | 1714 | r=regmask(r); |
|
- | 1715 | if(!fneg) { |
|
- | 1716 | int r2; |
|
- | 1717 | vswap(); |
|
- | 1718 | r2=gv(RC_FLOAT); |
|
- | 1719 | x|=vfpr(r2)<<16; |
|
- | 1720 | r|=regmask(r2); |
|
- | 1721 | } |
|
- | 1722 | vtop->r=get_reg_ex(RC_FLOAT,r); |
|
- | 1723 | if(!fneg) |
|
- | 1724 | vtop--; |
|
- | 1725 | o(x|(vfpr(vtop->r)<<12)); |
|
- | 1726 | } |
|
- | 1727 | ||
1060 | 1728 | #else |
|
1061 | static int is_fconst() |
1729 | static uint32_t is_fconst() |
1062 | { |
1730 | { |
1063 | long double f; |
1731 | long double f; |
1064 | int r; |
1732 | uint32_t r; |
1065 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
1733 | if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST) |
1066 | return 0; |
1734 | return 0; |
1067 | if (vtop->type.t == VT_FLOAT) |
1735 | if (vtop->type.t == VT_FLOAT) |
1068 | f = vtop->c.f; |
1736 | f = vtop->c.f; |
Line 1098... | Line 1766... | ||
1098 | 1766 | ||
1099 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
1767 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
1100 | two operands are guaranted to have the same floating point type */ |
1768 | two operands are guaranted to have the same floating point type */ |
1101 | void gen_opf(int op) |
1769 | void gen_opf(int op) |
1102 | { |
- | |
1103 | unsigned long x; |
1770 | { |
1104 | int r,r2,c1,c2; |
1771 | uint32_t x, r, r2, c1, c2; |
1105 | //fputs("gen_opf\n",stderr); |
1772 | //fputs("gen_opf\n",stderr); |
1106 | vswap(); |
1773 | vswap(); |
1107 | c1 = is_fconst(); |
1774 | c1 = is_fconst(); |
1108 | vswap(); |
1775 | vswap(); |
Line 1191... | Line 1858... | ||
1191 | } |
1858 | } |
1192 | break; |
1859 | break; |
1193 | default: |
1860 | default: |
1194 | if(op >= TOK_ULT && op <= TOK_GT) { |
1861 | if(op >= TOK_ULT && op <= TOK_GT) { |
1195 | x|=0xd0f110; // cmfe |
1862 | x|=0xd0f110; // cmfe |
- | 1863 | /* bug (intention?) in Linux FPU emulator |
|
- | 1864 | doesn't set carry if equal */ |
|
1196 | switch(op) { |
1865 | switch(op) { |
1197 | case TOK_ULT: |
1866 | case TOK_ULT: |
1198 | case TOK_UGE: |
1867 | case TOK_UGE: |
1199 | case TOK_ULE: |
1868 | case TOK_ULE: |
1200 | case TOK_UGT: |
1869 | case TOK_UGT: |
1201 | fputs("unsigned comparision on floats?\n",stderr); |
1870 | tcc_error("unsigned comparison on floats?"); |
1202 | break; |
1871 | break; |
1203 | case TOK_LT: |
1872 | case TOK_LT: |
1204 | op=TOK_ULT; |
- | |
1205 | break; |
- | |
1206 | case TOK_GE: |
- | |
1207 | op=TOK_UGE; |
1873 | op=TOK_Nset; |
1208 | break; |
1874 | break; |
1209 | case TOK_LE: |
1875 | case TOK_LE: |
1210 | op=TOK_ULE; |
1876 | op=TOK_ULE; /* correct in unordered case only if AC bit in FPSR set */ |
1211 | break; |
- | |
1212 | case TOK_GT: |
- | |
1213 | op=TOK_UGT; |
- | |
1214 | break; |
1877 | break; |
1215 | case TOK_EQ: |
1878 | case TOK_EQ: |
1216 | case TOK_NE: |
1879 | case TOK_NE: |
1217 | x&=~0x400000; // cmfe -> cmf |
1880 | x&=~0x400000; // cmfe -> cmf |
1218 | break; |
1881 | break; |
1219 | } |
1882 | } |
1220 | if(c1 && !c2) { |
1883 | if(c1 && !c2) { |
1221 | c2=c1; |
1884 | c2=c1; |
1222 | vswap(); |
1885 | vswap(); |
1223 | switch(op) { |
1886 | switch(op) { |
1224 | case TOK_ULT: |
1887 | case TOK_Nset: |
1225 | op=TOK_UGT; |
1888 | op=TOK_GT; |
1226 | break; |
1889 | break; |
1227 | case TOK_UGE: |
1890 | case TOK_GE: |
1228 | op=TOK_ULE; |
1891 | op=TOK_ULE; |
1229 | break; |
1892 | break; |
1230 | case TOK_ULE: |
1893 | case TOK_ULE: |
1231 | op=TOK_UGE; |
1894 | op=TOK_GE; |
1232 | break; |
1895 | break; |
1233 | case TOK_UGT: |
1896 | case TOK_GT: |
1234 | op=TOK_ULT; |
1897 | op=TOK_Nset; |
1235 | break; |
1898 | break; |
1236 | } |
1899 | } |
1237 | } |
1900 | } |
1238 | // bug (intention?) in Linux FPU emulator |
- | |
1239 | // doesn't set carry if equal |
- | |
1240 | if(op==TOK_ULT) |
- | |
1241 | op=TOK_LT; |
- | |
1242 | else if(op==TOK_UGE) |
- | |
1243 | op=TOK_GE; |
- | |
1244 | vswap(); |
1901 | vswap(); |
1245 | r=fpr(gv(RC_FLOAT)); |
1902 | r=fpr(gv(RC_FLOAT)); |
1246 | vswap(); |
1903 | vswap(); |
1247 | if(c2) { |
1904 | if(c2) { |
1248 | if(c2>0xf) |
1905 | if(c2>0xf) |
Line 1252... | Line 1909... | ||
1252 | r2=fpr(gv(RC_FLOAT)); |
1909 | r2=fpr(gv(RC_FLOAT)); |
1253 | } |
1910 | } |
1254 | vtop[-1].r = VT_CMP; |
1911 | vtop[-1].r = VT_CMP; |
1255 | vtop[-1].c.i = op; |
1912 | vtop[-1].c.i = op; |
1256 | } else { |
1913 | } else { |
1257 | error("unknown fp op %x!\n",op); |
1914 | tcc_error("unknown fp op %x!",op); |
1258 | return; |
1915 | return; |
1259 | } |
1916 | } |
1260 | } |
1917 | } |
1261 | if(vtop[-1].r == VT_CMP) |
1918 | if(vtop[-1].r == VT_CMP) |
1262 | c1=15; |
1919 | c1=15; |
Line 1268... | Line 1925... | ||
1268 | c1=fpr(vtop[-1].r); |
1925 | c1=fpr(vtop[-1].r); |
1269 | } |
1926 | } |
1270 | vtop--; |
1927 | vtop--; |
1271 | o(x|(r<<16)|(c1<<12)|r2); |
1928 | o(x|(r<<16)|(c1<<12)|r2); |
1272 | } |
1929 | } |
- | 1930 | #endif |
|
Line 1273... | Line 1931... | ||
1273 | 1931 | ||
1274 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
1932 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
1275 | and 'long long' cases. */ |
1933 | and 'long long' cases. */ |
1276 | void gen_cvt_itof(int t) |
1934 | ST_FUNC void gen_cvt_itof1(int t) |
- | 1935 | { |
|
1277 | { |
1936 | uint32_t r, r2; |
1278 | int r,r2,bt; |
1937 | int bt; |
1279 | bt=vtop->type.t & VT_BTYPE; |
1938 | bt=vtop->type.t & VT_BTYPE; |
- | 1939 | if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { |
|
- | 1940 | #ifndef TCC_ARM_VFP |
|
- | 1941 | uint32_t dsize = 0; |
|
1280 | if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) { |
1942 | #endif |
- | 1943 | r=intr(gv(RC_INT)); |
|
- | 1944 | #ifdef TCC_ARM_VFP |
|
- | 1945 | r2=vfpr(vtop->r=get_reg(RC_FLOAT)); |
|
- | 1946 | o(0xEE000A10|(r<<12)|(r2<<16)); /* fmsr */ |
|
- | 1947 | r2|=r2<<12; |
|
- | 1948 | if(!(vtop->type.t & VT_UNSIGNED)) |
|
- | 1949 | r2|=0x80; /* fuitoX -> fsituX */ |
|
- | 1950 | o(0xEEB80A40|r2|T2CPR(t)); /* fYitoX*/ |
|
1281 | r=intr(gv(RC_INT)); |
1951 | #else |
- | 1952 | r2=fpr(vtop->r=get_reg(RC_FLOAT)); |
|
- | 1953 | if((t & VT_BTYPE) != VT_FLOAT) |
|
1282 | r2=fpr(vtop->r=get_reg(RC_FLOAT)); |
1954 | dsize=0x80; /* flts -> fltd */ |
1283 | o(0xEE000190|(r2<<16)|(r<<12)); |
1955 | o(0xEE000110|dsize|(r2<<16)|(r<<12)); /* flts */ |
1284 | if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { |
1956 | if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) { |
1285 | unsigned int off=0; |
1957 | uint32_t off = 0; |
1286 | o(0xE3500000|(r<<12)); |
1958 | o(0xE3500000|(r<<12)); /* cmp */ |
1287 | r=fpr(get_reg(RC_FLOAT)); |
1959 | r=fpr(get_reg(RC_FLOAT)); |
1288 | if(last_itod_magic) { |
1960 | if(last_itod_magic) { |
1289 | off=ind+8-last_itod_magic; |
1961 | off=ind+8-last_itod_magic; |
1290 | off/=4; |
1962 | off/=4; |
1291 | if(off>255) |
1963 | if(off>255) |
1292 | off=0; |
1964 | off=0; |
1293 | } |
1965 | } |
1294 | o(0xBD1F8100|(r<<12)|off); |
1966 | o(0xBD1F0100|(r<<12)|off); /* ldflts */ |
1295 | if(!off) { |
1967 | if(!off) { |
1296 | o(0xEA000001); |
1968 | o(0xEA000000); /* b */ |
1297 | last_itod_magic=ind; |
1969 | last_itod_magic=ind; |
1298 | o(0x41F00000); |
- | |
1299 | o(0); |
1970 | o(0x4F800000); /* 4294967296.0f */ |
1300 | } |
1971 | } |
1301 | o(0xBE000180|(r2<<16)|(r2<<12)|r); |
1972 | o(0xBE000100|dsize|(r2<<16)|(r2<<12)|r); /* adflt */ |
- | 1973 | } |
|
1302 | } |
1974 | #endif |
1303 | return; |
1975 | return; |
1304 | } else if(bt == VT_LLONG) { |
1976 | } else if(bt == VT_LLONG) { |
- | 1977 | int func; |
|
- | 1978 | CType *func_type = 0; |
|
- | 1979 | if((t & VT_BTYPE) == VT_FLOAT) { |
|
1305 | int func; |
1980 | func_type = &func_float_type; |
1306 | if(vtop->type.t & VT_UNSIGNED) |
1981 | if(vtop->type.t & VT_UNSIGNED) |
1307 | func=TOK___ulltold; |
1982 | func=TOK___floatundisf; |
- | 1983 | else |
|
- | 1984 | func=TOK___floatdisf; |
|
- | 1985 | #if LDOUBLE_SIZE != 8 |
|
- | 1986 | } else if((t & VT_BTYPE) == VT_LDOUBLE) { |
|
- | 1987 | func_type = &func_ldouble_type; |
|
- | 1988 | if(vtop->type.t & VT_UNSIGNED) |
|
- | 1989 | func=TOK___floatundixf; |
|
- | 1990 | else |
|
- | 1991 | func=TOK___floatdixf; |
|
- | 1992 | } else if((t & VT_BTYPE) == VT_DOUBLE) { |
|
- | 1993 | #else |
|
- | 1994 | } else if((t & VT_BTYPE) == VT_DOUBLE || (t & VT_BTYPE) == VT_LDOUBLE) { |
|
- | 1995 | #endif |
|
- | 1996 | func_type = &func_double_type; |
|
- | 1997 | if(vtop->type.t & VT_UNSIGNED) |
|
- | 1998 | func=TOK___floatundidf; |
|
1308 | else |
1999 | else |
- | 2000 | func=TOK___floatdidf; |
|
- | 2001 | } |
|
1309 | func=TOK___slltold; |
2002 | if(func_type) { |
1310 | vpush_global_sym(&func_old_type, func); |
2003 | vpush_global_sym(func_type, func); |
1311 | vswap(); |
2004 | vswap(); |
1312 | gfunc_call(1); |
2005 | gfunc_call(1); |
1313 | vpushi(0); |
2006 | vpushi(0); |
1314 | vtop->r=TREG_F0; |
2007 | vtop->r=TREG_F0; |
1315 | return; |
2008 | return; |
- | 2009 | } |
|
1316 | } |
2010 | } |
1317 | error("unimplemented gen_cvt_itof %x!",vtop->type.t); |
2011 | tcc_error("unimplemented gen_cvt_itof %x!",vtop->type.t); |
Line 1318... | Line 2012... | ||
1318 | } |
2012 | } |
1319 | 2013 | ||
1320 | /* convert fp to int 't' type */ |
2014 | /* convert fp to int 't' type */ |
- | 2015 | void gen_cvt_ftoi(int t) |
|
1321 | void gen_cvt_ftoi(int t) |
2016 | { |
1322 | { |
2017 | uint32_t r, r2; |
1323 | int r,r2,u,func=0; |
2018 | int u, func = 0; |
1324 | u=t&VT_UNSIGNED; |
2019 | u=t&VT_UNSIGNED; |
1325 | t&=VT_BTYPE; |
2020 | t&=VT_BTYPE; |
- | 2021 | r2=vtop->type.t & VT_BTYPE; |
|
- | 2022 | if(t==VT_INT) { |
|
- | 2023 | #ifdef TCC_ARM_VFP |
|
- | 2024 | r=vfpr(gv(RC_FLOAT)); |
|
- | 2025 | u=u?0:0x10000; |
|
- | 2026 | o(0xEEBC0AC0|(r<<12)|r|T2CPR(r2)|u); /* ftoXizY */ |
|
- | 2027 | r2=intr(vtop->r=get_reg(RC_INT)); |
|
- | 2028 | o(0xEE100A10|(r<<16)|(r2<<12)); |
|
1326 | r2=vtop->type.t & VT_BTYPE; |
2029 | return; |
1327 | if(t==VT_INT) { |
2030 | #else |
1328 | if(u) { |
2031 | if(u) { |
1329 | if(r2 == VT_FLOAT) |
- | |
1330 | func=TOK___fixunssfsi; |
2032 | if(r2 == VT_FLOAT) |
1331 | else if(r2 == VT_DOUBLE) |
2033 | func=TOK___fixunssfsi; |
1332 | func=TOK___fixunsdfsi; |
- | |
1333 | else if(r2 == VT_LDOUBLE) |
- | |
1334 | #if LDOUBLE_SIZE == 8 |
- | |
1335 | func=TOK___fixunsdfsi; |
2034 | #if LDOUBLE_SIZE != 8 |
- | 2035 | else if(r2 == VT_LDOUBLE) |
|
- | 2036 | func=TOK___fixunsxfsi; |
|
- | 2037 | else if(r2 == VT_DOUBLE) |
|
1336 | #else |
2038 | #else |
- | 2039 | else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) |
|
1337 | func=TOK___fixunsxfsi; |
2040 | #endif |
1338 | #endif |
2041 | func=TOK___fixunsdfsi; |
1339 | } else { |
2042 | } else { |
1340 | r=fpr(gv(RC_FLOAT)); |
2043 | r=fpr(gv(RC_FLOAT)); |
1341 | r2=intr(vtop->r=get_reg(RC_INT)); |
2044 | r2=intr(vtop->r=get_reg(RC_INT)); |
1342 | o(0xEE100170|(r2<<12)|r); |
2045 | o(0xEE100170|(r2<<12)|r); |
- | 2046 | return; |
|
1343 | return; |
2047 | } |
1344 | } |
2048 | #endif |
1345 | } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 |
2049 | } else if(t == VT_LLONG) { // unsigned handled in gen_cvt_ftoi1 |
1346 | if(r2 == VT_FLOAT) |
- | |
1347 | func=TOK___fixsfdi; |
2050 | if(r2 == VT_FLOAT) |
1348 | else if(r2 == VT_DOUBLE) |
2051 | func=TOK___fixsfdi; |
1349 | func=TOK___fixdfdi; |
- | |
1350 | else if(r2 == VT_LDOUBLE) |
- | |
1351 | #if LDOUBLE_SIZE == 8 |
- | |
1352 | func=TOK___fixdfdi; |
2052 | #if LDOUBLE_SIZE != 8 |
- | 2053 | else if(r2 == VT_LDOUBLE) |
|
- | 2054 | func=TOK___fixxfdi; |
|
- | 2055 | else if(r2 == VT_DOUBLE) |
|
1353 | #else |
2056 | #else |
- | 2057 | else if(r2 == VT_LDOUBLE || r2 == VT_DOUBLE) |
|
1354 | func=TOK___fixxfdi; |
2058 | #endif |
1355 | #endif |
2059 | func=TOK___fixdfdi; |
1356 | } |
2060 | } |
1357 | if(func) { |
2061 | if(func) { |
1358 | vpush_global_sym(&func_old_type, func); |
2062 | vpush_global_sym(&func_old_type, func); |
Line 1362... | Line 2066... | ||
1362 | if(t == VT_LLONG) |
2066 | if(t == VT_LLONG) |
1363 | vtop->r2 = REG_LRET; |
2067 | vtop->r2 = REG_LRET; |
1364 | vtop->r = REG_IRET; |
2068 | vtop->r = REG_IRET; |
1365 | return; |
2069 | return; |
1366 | } |
2070 | } |
1367 | error("unimplemented gen_cvt_ftoi!"); |
2071 | tcc_error("unimplemented gen_cvt_ftoi!"); |
1368 | } |
2072 | } |
Line 1369... | Line 2073... | ||
1369 | 2073 | ||
1370 | /* convert from one floating point type to another */ |
2074 | /* convert from one floating point type to another */ |
1371 | void gen_cvt_ftof(int t) |
2075 | void gen_cvt_ftof(int t) |
- | 2076 | { |
|
- | 2077 | #ifdef TCC_ARM_VFP |
|
- | 2078 | if(((vtop->type.t & VT_BTYPE) == VT_FLOAT) != ((t & VT_BTYPE) == VT_FLOAT)) { |
|
- | 2079 | uint32_t r = vfpr(gv(RC_FLOAT)); |
|
- | 2080 | o(0xEEB70AC0|(r<<12)|r|T2CPR(vtop->type.t)); |
|
- | 2081 | } |
|
1372 | { |
2082 | #else |
1373 | /* all we have to do on i386 and ARM is to put the float in a register */ |
2083 | /* all we have to do on i386 and FPA ARM is to put the float in a register */ |
- | 2084 | gv(RC_FLOAT); |
|
1374 | gv(RC_FLOAT); |
2085 | #endif |
Line 1375... | Line 2086... | ||
1375 | } |
2086 | } |
1376 | 2087 | ||
1377 | /* computed goto support */ |
2088 | /* computed goto support */ |
1378 | void ggoto(void) |
2089 | void ggoto(void) |
1379 | { |
2090 | { |
1380 | gcall_or_jmp(1); |
2091 | gcall_or_jmp(1); |
Line -... | Line 2092... | ||
- | 2092 | vtop--; |
|
- | 2093 | } |
|
- | 2094 | ||
- | 2095 | /* Save the stack pointer onto the stack and return the location of its address */ |
|
- | 2096 | ST_FUNC void gen_vla_sp_save(int addr) { |
|
- | 2097 | tcc_error("variable length arrays unsupported for this target"); |
|
- | 2098 | } |
|
- | 2099 | ||
- | 2100 | /* Restore the SP from a location on the stack */ |
|
- | 2101 | ST_FUNC void gen_vla_sp_restore(int addr) { |
|
- | 2102 | tcc_error("variable length arrays unsupported for this target"); |
|
- | 2103 | } |
|
- | 2104 | ||
- | 2105 | /* Subtract from the stack pointer, and push the resulting value onto the stack */ |
|
- | 2106 | ST_FUNC void gen_vla_alloc(CType *type, int align) { |
|
1381 | vtop--; |
2107 | tcc_error("variable length arrays unsupported for this target"); |
1382 | } |
2108 | } |
1383 | 2109 | ||
- | 2110 | /* end of ARM code generator */ |