fix-mixed-struct (patch by Pip Cet)
[tinycc.git] / i386-gen.c
Commit [+]AuthorDateLineData
25618c04 bellard2001-12-13 22:28:53 +00001/*
2 * X86 code generator for TCC
3 *
c9c05ca5 bellard2004-10-27 21:38:03 +00004 * Copyright (c) 2001-2004 Fabrice Bellard
25618c04 bellard2001-12-13 22:28:53 +00005 *
8f5e44a4 bellard2003-05-24 14:11:17 +00006 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
25618c04 bellard2001-12-13 22:28:53 +000010 *
8f5e44a4 bellard2003-05-24 14:11:17 +000011 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
25618c04 bellard2001-12-13 22:28:53 +000015 *
8f5e44a4 bellard2003-05-24 14:11:17 +000016 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25618c04 bellard2001-12-13 22:28:53 +000019 */
39173894 bellard2001-12-12 21:16:34 +000020
88a3ccab grischka2009-12-20 01:53:49 +010021#ifdef TARGET_DEFS_ONLY
22
39173894 bellard2001-12-12 21:16:34 +000023/* number of available registers */
88a3ccab grischka2009-12-20 01:53:49 +010024#define NB_REGS 4
25#define NB_ASM_REGS 8
39173894 bellard2001-12-12 21:16:34 +000026
4e04f67c seyko2015-05-14 07:32:24 +030027typedef int RegArgs;
28
b7fed2f2 bellard2002-01-05 16:17:34 +000029/* a register can belong to several classes. The classes must be
30 sorted from more general to more precise (see gv2() code which does
31 assumptions on it). */
21c35b94 bellard2001-12-23 00:34:26 +000032#define RC_INT 0x0001 /* generic integer register */
33#define RC_FLOAT 0x0002 /* generic float register */
14658993 bellard2002-01-03 21:14:59 +000034#define RC_EAX 0x0004
b7fed2f2 bellard2002-01-05 16:17:34 +000035#define RC_ST0 0x0008
14658993 bellard2002-01-03 21:14:59 +000036#define RC_ECX 0x0010
37#define RC_EDX 0x0020
38#define RC_IRET RC_EAX /* function return: integer register */
39#define RC_LRET RC_EDX /* function return: second integer register */
b7fed2f2 bellard2002-01-05 16:17:34 +000040#define RC_FRET RC_ST0 /* function return: float register */
39173894 bellard2001-12-12 21:16:34 +000041
42/* pretty names for the registers */
43enum {
b5259da4 bellard2002-12-08 14:34:48 +000044 TREG_EAX = 0,
45 TREG_ECX,
46 TREG_EDX,
47 TREG_ST0,
41b3c7a5 James Lyon2013-04-27 20:39:34 +010048 TREG_ESP = 4
39173894 bellard2001-12-12 21:16:34 +000049};
50
21c35b94 bellard2001-12-23 00:34:26 +000051/* return registers for function */
b5259da4 bellard2002-12-08 14:34:48 +000052#define REG_IRET TREG_EAX /* single word int return register */
53#define REG_LRET TREG_EDX /* second word return register (for long long) */
54#define REG_FRET TREG_ST0 /* float return register */
39173894 bellard2001-12-12 21:16:34 +000055
56/* defined if function parameters must be evaluated in reverse order */
57#define INVERT_FUNC_PARAMS
58
59/* defined if structures are passed as pointers. Otherwise structures
60 are directly pushed on stack. */
0bdbd49e Urs Janssen2013-02-17 00:48:51 +010061/* #define FUNC_STRUCT_PARAM_AS_PTR */
39173894 bellard2001-12-12 21:16:34 +000062
25618c04 bellard2001-12-13 22:28:53 +000063/* pointer size, in bytes */
64#define PTR_SIZE 4
65
66/* long double size and alignment, in bytes */
67#define LDOUBLE_SIZE 12
68#define LDOUBLE_ALIGN 4
d1e7e264 bellard2002-11-24 15:58:50 +000069/* maximum alignment (for aligned attribute support) */
70#define MAX_ALIGN 8
25618c04 bellard2001-12-13 22:28:53 +000071
88a3ccab grischka2009-12-20 01:53:49 +010072
73#define psym oad
74
4df5bd2e bellard2003-10-14 22:15:56 +000075/******************************************************/
76/* ELF defines */
77
78#define EM_TCC_TARGET EM_386
79
6cd36b12 bellard2002-07-14 14:38:33 +000080/* relocation type for 32 bit data relocation */
4df5bd2e bellard2003-10-14 22:15:56 +000081#define R_DATA_32 R_386_32
5dadff3d Shinichiro Hamaji2009-07-19 06:42:23 +090082#define R_DATA_PTR R_386_32
4df5bd2e bellard2003-10-14 22:15:56 +000083#define R_JMP_SLOT R_386_JMP_SLOT
84#define R_COPY R_386_COPY
85
86#define ELF_START_ADDR 0x08048000
87#define ELF_PAGE_SIZE 0x1000
6cd36b12 bellard2002-07-14 14:38:33 +000088
39173894 bellard2001-12-12 21:16:34 +000089/******************************************************/
88a3ccab grischka2009-12-20 01:53:49 +010090#else /* ! TARGET_DEFS_ONLY */
91/******************************************************/
92#include "tcc.h"
93
94ST_DATA const int reg_classes[NB_REGS] = {
95 /* eax */ RC_INT | RC_EAX,
96 /* ecx */ RC_INT | RC_ECX,
97 /* edx */ RC_INT | RC_EDX,
98 /* st0 */ RC_FLOAT | RC_ST0,
99};
39173894 bellard2001-12-12 21:16:34 +0000100
a42941b1 bellard2002-07-27 14:06:11 +0000101static unsigned long func_sub_sp_offset;
621b3fc3 bellard2002-01-26 17:23:44 +0000102static int func_ret_sub;
7fa712e0 grischka2009-12-19 22:22:43 +0100103#ifdef CONFIG_TCC_BCHECK
acef4ff2 seyko2015-03-26 07:47:45 +0300104static addr_t func_bound_offset;
7fa712e0 grischka2009-12-19 22:22:43 +0100105#endif
14799da8 bellard2002-01-03 22:43:10 +0000106
4891761b bellard2002-08-18 13:19:18 +0000107/* XXX: make it faster ? */
88a3ccab grischka2009-12-20 01:53:49 +0100108ST_FUNC void g(int c)
39173894 bellard2001-12-12 21:16:34 +0000109{
4891761b bellard2002-08-18 13:19:18 +0000110 int ind1;
111 ind1 = ind + 1;
112 if (ind1 > cur_text_section->data_allocated)
113 section_realloc(cur_text_section, ind1);
a42941b1 bellard2002-07-27 14:06:11 +0000114 cur_text_section->data[ind] = c;
4891761b bellard2002-08-18 13:19:18 +0000115 ind = ind1;
39173894 bellard2001-12-12 21:16:34 +0000116}
117
88a3ccab grischka2009-12-20 01:53:49 +0100118ST_FUNC void o(unsigned int c)
39173894 bellard2001-12-12 21:16:34 +0000119{
120 while (c) {
121 g(c);
3bd3c71f bellard2004-10-04 22:06:22 +0000122 c = c >> 8;
39173894 bellard2001-12-12 21:16:34 +0000123 }
124}
125
88a3ccab grischka2009-12-20 01:53:49 +0100126ST_FUNC void gen_le16(int v)
1308e8eb grischka2009-12-19 22:08:37 +0100127{
128 g(v);
129 g(v >> 8);
130}
131
88a3ccab grischka2009-12-20 01:53:49 +0100132ST_FUNC void gen_le32(int c)
39173894 bellard2001-12-12 21:16:34 +0000133{
134 g(c);
135 g(c >> 8);
136 g(c >> 16);
137 g(c >> 24);
138}
139
39173894 bellard2001-12-12 21:16:34 +0000140/* output a symbol and patch all calls to it */
88a3ccab grischka2009-12-20 01:53:49 +0100141ST_FUNC void gsym_addr(int t, int a)
39173894 bellard2001-12-12 21:16:34 +0000142{
a42941b1 bellard2002-07-27 14:06:11 +0000143 int n, *ptr;
39173894 bellard2001-12-12 21:16:34 +0000144 while (t) {
a42941b1 bellard2002-07-27 14:06:11 +0000145 ptr = (int *)(cur_text_section->data + t);
146 n = *ptr; /* next value */
147 *ptr = a - t - 4;
39173894 bellard2001-12-12 21:16:34 +0000148 t = n;
149 }
150}
151
88a3ccab grischka2009-12-20 01:53:49 +0100152ST_FUNC void gsym(int t)
39173894 bellard2001-12-12 21:16:34 +0000153{
154 gsym_addr(t, ind);
155}
156
157/* psym is used to put an instruction with a data field which is a
158 reference to a symbol. It is in fact the same as oad ! */
159#define psym oad
160
161/* instruction + 4 bytes data. Return the address of the data */
88a3ccab grischka2009-12-20 01:53:49 +0100162ST_FUNC int oad(int c, int s)
39173894 bellard2001-12-12 21:16:34 +0000163{
4891761b bellard2002-08-18 13:19:18 +0000164 int ind1;
165
39173894 bellard2001-12-12 21:16:34 +0000166 o(c);
4891761b bellard2002-08-18 13:19:18 +0000167 ind1 = ind + 4;
168 if (ind1 > cur_text_section->data_allocated)
169 section_realloc(cur_text_section, ind1);
a42941b1 bellard2002-07-27 14:06:11 +0000170 *(int *)(cur_text_section->data + ind) = s;
39173894 bellard2001-12-12 21:16:34 +0000171 s = ind;
4891761b bellard2002-08-18 13:19:18 +0000172 ind = ind1;
39173894 bellard2001-12-12 21:16:34 +0000173 return s;
174}
175
6cd36b12 bellard2002-07-14 14:38:33 +0000176/* output constant with relocation if 'r & VT_SYM' is true */
88a3ccab grischka2009-12-20 01:53:49 +0100177ST_FUNC void gen_addr32(int r, Sym *sym, int c)
39173894 bellard2001-12-12 21:16:34 +0000178{
d2115bfb bellard2002-08-29 23:05:59 +0000179 if (r & VT_SYM)
180 greloc(cur_text_section, sym, ind, R_386_32);
181 gen_le32(c);
39173894 bellard2001-12-12 21:16:34 +0000182}
183
88a3ccab grischka2009-12-20 01:53:49 +0100184ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
1308e8eb grischka2009-12-19 22:08:37 +0100185{
186 if (r & VT_SYM)
187 greloc(cur_text_section, sym, ind, R_386_PC32);
188 gen_le32(c - 4);
189}
190
21c35b94 bellard2001-12-23 00:34:26 +0000191/* generate a modrm reference. 'op_reg' contains the addtionnal 3
192 opcode bits */
d2115bfb bellard2002-08-29 23:05:59 +0000193static void gen_modrm(int op_reg, int r, Sym *sym, int c)
21c35b94 bellard2001-12-23 00:34:26 +0000194{
195 op_reg = op_reg << 3;
196 if ((r & VT_VALMASK) == VT_CONST) {
197 /* constant memory reference */
198 o(0x05 | op_reg);
d2115bfb bellard2002-08-29 23:05:59 +0000199 gen_addr32(r, sym, c);
21c35b94 bellard2001-12-23 00:34:26 +0000200 } else if ((r & VT_VALMASK) == VT_LOCAL) {
201 /* currently, we use only ebp as base */
202 if (c == (char)c) {
203 /* short reference */
204 o(0x45 | op_reg);
205 g(c);
206 } else {
207 oad(0x85 | op_reg, c);
208 }
209 } else {
210 g(0x00 | op_reg | (r & VT_VALMASK));
211 }
212}
213
f7181903 bellard2001-12-20 01:05:21 +0000214/* load 'r' from value 'sv' */
88a3ccab grischka2009-12-20 01:53:49 +0100215ST_FUNC void load(int r, SValue *sv)
39173894 bellard2001-12-12 21:16:34 +0000216{
f7181903 bellard2001-12-20 01:05:21 +0000217 int v, t, ft, fc, fr;
218 SValue v1;
39173894 bellard2001-12-12 21:16:34 +0000219
5b113f3e grischka2009-11-13 17:14:05 +0100220#ifdef TCC_TARGET_PE
2341ee51 grischka2010-01-14 20:55:51 +0100221 SValue v2;
222 sv = pe_getimport(sv, &v2);
5b113f3e grischka2009-11-13 17:14:05 +0100223#endif
2341ee51 grischka2010-01-14 20:55:51 +0100224
f7181903 bellard2001-12-20 01:05:21 +0000225 fr = sv->r;
9620fd18 bellard2002-11-18 21:46:44 +0000226 ft = sv->type.t;
f7181903 bellard2001-12-20 01:05:21 +0000227 fc = sv->c.ul;
228
229 v = fr & VT_VALMASK;
230 if (fr & VT_LVAL) {
39173894 bellard2001-12-12 21:16:34 +0000231 if (v == VT_LLOCAL) {
9620fd18 bellard2002-11-18 21:46:44 +0000232 v1.type.t = VT_INT;
f7181903 bellard2001-12-20 01:05:21 +0000233 v1.r = VT_LOCAL | VT_LVAL;
234 v1.c.ul = fc;
21c35b94 bellard2001-12-23 00:34:26 +0000235 fr = r;
9527c494
DG
Daniel Glöckner2012-01-23 01:41:36 +0100236 if (!(reg_classes[fr] & RC_INT))
237 fr = get_reg(RC_INT);
238 load(fr, &v1);
39173894 bellard2001-12-12 21:16:34 +0000239 }
240 if ((ft & VT_BTYPE) == VT_FLOAT) {
241 o(0xd9); /* flds */
242 r = 0;
243 } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
244 o(0xdd); /* fldl */
245 r = 0;
25618c04 bellard2001-12-13 22:28:53 +0000246 } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
247 o(0xdb); /* fldt */
248 r = 5;
f6b50558 Thomas Preud'homme2013-06-14 16:18:16 +0200249 } else if ((ft & VT_TYPE) == VT_BYTE || (ft & VT_TYPE) == VT_BOOL) {
39173894 bellard2001-12-12 21:16:34 +0000250 o(0xbe0f); /* movsbl */
264dbcfe bellard2002-07-13 15:55:16 +0000251 } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
39173894 bellard2001-12-12 21:16:34 +0000252 o(0xb60f); /* movzbl */
264dbcfe bellard2002-07-13 15:55:16 +0000253 } else if ((ft & VT_TYPE) == VT_SHORT) {
39173894 bellard2001-12-12 21:16:34 +0000254 o(0xbf0f); /* movswl */
264dbcfe bellard2002-07-13 15:55:16 +0000255 } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
39173894 bellard2001-12-12 21:16:34 +0000256 o(0xb70f); /* movzwl */
264dbcfe bellard2002-07-13 15:55:16 +0000257 } else {
39173894 bellard2001-12-12 21:16:34 +0000258 o(0x8b); /* movl */
264dbcfe bellard2002-07-13 15:55:16 +0000259 }
d2115bfb bellard2002-08-29 23:05:59 +0000260 gen_modrm(r, fr, sv->sym, fc);
39173894 bellard2001-12-12 21:16:34 +0000261 } else {
262 if (v == VT_CONST) {
263 o(0xb8 + r); /* mov $xx, r */
d2115bfb bellard2002-08-29 23:05:59 +0000264 gen_addr32(fr, sv->sym, fc);
39173894 bellard2001-12-12 21:16:34 +0000265 } else if (v == VT_LOCAL) {
ab24aaec
KS
Kirill Smelkov2012-11-16 00:04:56 +0400266 if (fc) {
267 o(0x8d); /* lea xxx(%ebp), r */
268 gen_modrm(r, VT_LOCAL, sv->sym, fc);
269 } else {
270 o(0x89);
271 o(0xe8 + r); /* mov %ebp, r */
272 }
39173894 bellard2001-12-12 21:16:34 +0000273 } else if (v == VT_CMP) {
274 oad(0xb8 + r, 0); /* mov $0, r */
275 o(0x0f); /* setxx %br */
276 o(fc);
277 o(0xc0 + r);
278 } else if (v == VT_JMP || v == VT_JMPI) {
279 t = v & 1;
280 oad(0xb8 + r, t); /* mov $1, r */
3748975f bellard2002-09-08 22:06:11 +0000281 o(0x05eb); /* jmp after */
39173894 bellard2001-12-12 21:16:34 +0000282 gsym(fc);
283 oad(0xb8 + r, t ^ 1); /* mov $0, r */
284 } else if (v != r) {
285 o(0x89);
286 o(0xc0 + r + v * 8); /* mov v, r */
287 }
288 }
289}
290
f7181903 bellard2001-12-20 01:05:21 +0000291/* store register 'r' in lvalue 'v' */
88a3ccab grischka2009-12-20 01:53:49 +0100292ST_FUNC void store(int r, SValue *v)
39173894 bellard2001-12-12 21:16:34 +0000293{
f7181903 bellard2001-12-20 01:05:21 +0000294 int fr, bt, ft, fc;
39173894 bellard2001-12-12 21:16:34 +0000295
5b113f3e grischka2009-11-13 17:14:05 +0100296#ifdef TCC_TARGET_PE
2341ee51 grischka2010-01-14 20:55:51 +0100297 SValue v2;
298 v = pe_getimport(v, &v2);
5b113f3e grischka2009-11-13 17:14:05 +0100299#endif
2341ee51 grischka2010-01-14 20:55:51 +0100300
9620fd18 bellard2002-11-18 21:46:44 +0000301 ft = v->type.t;
f7181903 bellard2001-12-20 01:05:21 +0000302 fc = v->c.ul;
303 fr = v->r & VT_VALMASK;
39173894 bellard2001-12-12 21:16:34 +0000304 bt = ft & VT_BTYPE;
21c35b94 bellard2001-12-23 00:34:26 +0000305 /* XXX: incorrect if float reg to reg */
39173894 bellard2001-12-12 21:16:34 +0000306 if (bt == VT_FLOAT) {
2694c105 bellard2001-12-17 21:56:48 +0000307 o(0xd9); /* fsts */
308 r = 2;
39173894 bellard2001-12-12 21:16:34 +0000309 } else if (bt == VT_DOUBLE) {
310 o(0xdd); /* fstpl */
2694c105 bellard2001-12-17 21:56:48 +0000311 r = 2;
25618c04 bellard2001-12-13 22:28:53 +0000312 } else if (bt == VT_LDOUBLE) {
2694c105 bellard2001-12-17 21:56:48 +0000313 o(0xc0d9); /* fld %st(0) */
25618c04 bellard2001-12-13 22:28:53 +0000314 o(0xdb); /* fstpt */
315 r = 7;
39173894 bellard2001-12-12 21:16:34 +0000316 } else {
317 if (bt == VT_SHORT)
318 o(0x66);
09f4ce98 bellard2005-04-17 13:15:31 +0000319 if (bt == VT_BYTE || bt == VT_BOOL)
39173894 bellard2001-12-12 21:16:34 +0000320 o(0x88);
321 else
322 o(0x89);
323 }
21c35b94 bellard2001-12-23 00:34:26 +0000324 if (fr == VT_CONST ||
325 fr == VT_LOCAL ||
326 (v->r & VT_LVAL)) {
d2115bfb bellard2002-08-29 23:05:59 +0000327 gen_modrm(r, v->r, v->sym, fc);
39173894 bellard2001-12-12 21:16:34 +0000328 } else if (fr != r) {
329 o(0xc0 + fr + r * 8); /* mov r, fr */
330 }
331}
332
58af3a6c bellard2002-07-24 22:11:30 +0000333static void gadd_sp(int val)
334{
335 if (val == (char)val) {
336 o(0xc483);
337 g(val);
338 } else {
339 oad(0xc481, val); /* add $xxx, %esp */
340 }
341}
342
73faaea2 grischka2013-08-28 22:55:05 +0200343static void gen_static_call(int v)
344{
345 Sym *sym;
346
347 sym = external_global_sym(v, &func_old_type, 0);
348 oad(0xe8, -4);
349 greloc(cur_text_section, sym, ind-4, R_386_PC32);
350}
351
fde824b7 bellard2002-11-03 00:43:01 +0000352/* 'is_jmp' is '1' if it is a jump */
353static void gcall_or_jmp(int is_jmp)
39173894 bellard2001-12-12 21:16:34 +0000354{
355 int r;
f7181903 bellard2001-12-20 01:05:21 +0000356 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
39173894 bellard2001-12-12 21:16:34 +0000357 /* constant case */
6cd36b12 bellard2002-07-14 14:38:33 +0000358 if (vtop->r & VT_SYM) {
359 /* relocation case */
d2115bfb bellard2002-08-29 23:05:59 +0000360 greloc(cur_text_section, vtop->sym,
a42941b1 bellard2002-07-27 14:06:11 +0000361 ind + 1, R_386_PC32);
39173894 bellard2001-12-12 21:16:34 +0000362 } else {
431d6480 bellard2002-08-31 12:42:16 +0000363 /* put an empty PC32 relocation */
364 put_elf_reloc(symtab_section, cur_text_section,
365 ind + 1, R_386_PC32, 0);
39173894 bellard2001-12-12 21:16:34 +0000366 }
fde824b7 bellard2002-11-03 00:43:01 +0000367 oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
39173894 bellard2001-12-12 21:16:34 +0000368 } else {
369 /* otherwise, indirect call */
21c35b94 bellard2001-12-23 00:34:26 +0000370 r = gv(RC_INT);
fde824b7 bellard2002-11-03 00:43:01 +0000371 o(0xff); /* call/jmp *r */
372 o(0xd0 + r + (is_jmp << 4));
39173894 bellard2001-12-12 21:16:34 +0000373 }
fde824b7 bellard2002-11-03 00:43:01 +0000374}
375
72a88fba bellard2004-10-18 00:14:40 +0000376static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
e9c64e3f bellard2005-09-03 22:21:22 +0000377static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX };
72a88fba bellard2004-10-18 00:14:40 +0000378
4e04f67c seyko2015-05-14 07:32:24 +0300379ST_FUNC int regargs_nregs(RegArgs *args)
380{
381 return *args;
382}
383
dcec8673
TP
Thomas Preud'homme2013-11-22 09:27:15 +0800384/* Return the number of registers needed to return the struct, or 0 if
385 returning via struct pointer. */
4e04f67c seyko2015-05-14 07:32:24 +0300386ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize, RegArgs *args)
be1b6ba7 grischka2013-04-30 00:33:34 +0200387{
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100388#ifdef TCC_TARGET_PE
389 int size, align;
be1b6ba7 grischka2013-04-30 00:33:34 +0200390
391 *ret_align = 1; // Never have to re-align return values for x86
50899e30 Michael Matz2015-03-09 00:19:59 +0100392 *regsize = 4;
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100393 size = type_size(vt, &align);
394 if (size > 8) {
4e04f67c seyko2015-05-14 07:32:24 +0300395 *args = 0;
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100396 } else if (size > 4) {
397 ret->ref = NULL;
398 ret->t = VT_LLONG;
4e04f67c seyko2015-05-14 07:32:24 +0300399 *args = 1;
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100400 } else {
401 ret->ref = NULL;
402 ret->t = VT_INT;
4e04f67c seyko2015-05-14 07:32:24 +0300403 *args = 1;
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100404 }
405#else
be1b6ba7 grischka2013-04-30 00:33:34 +0200406 *ret_align = 1; // Never have to re-align return values for x86
4e04f67c seyko2015-05-14 07:32:24 +0300407 *args = 0;
2bbfaf43 James Lyon2013-04-18 17:27:34 +0100408#endif
4e04f67c seyko2015-05-14 07:32:24 +0300409
410 return *args != 0;
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100411}
412
214cccce bellard2003-04-16 21:16:20 +0000413/* Generate function call. The function address is pushed first, then
414 all the parameters in call order. This functions pops all the
415 parameters and the function address. */
88a3ccab grischka2009-12-20 01:53:49 +0100416ST_FUNC void gfunc_call(int nb_args)
fde824b7 bellard2002-11-03 00:43:01 +0000417{
72a88fba bellard2004-10-18 00:14:40 +0000418 int size, align, r, args_size, i, func_call;
214cccce bellard2003-04-16 21:16:20 +0000419 Sym *func_sym;
420
421 args_size = 0;
422 for(i = 0;i < nb_args; i++) {
423 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
424 size = type_size(&vtop->type, &align);
425 /* align to stack align size */
426 size = (size + 3) & ~3;
427 /* allocate the necessary size on stack */
428 oad(0xec81, size); /* sub $xxx, %esp */
429 /* generate structure store */
430 r = get_reg(RC_INT);
431 o(0x89); /* mov %esp, r */
432 o(0xe0 + r);
433 vset(&vtop->type, r | VT_LVAL, 0);
434 vswap();
435 vstore();
436 args_size += size;
437 } else if (is_float(vtop->type.t)) {
438 gv(RC_FLOAT); /* only one float register */
439 if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
440 size = 4;
441 else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
442 size = 8;
443 else
444 size = 12;
445 oad(0xec81, size); /* sub $xxx, %esp */
446 if (size == 12)
447 o(0x7cdb);
448 else
449 o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
450 g(0x24);
451 g(0x00);
452 args_size += size;
453 } else {
454 /* simple type (currently always same size) */
455 /* XXX: implicit cast ? */
456 r = gv(RC_INT);
457 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
458 size = 8;
459 o(0x50 + vtop->r2); /* push r */
460 } else {
461 size = 4;
462 }
463 o(0x50 + r); /* push r */
464 args_size += size;
465 }
466 vtop--;
467 }
468 save_regs(0); /* save used temporary registers */
469 func_sym = vtop->type.ref;
3fe2a95d grischka2014-01-07 14:57:07 +0100470 func_call = func_sym->a.func_call;
72a88fba bellard2004-10-18 00:14:40 +0000471 /* fast call case */
e9c64e3f bellard2005-09-03 22:21:22 +0000472 if ((func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) ||
473 func_call == FUNC_FASTCALLW) {
72a88fba bellard2004-10-18 00:14:40 +0000474 int fastcall_nb_regs;
e9c64e3f bellard2005-09-03 22:21:22 +0000475 uint8_t *fastcall_regs_ptr;
476 if (func_call == FUNC_FASTCALLW) {
477 fastcall_regs_ptr = fastcallw_regs;
478 fastcall_nb_regs = 2;
479 } else {
480 fastcall_regs_ptr = fastcall_regs;
481 fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
482 }
72a88fba bellard2004-10-18 00:14:40 +0000483 for(i = 0;i < fastcall_nb_regs; i++) {
484 if (args_size <= 0)
485 break;
e9c64e3f bellard2005-09-03 22:21:22 +0000486 o(0x58 + fastcall_regs_ptr[i]); /* pop r */
72a88fba bellard2004-10-18 00:14:40 +0000487 /* XXX: incorrect for struct/floats */
488 args_size -= 4;
489 }
490 }
ae2ece93
JL
James Lyon2013-04-26 00:31:46 +0100491#ifndef TCC_TARGET_PE
492 else if ((vtop->type.ref->type.t & VT_BTYPE) == VT_STRUCT)
493 args_size -= 4;
494#endif
fde824b7 bellard2002-11-03 00:43:01 +0000495 gcall_or_jmp(0);
610fd475 grischka2009-06-17 02:11:13 +0200496
5342b32e grischka2007-12-19 17:36:42 +0000497 if (args_size && func_call != FUNC_STDCALL)
214cccce bellard2003-04-16 21:16:20 +0000498 gadd_sp(args_size);
fbc51a39 bellard2001-12-16 17:58:32 +0000499 vtop--;
39173894 bellard2001-12-12 21:16:34 +0000500}
501
9825011c bellard2005-04-10 22:15:08 +0000502#ifdef TCC_TARGET_PE
503#define FUNC_PROLOG_SIZE 10
504#else
505#define FUNC_PROLOG_SIZE 9
506#endif
507
14799da8 bellard2002-01-03 22:43:10 +0000508/* generate function prolog of type 't' */
88a3ccab grischka2009-12-20 01:53:49 +0100509ST_FUNC void gfunc_prolog(CType *func_type)
14799da8 bellard2002-01-03 22:43:10 +0000510{
72a88fba bellard2004-10-18 00:14:40 +0000511 int addr, align, size, func_call, fastcall_nb_regs;
512 int param_index, param_addr;
e9c64e3f bellard2005-09-03 22:21:22 +0000513 uint8_t *fastcall_regs_ptr;
14799da8 bellard2002-01-03 22:43:10 +0000514 Sym *sym;
9620fd18 bellard2002-11-18 21:46:44 +0000515 CType *type;
14799da8 bellard2002-01-03 22:43:10 +0000516
9620fd18 bellard2002-11-18 21:46:44 +0000517 sym = func_type->ref;
3fe2a95d grischka2014-01-07 14:57:07 +0100518 func_call = sym->a.func_call;
14799da8 bellard2002-01-03 22:43:10 +0000519 addr = 8;
72a88fba bellard2004-10-18 00:14:40 +0000520 loc = 0;
610fd475 grischka2009-06-17 02:11:13 +0200521 func_vc = 0;
522
72a88fba bellard2004-10-18 00:14:40 +0000523 if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
524 fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
e9c64e3f bellard2005-09-03 22:21:22 +0000525 fastcall_regs_ptr = fastcall_regs;
526 } else if (func_call == FUNC_FASTCALLW) {
527 fastcall_nb_regs = 2;
528 fastcall_regs_ptr = fastcallw_regs;
72a88fba bellard2004-10-18 00:14:40 +0000529 } else {
530 fastcall_nb_regs = 0;
e9c64e3f bellard2005-09-03 22:21:22 +0000531 fastcall_regs_ptr = NULL;
72a88fba bellard2004-10-18 00:14:40 +0000532 }
533 param_index = 0;
534
9825011c bellard2005-04-10 22:15:08 +0000535 ind += FUNC_PROLOG_SIZE;
536 func_sub_sp_offset = ind;
14799da8 bellard2002-01-03 22:43:10 +0000537 /* if the function returns a structure, then add an
538 implicit pointer parameter */
9620fd18 bellard2002-11-18 21:46:44 +0000539 func_vt = sym->type;
8efaa711 Thomas Preud'homme2014-01-06 22:27:39 +0800540 func_var = (sym->c == FUNC_ELLIPSIS);
2bbfaf43
JL
James Lyon2013-04-18 17:27:34 +0100541#ifdef TCC_TARGET_PE
542 size = type_size(&func_vt,&align);
543 if (((func_vt.t & VT_BTYPE) == VT_STRUCT) && (size > 8)) {
544#else
9620fd18 bellard2002-11-18 21:46:44 +0000545 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
2bbfaf43 James Lyon2013-04-18 17:27:34 +0100546#endif
72a88fba bellard2004-10-18 00:14:40 +0000547 /* XXX: fastcall case ? */
14799da8 bellard2002-01-03 22:43:10 +0000548 func_vc = addr;
549 addr += 4;
72a88fba bellard2004-10-18 00:14:40 +0000550 param_index++;
14799da8 bellard2002-01-03 22:43:10 +0000551 }
552 /* define parameters */
553 while ((sym = sym->next) != NULL) {
9620fd18 bellard2002-11-18 21:46:44 +0000554 type = &sym->type;
9620fd18 bellard2002-11-18 21:46:44 +0000555 size = type_size(type, &align);
14799da8 bellard2002-01-03 22:43:10 +0000556 size = (size + 3) & ~3;
557#ifdef FUNC_STRUCT_PARAM_AS_PTR
558 /* structs are passed as pointer */
9620fd18 bellard2002-11-18 21:46:44 +0000559 if ((type->t & VT_BTYPE) == VT_STRUCT) {
14799da8 bellard2002-01-03 22:43:10 +0000560 size = 4;
561 }
562#endif
72a88fba bellard2004-10-18 00:14:40 +0000563 if (param_index < fastcall_nb_regs) {
564 /* save FASTCALL register */
565 loc -= 4;
566 o(0x89); /* movl */
e9c64e3f bellard2005-09-03 22:21:22 +0000567 gen_modrm(fastcall_regs_ptr[param_index], VT_LOCAL, NULL, loc);
72a88fba bellard2004-10-18 00:14:40 +0000568 param_addr = loc;
569 } else {
570 param_addr = addr;
571 addr += size;
572 }
573 sym_push(sym->v & ~SYM_FIELD, type,
2c657f66 Daniel Glöckner2008-08-20 01:44:12 +0200574 VT_LOCAL | lvalue_type(type->t), param_addr);
72a88fba bellard2004-10-18 00:14:40 +0000575 param_index++;
14799da8 bellard2002-01-03 22:43:10 +0000576 }
621b3fc3 bellard2002-01-26 17:23:44 +0000577 func_ret_sub = 0;
578 /* pascal type call ? */
579 if (func_call == FUNC_STDCALL)
580 func_ret_sub = addr - 8;
ae2ece93
JL
James Lyon2013-04-26 00:31:46 +0100581#ifndef TCC_TARGET_PE
582 else if (func_vc)
583 func_ret_sub = 4;
584#endif
72a88fba bellard2004-10-18 00:14:40 +0000585
7fa712e0 grischka2009-12-19 22:22:43 +0100586#ifdef CONFIG_TCC_BCHECK
b7fed2f2 bellard2002-01-05 16:17:34 +0000587 /* leave some room for bound checking code */
f9181416 grischka2009-05-11 18:45:44 +0200588 if (tcc_state->do_bounds_check) {
b7fed2f2 bellard2002-01-05 16:17:34 +0000589 oad(0xb8, 0); /* lbound section pointer */
590 oad(0xb8, 0); /* call to function */
a42941b1 bellard2002-07-27 14:06:11 +0000591 func_bound_offset = lbounds_section->data_offset;
b7fed2f2 bellard2002-01-05 16:17:34 +0000592 }
7fa712e0 grischka2009-12-19 22:22:43 +0100593#endif
14799da8 bellard2002-01-03 22:43:10 +0000594}
595
596/* generate function epilog */
88a3ccab grischka2009-12-20 01:53:49 +0100597ST_FUNC void gfunc_epilog(void)
14799da8 bellard2002-01-03 22:43:10 +0000598{
acef4ff2 seyko2015-03-26 07:47:45 +0300599 addr_t v, saved_ind;
9825011c bellard2005-04-10 22:15:08 +0000600
4226681d bellard2002-03-03 22:45:55 +0000601#ifdef CONFIG_TCC_BCHECK
f9181416 grischka2009-05-11 18:45:44 +0200602 if (tcc_state->do_bounds_check
603 && func_bound_offset != lbounds_section->data_offset) {
acef4ff2 seyko2015-03-26 07:47:45 +0300604 addr_t saved_ind;
605 addr_t *bounds_ptr;
73faaea2 grischka2013-08-28 22:55:05 +0200606 Sym *sym_data;
b7fed2f2 bellard2002-01-05 16:17:34 +0000607 /* add end of table info */
acef4ff2 seyko2015-03-26 07:47:45 +0300608 bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t));
a42941b1 bellard2002-07-27 14:06:11 +0000609 *bounds_ptr = 0;
b7fed2f2 bellard2002-01-05 16:17:34 +0000610 /* generate bound local allocation */
611 saved_ind = ind;
9825011c bellard2005-04-10 22:15:08 +0000612 ind = func_sub_sp_offset;
9620fd18 bellard2002-11-18 21:46:44 +0000613 sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
a42941b1 bellard2002-07-27 14:06:11 +0000614 func_bound_offset, lbounds_section->data_offset);
58af3a6c bellard2002-07-24 22:11:30 +0000615 greloc(cur_text_section, sym_data,
a42941b1 bellard2002-07-27 14:06:11 +0000616 ind + 1, R_386_32);
58af3a6c bellard2002-07-24 22:11:30 +0000617 oad(0xb8, 0); /* mov %eax, xxx */
73faaea2 grischka2013-08-28 22:55:05 +0200618 gen_static_call(TOK___bound_local_new);
619
b7fed2f2 bellard2002-01-05 16:17:34 +0000620 ind = saved_ind;
621 /* generate bound check local freeing */
622 o(0x5250); /* save returned value, if any */
58af3a6c bellard2002-07-24 22:11:30 +0000623 greloc(cur_text_section, sym_data,
a42941b1 bellard2002-07-27 14:06:11 +0000624 ind + 1, R_386_32);
58af3a6c bellard2002-07-24 22:11:30 +0000625 oad(0xb8, 0); /* mov %eax, xxx */
73faaea2 grischka2013-08-28 22:55:05 +0200626 gen_static_call(TOK___bound_local_delete);
627
b7fed2f2 bellard2002-01-05 16:17:34 +0000628 o(0x585a); /* restore returned value, if any */
629 }
4226681d bellard2002-03-03 22:45:55 +0000630#endif
621b3fc3 bellard2002-01-26 17:23:44 +0000631 o(0xc9); /* leave */
632 if (func_ret_sub == 0) {
633 o(0xc3); /* ret */
634 } else {
635 o(0xc2); /* ret n */
636 g(func_ret_sub);
637 g(func_ret_sub >> 8);
638 }
b7fed2f2 bellard2002-01-05 16:17:34 +0000639 /* align local size to word & save local variables */
9825011c bellard2005-04-10 22:15:08 +0000640
641 v = (-loc + 3) & -4;
642 saved_ind = ind;
643 ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
644#ifdef TCC_TARGET_PE
645 if (v >= 4096) {
9825011c bellard2005-04-10 22:15:08 +0000646 oad(0xb8, v); /* mov stacksize, %eax */
73faaea2 grischka2013-08-28 22:55:05 +0200647 gen_static_call(TOK___chkstk); /* call __chkstk, (does the stackframe too) */
9825011c bellard2005-04-10 22:15:08 +0000648 } else
649#endif
650 {
651 o(0xe58955); /* push %ebp, mov %esp, %ebp */
652 o(0xec81); /* sub esp, stacksize */
653 gen_le32(v);
654#if FUNC_PROLOG_SIZE == 10
655 o(0x90); /* adjust to FUNC_PROLOG_SIZE */
656#endif
657 }
658 ind = saved_ind;
14799da8 bellard2002-01-03 22:43:10 +0000659}
660
421911f9 bellard2002-02-10 16:13:14 +0000661/* generate a jump to a label */
88a3ccab grischka2009-12-20 01:53:49 +0100662ST_FUNC int gjmp(int t)
39173894 bellard2001-12-12 21:16:34 +0000663{
664 return psym(0xe9, t);
665}
666
421911f9 bellard2002-02-10 16:13:14 +0000667/* generate a jump to a fixed address */
88a3ccab grischka2009-12-20 01:53:49 +0100668ST_FUNC void gjmp_addr(int a)
421911f9 bellard2002-02-10 16:13:14 +0000669{
3748975f bellard2002-09-08 22:06:11 +0000670 int r;
671 r = a - ind - 2;
672 if (r == (char)r) {
673 g(0xeb);
674 g(r);
675 } else {
676 oad(0xe9, a - ind - 5);
677 }
421911f9 bellard2002-02-10 16:13:14 +0000678}
679
fbc51a39 bellard2001-12-16 17:58:32 +0000680/* generate a test. set 'inv' to invert test. Stack entry is popped */
88a3ccab grischka2009-12-20 01:53:49 +0100681ST_FUNC int gtst(int inv, int t)
39173894 bellard2001-12-12 21:16:34 +0000682{
683 int v, *p;
d1e7e264 bellard2002-11-24 15:58:50 +0000684
f7181903 bellard2001-12-20 01:05:21 +0000685 v = vtop->r & VT_VALMASK;
39173894 bellard2001-12-12 21:16:34 +0000686 if (v == VT_CMP) {
687 /* fast case : can jump directly since flags are set */
688 g(0x0f);
2694c105 bellard2001-12-17 21:56:48 +0000689 t = psym((vtop->c.i - 16) ^ inv, t);
2437ccdc seyko2015-03-03 15:51:09 +0300690 } else if (v == VT_JMP || v == VT_JMPI) {
39173894 bellard2001-12-12 21:16:34 +0000691 /* && or || optimization */
692 if ((v & 1) == inv) {
fbc51a39 bellard2001-12-16 17:58:32 +0000693 /* insert vtop->c jump list in t */
2694c105 bellard2001-12-17 21:56:48 +0000694 p = &vtop->c.i;
39173894 bellard2001-12-12 21:16:34 +0000695 while (*p != 0)
a42941b1 bellard2002-07-27 14:06:11 +0000696 p = (int *)(cur_text_section->data + *p);
39173894 bellard2001-12-12 21:16:34 +0000697 *p = t;
2694c105 bellard2001-12-17 21:56:48 +0000698 t = vtop->c.i;
39173894 bellard2001-12-12 21:16:34 +0000699 } else {
700 t = gjmp(t);
2694c105 bellard2001-12-17 21:56:48 +0000701 gsym(vtop->c.i);
39173894 bellard2001-12-12 21:16:34 +0000702 }
39173894 bellard2001-12-12 21:16:34 +0000703 }
fbc51a39 bellard2001-12-16 17:58:32 +0000704 vtop--;
39173894 bellard2001-12-12 21:16:34 +0000705 return t;
706}
707
fbc51a39 bellard2001-12-16 17:58:32 +0000708/* generate an integer binary operation */
88a3ccab grischka2009-12-20 01:53:49 +0100709ST_FUNC void gen_opi(int op)
39173894 bellard2001-12-12 21:16:34 +0000710{
14658993 bellard2002-01-03 21:14:59 +0000711 int r, fr, opc, c;
fbc51a39 bellard2001-12-16 17:58:32 +0000712
14658993 bellard2002-01-03 21:14:59 +0000713 switch(op) {
714 case '+':
715 case TOK_ADDC1: /* add with carry generation */
716 opc = 0;
717 gen_op8:
6cd36b12 bellard2002-07-14 14:38:33 +0000718 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
14658993 bellard2002-01-03 21:14:59 +0000719 /* constant case */
b7fed2f2 bellard2002-01-05 16:17:34 +0000720 vswap();
721 r = gv(RC_INT);
722 vswap();
14658993 bellard2002-01-03 21:14:59 +0000723 c = vtop->c.i;
724 if (c == (char)c) {
d3c43224
U
U-UNIT1\dennis2010-04-03 21:20:34 +0300725 /* generate inc and dec for smaller code */
726 if (c==1 && opc==0) {
727 o (0x40 | r); // inc
728 } else if (c==1 && opc==5) {
729 o (0x48 | r); // dec
730 } else {
731 o(0x83);
732 o(0xc0 | (opc << 3) | r);
733 g(c);
734 }
14658993 bellard2002-01-03 21:14:59 +0000735 } else {
736 o(0x81);
737 oad(0xc0 | (opc << 3) | r, c);
738 }
739 } else {
b7fed2f2 bellard2002-01-05 16:17:34 +0000740 gv2(RC_INT, RC_INT);
741 r = vtop[-1].r;
742 fr = vtop[0].r;
14658993 bellard2002-01-03 21:14:59 +0000743 o((opc << 3) | 0x01);
744 o(0xc0 + r + fr * 8);
745 }
746 vtop--;
747 if (op >= TOK_ULT && op <= TOK_GT) {
9620fd18 bellard2002-11-18 21:46:44 +0000748 vtop->r = VT_CMP;
749 vtop->c.i = op;
14658993 bellard2002-01-03 21:14:59 +0000750 }
751 break;
752 case '-':
753 case TOK_SUBC1: /* sub with carry generation */
754 opc = 5;
755 goto gen_op8;
756 case TOK_ADDC2: /* add with carry use */
757 opc = 2;
758 goto gen_op8;
759 case TOK_SUBC2: /* sub with carry use */
760 opc = 3;
761 goto gen_op8;
762 case '&':
763 opc = 4;
764 goto gen_op8;
765 case '^':
766 opc = 6;
767 goto gen_op8;
768 case '|':
769 opc = 1;
770 goto gen_op8;
771 case '*':
b7fed2f2 bellard2002-01-05 16:17:34 +0000772 gv2(RC_INT, RC_INT);
773 r = vtop[-1].r;
774 fr = vtop[0].r;
14658993 bellard2002-01-03 21:14:59 +0000775 vtop--;
39173894 bellard2001-12-12 21:16:34 +0000776 o(0xaf0f); /* imul fr, r */
777 o(0xc0 + fr + r * 8);
14658993 bellard2002-01-03 21:14:59 +0000778 break;
779 case TOK_SHL:
780 opc = 4;
781 goto gen_shift;
782 case TOK_SHR:
783 opc = 5;
784 goto gen_shift;
785 case TOK_SAR:
786 opc = 7;
787 gen_shift:
14658993 bellard2002-01-03 21:14:59 +0000788 opc = 0xc0 | (opc << 3);
6cd36b12 bellard2002-07-14 14:38:33 +0000789 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
14658993 bellard2002-01-03 21:14:59 +0000790 /* constant case */
b7fed2f2 bellard2002-01-05 16:17:34 +0000791 vswap();
792 r = gv(RC_INT);
793 vswap();
14658993 bellard2002-01-03 21:14:59 +0000794 c = vtop->c.i & 0x1f;
795 o(0xc1); /* shl/shr/sar $xxx, r */
796 o(opc | r);
797 g(c);
798 } else {
799 /* we generate the shift in ecx */
b7fed2f2 bellard2002-01-05 16:17:34 +0000800 gv2(RC_INT, RC_ECX);
801 r = vtop[-1].r;
14658993 bellard2002-01-03 21:14:59 +0000802 o(0xd3); /* shl/shr/sar %cl, r */
803 o(opc | r);
39173894 bellard2001-12-12 21:16:34 +0000804 }
14658993 bellard2002-01-03 21:14:59 +0000805 vtop--;
14658993 bellard2002-01-03 21:14:59 +0000806 break;
807 case '/':
808 case TOK_UDIV:
809 case TOK_PDIV:
810 case '%':
811 case TOK_UMOD:
812 case TOK_UMULL:
b7fed2f2 bellard2002-01-05 16:17:34 +0000813 /* first operand must be in eax */
814 /* XXX: need better constraint for second operand */
815 gv2(RC_EAX, RC_ECX);
816 r = vtop[-1].r;
817 fr = vtop[0].r;
14658993 bellard2002-01-03 21:14:59 +0000818 vtop--;
b5259da4 bellard2002-12-08 14:34:48 +0000819 save_reg(TREG_EDX);
14658993 bellard2002-01-03 21:14:59 +0000820 if (op == TOK_UMULL) {
821 o(0xf7); /* mul fr */
822 o(0xe0 + fr);
b5259da4 bellard2002-12-08 14:34:48 +0000823 vtop->r2 = TREG_EDX;
824 r = TREG_EAX;
39173894 bellard2001-12-12 21:16:34 +0000825 } else {
14658993 bellard2002-01-03 21:14:59 +0000826 if (op == TOK_UDIV || op == TOK_UMOD) {
827 o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
828 o(0xf0 + fr);
829 } else {
830 o(0xf799); /* cltd, idiv fr, %eax */
831 o(0xf8 + fr);
832 }
833 if (op == '%' || op == TOK_UMOD)
b5259da4 bellard2002-12-08 14:34:48 +0000834 r = TREG_EDX;
14658993 bellard2002-01-03 21:14:59 +0000835 else
b5259da4 bellard2002-12-08 14:34:48 +0000836 r = TREG_EAX;
39173894 bellard2001-12-12 21:16:34 +0000837 }
f7181903 bellard2001-12-20 01:05:21 +0000838 vtop->r = r;
14658993 bellard2002-01-03 21:14:59 +0000839 break;
840 default:
841 opc = 7;
842 goto gen_op8;
39173894 bellard2001-12-12 21:16:34 +0000843 }
844}
845
fbc51a39 bellard2001-12-16 17:58:32 +0000846/* generate a floating point operation 'v = t1 op t2' instruction. The
847 two operands are guaranted to have the same floating point type */
b7fed2f2 bellard2002-01-05 16:17:34 +0000848/* XXX: need to use ST1 too */
88a3ccab grischka2009-12-20 01:53:49 +0100849ST_FUNC void gen_opf(int op)
39173894 bellard2001-12-12 21:16:34 +0000850{
621b3fc3 bellard2002-01-26 17:23:44 +0000851 int a, ft, fc, swapped, r;
39173894 bellard2001-12-12 21:16:34 +0000852
2694c105 bellard2001-12-17 21:56:48 +0000853 /* convert constants to memory references */
14658993 bellard2002-01-03 21:14:59 +0000854 if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
2694c105 bellard2001-12-17 21:56:48 +0000855 vswap();
21c35b94 bellard2001-12-23 00:34:26 +0000856 gv(RC_FLOAT);
2694c105 bellard2001-12-17 21:56:48 +0000857 vswap();
858 }
14658993 bellard2002-01-03 21:14:59 +0000859 if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
21c35b94 bellard2001-12-23 00:34:26 +0000860 gv(RC_FLOAT);
2694c105 bellard2001-12-17 21:56:48 +0000861
39173894 bellard2001-12-12 21:16:34 +0000862 /* must put at least one value in the floating point register */
f7181903 bellard2001-12-20 01:05:21 +0000863 if ((vtop[-1].r & VT_LVAL) &&
864 (vtop[0].r & VT_LVAL)) {
39173894 bellard2001-12-12 21:16:34 +0000865 vswap();
21c35b94 bellard2001-12-23 00:34:26 +0000866 gv(RC_FLOAT);
39173894 bellard2001-12-12 21:16:34 +0000867 vswap();
868 }
264dbcfe bellard2002-07-13 15:55:16 +0000869 swapped = 0;
870 /* swap the stack if needed so that t1 is the register and t2 is
871 the memory reference */
872 if (vtop[-1].r & VT_LVAL) {
873 vswap();
874 swapped = 1;
875 }
14658993 bellard2002-01-03 21:14:59 +0000876 if (op >= TOK_ULT && op <= TOK_GT) {
39173894 bellard2001-12-12 21:16:34 +0000877 /* load on stack second operand */
b5259da4 bellard2002-12-08 14:34:48 +0000878 load(TREG_ST0, vtop);
879 save_reg(TREG_EAX); /* eax is used by FP comparison code */
39173894 bellard2001-12-12 21:16:34 +0000880 if (op == TOK_GE || op == TOK_GT)
264dbcfe bellard2002-07-13 15:55:16 +0000881 swapped = !swapped;
882 else if (op == TOK_EQ || op == TOK_NE)
883 swapped = 0;
884 if (swapped)
39173894 bellard2001-12-12 21:16:34 +0000885 o(0xc9d9); /* fxch %st(1) */
e0e9a2a2
TP
Thomas Preud'homme2013-12-31 23:40:21 +0800886 if (op == TOK_EQ || op == TOK_NE)
887 o(0xe9da); /* fucompp */
888 else
889 o(0xd9de); /* fcompp */
39173894 bellard2001-12-12 21:16:34 +0000890 o(0xe0df); /* fnstsw %ax */
891 if (op == TOK_EQ) {
892 o(0x45e480); /* and $0x45, %ah */
893 o(0x40fC80); /* cmp $0x40, %ah */
894 } else if (op == TOK_NE) {
895 o(0x45e480); /* and $0x45, %ah */
896 o(0x40f480); /* xor $0x40, %ah */
897 op = TOK_NE;
898 } else if (op == TOK_GE || op == TOK_LE) {
899 o(0x05c4f6); /* test $0x05, %ah */
900 op = TOK_EQ;
901 } else {
902 o(0x45c4f6); /* test $0x45, %ah */
903 op = TOK_EQ;
904 }
fbc51a39 bellard2001-12-16 17:58:32 +0000905 vtop--;
f7181903 bellard2001-12-20 01:05:21 +0000906 vtop->r = VT_CMP;
2694c105 bellard2001-12-17 21:56:48 +0000907 vtop->c.i = op;
39173894 bellard2001-12-12 21:16:34 +0000908 } else {
21c35b94 bellard2001-12-23 00:34:26 +0000909 /* no memory reference possible for long double operations */
9620fd18 bellard2002-11-18 21:46:44 +0000910 if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
b5259da4 bellard2002-12-08 14:34:48 +0000911 load(TREG_ST0, vtop);
21c35b94 bellard2001-12-23 00:34:26 +0000912 swapped = !swapped;
913 }
39173894 bellard2001-12-12 21:16:34 +0000914
915 switch(op) {
916 default:
917 case '+':
918 a = 0;
919 break;
920 case '-':
21c35b94 bellard2001-12-23 00:34:26 +0000921 a = 4;
39173894 bellard2001-12-12 21:16:34 +0000922 if (swapped)
21c35b94 bellard2001-12-23 00:34:26 +0000923 a++;
39173894 bellard2001-12-12 21:16:34 +0000924 break;
925 case '*':
21c35b94 bellard2001-12-23 00:34:26 +0000926 a = 1;
39173894 bellard2001-12-12 21:16:34 +0000927 break;
928 case '/':
21c35b94 bellard2001-12-23 00:34:26 +0000929 a = 6;
39173894 bellard2001-12-12 21:16:34 +0000930 if (swapped)
21c35b94 bellard2001-12-23 00:34:26 +0000931 a++;
39173894 bellard2001-12-12 21:16:34 +0000932 break;
933 }
9620fd18 bellard2002-11-18 21:46:44 +0000934 ft = vtop->type.t;
2694c105 bellard2001-12-17 21:56:48 +0000935 fc = vtop->c.ul;
21c35b94 bellard2001-12-23 00:34:26 +0000936 if ((ft & VT_BTYPE) == VT_LDOUBLE) {
937 o(0xde); /* fxxxp %st, %st(1) */
938 o(0xc1 + (a << 3));
39173894 bellard2001-12-12 21:16:34 +0000939 } else {
621b3fc3 bellard2002-01-26 17:23:44 +0000940 /* if saved lvalue, then we must reload it */
941 r = vtop->r;
942 if ((r & VT_VALMASK) == VT_LLOCAL) {
943 SValue v1;
944 r = get_reg(RC_INT);
9620fd18 bellard2002-11-18 21:46:44 +0000945 v1.type.t = VT_INT;
621b3fc3 bellard2002-01-26 17:23:44 +0000946 v1.r = VT_LOCAL | VT_LVAL;
947 v1.c.ul = fc;
948 load(r, &v1);
949 fc = 0;
950 }
951
21c35b94 bellard2001-12-23 00:34:26 +0000952 if ((ft & VT_BTYPE) == VT_DOUBLE)
953 o(0xdc);
954 else
955 o(0xd8);
d2115bfb bellard2002-08-29 23:05:59 +0000956 gen_modrm(a, r, vtop->sym, fc);
39173894 bellard2001-12-12 21:16:34 +0000957 }
fbc51a39 bellard2001-12-16 17:58:32 +0000958 vtop--;
39173894 bellard2001-12-12 21:16:34 +0000959 }
39173894 bellard2001-12-12 21:16:34 +0000960}
961
14658993 bellard2002-01-03 21:14:59 +0000962/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
963 and 'long long' cases. */
88a3ccab grischka2009-12-20 01:53:49 +0100964ST_FUNC void gen_cvt_itof(int t)
39173894 bellard2001-12-12 21:16:34 +0000965{
b5259da4 bellard2002-12-08 14:34:48 +0000966 save_reg(TREG_ST0);
21c35b94 bellard2001-12-23 00:34:26 +0000967 gv(RC_INT);
9620fd18 bellard2002-11-18 21:46:44 +0000968 if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
14658993 bellard2002-01-03 21:14:59 +0000969 /* signed long long to float/double/long double (unsigned case
970 is handled generically) */
971 o(0x50 + vtop->r2); /* push r2 */
972 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
973 o(0x242cdf); /* fildll (%esp) */
974 o(0x08c483); /* add $8, %esp */
9620fd18 bellard2002-11-18 21:46:44 +0000975 } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
14658993 bellard2002-01-03 21:14:59 +0000976 (VT_INT | VT_UNSIGNED)) {
25618c04 bellard2001-12-13 22:28:53 +0000977 /* unsigned int to float/double/long double */
39173894 bellard2001-12-12 21:16:34 +0000978 o(0x6a); /* push $0 */
979 g(0x00);
f7181903 bellard2001-12-20 01:05:21 +0000980 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
39173894 bellard2001-12-12 21:16:34 +0000981 o(0x242cdf); /* fildll (%esp) */
982 o(0x08c483); /* add $8, %esp */
983 } else {
25618c04 bellard2001-12-13 22:28:53 +0000984 /* int to float/double/long double */
f7181903 bellard2001-12-20 01:05:21 +0000985 o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
39173894 bellard2001-12-12 21:16:34 +0000986 o(0x2404db); /* fildl (%esp) */
987 o(0x04c483); /* add $4, %esp */
988 }
b5259da4 bellard2002-12-08 14:34:48 +0000989 vtop->r = TREG_ST0;
2694c105 bellard2001-12-17 21:56:48 +0000990}
991
2694c105 bellard2001-12-17 21:56:48 +0000992/* convert fp to int 't' type */
88a3ccab grischka2009-12-20 01:53:49 +0100993ST_FUNC void gen_cvt_ftoi(int t)
2694c105 bellard2001-12-17 21:56:48 +0000994{
664c19ad seyko2015-03-04 16:25:51 +0300995 #ifndef COMMIT_4ad186c5ef61_IS_FIXED
996 /* a good version but it takes a more time to execute */
997 gv(RC_FLOAT);
998 save_reg(TREG_EAX);
999 save_reg(TREG_EDX);
1000 gen_static_call(TOK___tcc_cvt_ftol);
1001 vtop->r = TREG_EAX; /* mark reg as used */
1002 if (t == VT_LLONG)
1003 vtop->r2 = TREG_EDX;
1004 #else
1005 /* a new version with a bug: t2a = 44100312 */
1006 /*
1007 #include<stdio.h>
1008 int main() {
1009 int t1 = 176401255;
1010 float f = 0.25f;
1011 int t2a = (int)(t1 * f); // must be 44100313
1012 int t2b = (int)(t1 * (float)0.25f);
1013 printf("t2a=%d t2b=%d \n",t2a,t2b);
1014 return 0;
1015 }
1016 */
4ad186c5 grischka2014-01-06 19:07:08 +01001017 int bt = vtop->type.t & VT_BTYPE;
1018 if (bt == VT_FLOAT)
1019 vpush_global_sym(&func_old_type, TOK___fixsfdi);
1020 else if (bt == VT_LDOUBLE)
1021 vpush_global_sym(&func_old_type, TOK___fixxfdi);
1022 else
1023 vpush_global_sym(&func_old_type, TOK___fixdfdi);
1024 vswap();
1025 gfunc_call(1);
1026 vpushi(0);
1027 vtop->r = REG_IRET;
1028 vtop->r2 = REG_LRET;
664c19ad seyko2015-03-04 16:25:51 +03001029 #endif
39173894 bellard2001-12-12 21:16:34 +00001030}
1031
2694c105 bellard2001-12-17 21:56:48 +00001032/* convert from one floating point type to another */
88a3ccab grischka2009-12-20 01:53:49 +01001033ST_FUNC void gen_cvt_ftof(int t)
2694c105 bellard2001-12-17 21:56:48 +00001034{
1035 /* all we have to do on i386 is to put the float in a register */
21c35b94 bellard2001-12-23 00:34:26 +00001036 gv(RC_FLOAT);
2694c105 bellard2001-12-17 21:56:48 +00001037}
1038
fde824b7 bellard2002-11-03 00:43:01 +00001039/* computed goto support */
88a3ccab grischka2009-12-20 01:53:49 +01001040ST_FUNC void ggoto(void)
fde824b7 bellard2002-11-03 00:43:01 +00001041{
1042 gcall_or_jmp(1);
1043 vtop--;
1044}
1045
b7fed2f2 bellard2002-01-05 16:17:34 +00001046/* bound check support functions */
4226681d bellard2002-03-03 22:45:55 +00001047#ifdef CONFIG_TCC_BCHECK
264dbcfe bellard2002-07-13 15:55:16 +00001048
1049/* generate a bounded pointer addition */
88a3ccab grischka2009-12-20 01:53:49 +01001050ST_FUNC void gen_bounded_ptr_add(void)
b7fed2f2 bellard2002-01-05 16:17:34 +00001051{
1052 /* prepare fast i386 function call (args in eax and edx) */
1053 gv2(RC_EAX, RC_EDX);
1054 /* save all temporary registers */
264dbcfe bellard2002-07-13 15:55:16 +00001055 vtop -= 2;
1056 save_regs(0);
1057 /* do a fast function call */
73faaea2 grischka2013-08-28 22:55:05 +02001058 gen_static_call(TOK___bound_ptr_add);
264dbcfe bellard2002-07-13 15:55:16 +00001059 /* returned pointer is in eax */
1060 vtop++;
b5259da4 bellard2002-12-08 14:34:48 +00001061 vtop->r = TREG_EAX | VT_BOUNDED;
6cdecbe4 bellard2002-07-22 23:37:39 +00001062 /* address of bounding function call point */
a42941b1 bellard2002-07-27 14:06:11 +00001063 vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
b7fed2f2 bellard2002-01-05 16:17:34 +00001064}
1065
264dbcfe bellard2002-07-13 15:55:16 +00001066/* patch pointer addition in vtop so that pointer dereferencing is
1067 also tested */
88a3ccab grischka2009-12-20 01:53:49 +01001068ST_FUNC void gen_bounded_ptr_deref(void)
b7fed2f2 bellard2002-01-05 16:17:34 +00001069{
acef4ff2 seyko2015-03-26 07:47:45 +03001070 addr_t func;
1071 addr_t size, align;
6cdecbe4 bellard2002-07-22 23:37:39 +00001072 Elf32_Rel *rel;
1073 Sym *sym;
264dbcfe bellard2002-07-13 15:55:16 +00001074
1075 size = 0;
1076 /* XXX: put that code in generic part of tcc */
9620fd18 bellard2002-11-18 21:46:44 +00001077 if (!is_float(vtop->type.t)) {
264dbcfe bellard2002-07-13 15:55:16 +00001078 if (vtop->r & VT_LVAL_BYTE)
1079 size = 1;
1080 else if (vtop->r & VT_LVAL_SHORT)
1081 size = 2;
1082 }
1083 if (!size)
9620fd18 bellard2002-11-18 21:46:44 +00001084 size = type_size(&vtop->type, &align);
264dbcfe bellard2002-07-13 15:55:16 +00001085 switch(size) {
6cdecbe4 bellard2002-07-22 23:37:39 +00001086 case 1: func = TOK___bound_ptr_indir1; break;
1087 case 2: func = TOK___bound_ptr_indir2; break;
1088 case 4: func = TOK___bound_ptr_indir4; break;
1089 case 8: func = TOK___bound_ptr_indir8; break;
1090 case 12: func = TOK___bound_ptr_indir12; break;
1091 case 16: func = TOK___bound_ptr_indir16; break;
264dbcfe bellard2002-07-13 15:55:16 +00001092 default:
9c25ed13 Thomas Preud'homme2012-01-08 17:58:19 +01001093 tcc_error("unhandled size when dereferencing bounded pointer");
6cdecbe4 bellard2002-07-22 23:37:39 +00001094 func = 0;
264dbcfe bellard2002-07-13 15:55:16 +00001095 break;
b7fed2f2 bellard2002-01-05 16:17:34 +00001096 }
1097
6cdecbe4 bellard2002-07-22 23:37:39 +00001098 /* patch relocation */
1099 /* XXX: find a better solution ? */
a42941b1 bellard2002-07-27 14:06:11 +00001100 rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
9620fd18 bellard2002-11-18 21:46:44 +00001101 sym = external_global_sym(func, &func_old_type, 0);
6cdecbe4 bellard2002-07-22 23:37:39 +00001102 if (!sym->c)
4c9c0ab1 bellard2002-07-27 23:08:29 +00001103 put_extern_sym(sym, NULL, 0, 0);
6cdecbe4 bellard2002-07-22 23:37:39 +00001104 rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
b7fed2f2 bellard2002-01-05 16:17:34 +00001105}
4226681d bellard2002-03-03 22:45:55 +00001106#endif
b7fed2f2 bellard2002-01-05 16:17:34 +00001107
41b3c7a5
JL
James Lyon2013-04-27 20:39:34 +01001108/* Save the stack pointer onto the stack */
1109ST_FUNC void gen_vla_sp_save(int addr) {
1110 /* mov %esp,addr(%ebp)*/
1111 o(0x89);
1112 gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
1113}
1114
1115/* Restore the SP from a location on the stack */
1116ST_FUNC void gen_vla_sp_restore(int addr) {
1117 o(0x8b);
1118 gen_modrm(TREG_ESP, VT_LOCAL, NULL, addr);
1119}
1120
1121/* Subtract from the stack pointer, and push the resulting value onto the stack */
1122ST_FUNC void gen_vla_alloc(CType *type, int align) {
1123#ifdef TCC_TARGET_PE
1124 /* alloca does more than just adjust %rsp on Windows */
1125 vpush_global_sym(&func_old_type, TOK_alloca);
1126 vswap(); /* Move alloca ref past allocation size */
1127 gfunc_call(1);
41b3c7a5
JL
James Lyon2013-04-27 20:39:34 +01001128#else
1129 int r;
1130 r = gv(RC_INT); /* allocation size */
1131 /* sub r,%rsp */
1132 o(0x2b);
1133 o(0xe0 | r);
1134 /* We align to 16 bytes rather than align */
1135 /* and ~15, %esp */
1136 o(0xf0e483);
41b3c7a5 James Lyon2013-04-27 20:39:34 +01001137 vpop();
41b3c7a5
JL
James Lyon2013-04-27 20:39:34 +01001138#endif
1139}
1140
39173894 bellard2001-12-12 21:16:34 +00001141/* end of X86 code generator */
1142/*************************************************************/
88a3ccab grischka2009-12-20 01:53:49 +01001143#endif
1144/*************************************************************/