Rev 647 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 647 | Rev 6429 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * CIL code generator for TCC |
2 | * CIL code generator for TCC |
3 | * |
3 | * |
4 | * Copyright (c) 2002 Fabrice Bellard |
4 | * Copyright (c) 2002 Fabrice Bellard |
5 | * |
5 | * |
6 | * This program is free software; you can redistribute it and/or modify |
6 | * This library is free software; you can redistribute it and/or |
7 | * it under the terms of the GNU General Public License as published by |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * the Free Software Foundation; either version 2 of the License, or |
8 | * License as published by the Free Software Foundation; either |
9 | * (at your option) any later version. |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * GNU General Public License for more details. |
14 | * Lesser General Public License for more details. |
15 | * |
15 | * |
16 | * You should have received a copy of the GNU General Public License |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * along with this program; if not, write to the Free Software |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
19 | */ |
20 | 20 | ||
21 | /* number of available registers */ |
21 | /* number of available registers */ |
22 | #define NB_REGS 3 |
22 | #define NB_REGS 3 |
23 | 23 | ||
24 | /* a register can belong to several classes. The classes must be |
24 | /* a register can belong to several classes. The classes must be |
25 | sorted from more general to more precise (see gv2() code which does |
25 | sorted from more general to more precise (see gv2() code which does |
26 | assumptions on it). */ |
26 | assumptions on it). */ |
27 | #define RC_ST 0x0001 /* any stack entry */ |
27 | #define RC_ST 0x0001 /* any stack entry */ |
28 | #define RC_ST0 0x0002 /* top of stack */ |
28 | #define RC_ST0 0x0002 /* top of stack */ |
29 | #define RC_ST1 0x0004 /* top - 1 */ |
29 | #define RC_ST1 0x0004 /* top - 1 */ |
30 | 30 | ||
31 | #define RC_INT RC_ST |
31 | #define RC_INT RC_ST |
32 | #define RC_FLOAT RC_ST |
32 | #define RC_FLOAT RC_ST |
33 | #define RC_IRET RC_ST0 /* function return: integer register */ |
33 | #define RC_IRET RC_ST0 /* function return: integer register */ |
34 | #define RC_LRET RC_ST0 /* function return: second integer register */ |
34 | #define RC_LRET RC_ST0 /* function return: second integer register */ |
35 | #define RC_FRET RC_ST0 /* function return: float register */ |
35 | #define RC_FRET RC_ST0 /* function return: float register */ |
36 | 36 | ||
37 | /* pretty names for the registers */ |
37 | /* pretty names for the registers */ |
38 | enum { |
38 | enum { |
39 | REG_ST0 = 0, |
39 | REG_ST0 = 0, |
40 | REG_ST1, |
40 | REG_ST1, |
41 | REG_ST2, |
41 | REG_ST2, |
42 | }; |
42 | }; |
43 | 43 | ||
44 | int reg_classes[NB_REGS] = { |
44 | const int reg_classes[NB_REGS] = { |
45 | /* ST0 */ RC_ST | RC_ST0, |
45 | /* ST0 */ RC_ST | RC_ST0, |
46 | /* ST1 */ RC_ST | RC_ST1, |
46 | /* ST1 */ RC_ST | RC_ST1, |
47 | /* ST2 */ RC_ST, |
47 | /* ST2 */ RC_ST, |
48 | }; |
48 | }; |
49 | 49 | ||
50 | /* return registers for function */ |
50 | /* return registers for function */ |
51 | #define REG_IRET REG_ST0 /* single word int return register */ |
51 | #define REG_IRET REG_ST0 /* single word int return register */ |
52 | #define REG_LRET REG_ST0 /* second word return register (for long long) */ |
52 | #define REG_LRET REG_ST0 /* second word return register (for long long) */ |
53 | #define REG_FRET REG_ST0 /* float return register */ |
53 | #define REG_FRET REG_ST0 /* float return register */ |
54 | 54 | ||
55 | /* defined if function parameters must be evaluated in reverse order */ |
55 | /* defined if function parameters must be evaluated in reverse order */ |
56 | //#define INVERT_FUNC_PARAMS |
56 | /* #define INVERT_FUNC_PARAMS */ |
57 | 57 | ||
58 | /* defined if structures are passed as pointers. Otherwise structures |
58 | /* defined if structures are passed as pointers. Otherwise structures |
59 | are directly pushed on stack. */ |
59 | are directly pushed on stack. */ |
60 | //#define FUNC_STRUCT_PARAM_AS_PTR |
60 | /* #define FUNC_STRUCT_PARAM_AS_PTR */ |
61 | 61 | ||
62 | /* pointer size, in bytes */ |
62 | /* pointer size, in bytes */ |
63 | #define PTR_SIZE 4 |
63 | #define PTR_SIZE 4 |
64 | 64 | ||
65 | /* long double size and alignment, in bytes */ |
65 | /* long double size and alignment, in bytes */ |
66 | #define LDOUBLE_SIZE 8 |
66 | #define LDOUBLE_SIZE 8 |
67 | #define LDOUBLE_ALIGN 8 |
67 | #define LDOUBLE_ALIGN 8 |
68 | 68 | ||
69 | /* function call context */ |
69 | /* function call context */ |
70 | typedef struct GFuncContext { |
70 | typedef struct GFuncContext { |
71 | int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */ |
71 | int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */ |
72 | } GFuncContext; |
72 | } GFuncContext; |
73 | 73 | ||
74 | /******************************************************/ |
74 | /******************************************************/ |
75 | /* opcode definitions */ |
75 | /* opcode definitions */ |
76 | 76 | ||
77 | #define IL_OP_PREFIX 0xFE |
77 | #define IL_OP_PREFIX 0xFE |
78 | 78 | ||
79 | enum ILOPCodes { |
79 | enum ILOPCodes { |
80 | #define OP(name, str, n) IL_OP_ ## name = n, |
80 | #define OP(name, str, n) IL_OP_ ## name = n, |
81 | #include "il-opcodes.h" |
81 | #include "il-opcodes.h" |
82 | #undef OP |
82 | #undef OP |
83 | }; |
83 | }; |
84 | 84 | ||
85 | char *il_opcodes_str[] = { |
85 | char *il_opcodes_str[] = { |
86 | #define OP(name, str, n) [n] = str, |
86 | #define OP(name, str, n) [n] = str, |
87 | #include "il-opcodes.h" |
87 | #include "il-opcodes.h" |
88 | #undef OP |
88 | #undef OP |
89 | }; |
89 | }; |
90 | 90 | ||
91 | /******************************************************/ |
91 | /******************************************************/ |
92 | 92 | ||
93 | /* arguments variable numbers start from there */ |
93 | /* arguments variable numbers start from there */ |
94 | #define ARG_BASE 0x70000000 |
94 | #define ARG_BASE 0x70000000 |
95 | 95 | ||
96 | static FILE *il_outfile; |
96 | static FILE *il_outfile; |
97 | 97 | ||
98 | static void out_byte(int c) |
98 | static void out_byte(int c) |
99 | { |
99 | { |
100 | *(char *)ind++ = c; |
100 | *(char *)ind++ = c; |
101 | } |
101 | } |
102 | 102 | ||
103 | static void out_le32(int c) |
103 | static void out_le32(int c) |
104 | { |
104 | { |
105 | out_byte(c); |
105 | out_byte(c); |
106 | out_byte(c >> 8); |
106 | out_byte(c >> 8); |
107 | out_byte(c >> 16); |
107 | out_byte(c >> 16); |
108 | out_byte(c >> 24); |
108 | out_byte(c >> 24); |
109 | } |
109 | } |
110 | 110 | ||
111 | static void init_outfile(void) |
111 | static void init_outfile(void) |
112 | { |
112 | { |
113 | if (!il_outfile) { |
113 | if (!il_outfile) { |
114 | il_outfile = stdout; |
114 | il_outfile = stdout; |
115 | fprintf(il_outfile, |
115 | fprintf(il_outfile, |
116 | ".assembly extern mscorlib\n" |
116 | ".assembly extern mscorlib\n" |
117 | "{\n" |
117 | "{\n" |
118 | ".ver 1:0:2411:0\n" |
118 | ".ver 1:0:2411:0\n" |
119 | "}\n\n"); |
119 | "}\n\n"); |
120 | } |
120 | } |
121 | } |
121 | } |
122 | 122 | ||
123 | static void out_op1(int op) |
123 | static void out_op1(int op) |
124 | { |
124 | { |
125 | if (op & 0x100) |
125 | if (op & 0x100) |
126 | out_byte(IL_OP_PREFIX); |
126 | out_byte(IL_OP_PREFIX); |
127 | out_byte(op & 0xff); |
127 | out_byte(op & 0xff); |
128 | } |
128 | } |
129 | 129 | ||
130 | /* output an opcode with prefix */ |
130 | /* output an opcode with prefix */ |
131 | static void out_op(int op) |
131 | static void out_op(int op) |
132 | { |
132 | { |
133 | out_op1(op); |
133 | out_op1(op); |
134 | fprintf(il_outfile, " %s\n", il_opcodes_str[op]); |
134 | fprintf(il_outfile, " %s\n", il_opcodes_str[op]); |
135 | } |
135 | } |
136 | 136 | ||
137 | static void out_opb(int op, int c) |
137 | static void out_opb(int op, int c) |
138 | { |
138 | { |
139 | out_op1(op); |
139 | out_op1(op); |
140 | out_byte(c); |
140 | out_byte(c); |
141 | fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c); |
141 | fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c); |
142 | } |
142 | } |
143 | 143 | ||
144 | static void out_opi(int op, int c) |
144 | static void out_opi(int op, int c) |
145 | { |
145 | { |
146 | out_op1(op); |
146 | out_op1(op); |
147 | out_le32(c); |
147 | out_le32(c); |
148 | fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c); |
148 | fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c); |
149 | } |
149 | } |
150 | 150 | ||
151 | /* XXX: not complete */ |
151 | /* XXX: not complete */ |
152 | static void il_type_to_str(char *buf, int buf_size, |
152 | static void il_type_to_str(char *buf, int buf_size, |
153 | int t, const char *varstr) |
153 | int t, const char *varstr) |
154 | { |
154 | { |
155 | int bt; |
155 | int bt; |
156 | Sym *s, *sa; |
156 | Sym *s, *sa; |
157 | char buf1[256]; |
157 | char buf1[256]; |
158 | const char *tstr; |
158 | const char *tstr; |
159 | 159 | ||
160 | t = t & VT_TYPE; |
160 | t = t & VT_TYPE; |
161 | bt = t & VT_BTYPE; |
161 | bt = t & VT_BTYPE; |
162 | buf[0] = '\0'; |
162 | buf[0] = '\0'; |
163 | if (t & VT_UNSIGNED) |
163 | if (t & VT_UNSIGNED) |
164 | pstrcat(buf, buf_size, "unsigned "); |
164 | pstrcat(buf, buf_size, "unsigned "); |
165 | switch(bt) { |
165 | switch(bt) { |
166 | case VT_VOID: |
166 | case VT_VOID: |
167 | tstr = "void"; |
167 | tstr = "void"; |
168 | goto add_tstr; |
168 | goto add_tstr; |
169 | case VT_BOOL: |
169 | case VT_BOOL: |
170 | tstr = "bool"; |
170 | tstr = "bool"; |
171 | goto add_tstr; |
171 | goto add_tstr; |
172 | case VT_BYTE: |
172 | case VT_BYTE: |
173 | tstr = "int8"; |
173 | tstr = "int8"; |
174 | goto add_tstr; |
174 | goto add_tstr; |
175 | case VT_SHORT: |
175 | case VT_SHORT: |
176 | tstr = "int16"; |
176 | tstr = "int16"; |
177 | goto add_tstr; |
177 | goto add_tstr; |
178 | case VT_ENUM: |
178 | case VT_ENUM: |
179 | case VT_INT: |
179 | case VT_INT: |
180 | case VT_LONG: |
180 | case VT_LONG: |
181 | tstr = "int32"; |
181 | tstr = "int32"; |
182 | goto add_tstr; |
182 | goto add_tstr; |
183 | case VT_LLONG: |
183 | case VT_LLONG: |
184 | tstr = "int64"; |
184 | tstr = "int64"; |
185 | goto add_tstr; |
185 | goto add_tstr; |
186 | case VT_FLOAT: |
186 | case VT_FLOAT: |
187 | tstr = "float32"; |
187 | tstr = "float32"; |
188 | goto add_tstr; |
188 | goto add_tstr; |
189 | case VT_DOUBLE: |
189 | case VT_DOUBLE: |
190 | case VT_LDOUBLE: |
190 | case VT_LDOUBLE: |
191 | tstr = "float64"; |
191 | tstr = "float64"; |
192 | add_tstr: |
192 | add_tstr: |
193 | pstrcat(buf, buf_size, tstr); |
193 | pstrcat(buf, buf_size, tstr); |
194 | break; |
194 | break; |
195 | case VT_STRUCT: |
195 | case VT_STRUCT: |
196 | error("structures not handled yet"); |
196 | tcc_error("structures not handled yet"); |
197 | break; |
197 | break; |
198 | case VT_FUNC: |
198 | case VT_FUNC: |
199 | s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
199 | s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
200 | il_type_to_str(buf, buf_size, s->t, varstr); |
200 | il_type_to_str(buf, buf_size, s->t, varstr); |
201 | pstrcat(buf, buf_size, "("); |
201 | pstrcat(buf, buf_size, "("); |
202 | sa = s->next; |
202 | sa = s->next; |
203 | while (sa != NULL) { |
203 | while (sa != NULL) { |
204 | il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); |
204 | il_type_to_str(buf1, sizeof(buf1), sa->t, NULL); |
205 | pstrcat(buf, buf_size, buf1); |
205 | pstrcat(buf, buf_size, buf1); |
206 | sa = sa->next; |
206 | sa = sa->next; |
207 | if (sa) |
207 | if (sa) |
208 | pstrcat(buf, buf_size, ", "); |
208 | pstrcat(buf, buf_size, ", "); |
209 | } |
209 | } |
210 | pstrcat(buf, buf_size, ")"); |
210 | pstrcat(buf, buf_size, ")"); |
211 | goto no_var; |
211 | goto no_var; |
212 | case VT_PTR: |
212 | case VT_PTR: |
213 | s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
213 | s = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
214 | pstrcpy(buf1, sizeof(buf1), "*"); |
214 | pstrcpy(buf1, sizeof(buf1), "*"); |
215 | if (varstr) |
215 | if (varstr) |
216 | pstrcat(buf1, sizeof(buf1), varstr); |
216 | pstrcat(buf1, sizeof(buf1), varstr); |
217 | il_type_to_str(buf, buf_size, s->t, buf1); |
217 | il_type_to_str(buf, buf_size, s->t, buf1); |
218 | goto no_var; |
218 | goto no_var; |
219 | } |
219 | } |
220 | if (varstr) { |
220 | if (varstr) { |
221 | pstrcat(buf, buf_size, " "); |
221 | pstrcat(buf, buf_size, " "); |
222 | pstrcat(buf, buf_size, varstr); |
222 | pstrcat(buf, buf_size, varstr); |
223 | } |
223 | } |
224 | no_var: ; |
224 | no_var: ; |
225 | } |
225 | } |
226 | 226 | ||
227 | 227 | ||
228 | /* patch relocation entry with value 'val' */ |
228 | /* patch relocation entry with value 'val' */ |
229 | void greloc_patch1(Reloc *p, int val) |
229 | void greloc_patch1(Reloc *p, int val) |
230 | { |
230 | { |
231 | } |
231 | } |
232 | 232 | ||
233 | /* output a symbol and patch all calls to it */ |
233 | /* output a symbol and patch all calls to it */ |
234 | void gsym_addr(t, a) |
234 | void gsym_addr(t, a) |
235 | { |
235 | { |
236 | } |
236 | } |
237 | 237 | ||
238 | /* output jump and return symbol */ |
238 | /* output jump and return symbol */ |
239 | static int out_opj(int op, int c) |
239 | static int out_opj(int op, int c) |
240 | { |
240 | { |
241 | out_op1(op); |
241 | out_op1(op); |
242 | out_le32(0); |
242 | out_le32(0); |
243 | if (c == 0) { |
243 | if (c == 0) { |
244 | c = ind - (int)cur_text_section->data; |
244 | c = ind - (int)cur_text_section->data; |
245 | } |
245 | } |
246 | fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c); |
246 | fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c); |
247 | return c; |
247 | return c; |
248 | } |
248 | } |
249 | 249 | ||
250 | void gsym(int t) |
250 | void gsym(int t) |
251 | { |
251 | { |
252 | fprintf(il_outfile, "L%d:\n", t); |
252 | fprintf(il_outfile, "L%d:\n", t); |
253 | } |
253 | } |
254 | 254 | ||
255 | /* load 'r' from value 'sv' */ |
255 | /* load 'r' from value 'sv' */ |
256 | void load(int r, SValue *sv) |
256 | void load(int r, SValue *sv) |
257 | { |
257 | { |
258 | int v, fc, ft; |
258 | int v, fc, ft; |
259 | 259 | ||
260 | v = sv->r & VT_VALMASK; |
260 | v = sv->r & VT_VALMASK; |
261 | fc = sv->c.i; |
261 | fc = sv->c.i; |
262 | ft = sv->t; |
262 | ft = sv->t; |
263 | 263 | ||
264 | if (sv->r & VT_LVAL) { |
264 | if (sv->r & VT_LVAL) { |
265 | if (v == VT_LOCAL) { |
265 | if (v == VT_LOCAL) { |
266 | if (fc >= ARG_BASE) { |
266 | if (fc >= ARG_BASE) { |
267 | fc -= ARG_BASE; |
267 | fc -= ARG_BASE; |
268 | if (fc >= 0 && fc <= 4) { |
268 | if (fc >= 0 && fc <= 4) { |
269 | out_op(IL_OP_LDARG_0 + fc); |
269 | out_op(IL_OP_LDARG_0 + fc); |
270 | } else if (fc <= 0xff) { |
270 | } else if (fc <= 0xff) { |
271 | out_opb(IL_OP_LDARG_S, fc); |
271 | out_opb(IL_OP_LDARG_S, fc); |
272 | } else { |
272 | } else { |
273 | out_opi(IL_OP_LDARG, fc); |
273 | out_opi(IL_OP_LDARG, fc); |
274 | } |
274 | } |
275 | } else { |
275 | } else { |
276 | if (fc >= 0 && fc <= 4) { |
276 | if (fc >= 0 && fc <= 4) { |
277 | out_op(IL_OP_LDLOC_0 + fc); |
277 | out_op(IL_OP_LDLOC_0 + fc); |
278 | } else if (fc <= 0xff) { |
278 | } else if (fc <= 0xff) { |
279 | out_opb(IL_OP_LDLOC_S, fc); |
279 | out_opb(IL_OP_LDLOC_S, fc); |
280 | } else { |
280 | } else { |
281 | out_opi(IL_OP_LDLOC, fc); |
281 | out_opi(IL_OP_LDLOC, fc); |
282 | } |
282 | } |
283 | } |
283 | } |
284 | } else if (v == VT_CONST) { |
284 | } else if (v == VT_CONST) { |
285 | /* XXX: handle globals */ |
285 | /* XXX: handle globals */ |
286 | out_opi(IL_OP_LDSFLD, 0); |
286 | out_opi(IL_OP_LDSFLD, 0); |
287 | } else { |
287 | } else { |
288 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
288 | if ((ft & VT_BTYPE) == VT_FLOAT) { |
289 | out_op(IL_OP_LDIND_R4); |
289 | out_op(IL_OP_LDIND_R4); |
290 | } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
290 | } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
291 | out_op(IL_OP_LDIND_R8); |
291 | out_op(IL_OP_LDIND_R8); |
292 | } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
292 | } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
293 | out_op(IL_OP_LDIND_R8); |
293 | out_op(IL_OP_LDIND_R8); |
294 | } else if ((ft & VT_TYPE) == VT_BYTE) |
294 | } else if ((ft & VT_TYPE) == VT_BYTE) |
295 | out_op(IL_OP_LDIND_I1); |
295 | out_op(IL_OP_LDIND_I1); |
296 | else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) |
296 | else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) |
297 | out_op(IL_OP_LDIND_U1); |
297 | out_op(IL_OP_LDIND_U1); |
298 | else if ((ft & VT_TYPE) == VT_SHORT) |
298 | else if ((ft & VT_TYPE) == VT_SHORT) |
299 | out_op(IL_OP_LDIND_I2); |
299 | out_op(IL_OP_LDIND_I2); |
300 | else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) |
300 | else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) |
301 | out_op(IL_OP_LDIND_U2); |
301 | out_op(IL_OP_LDIND_U2); |
302 | else |
302 | else |
303 | out_op(IL_OP_LDIND_I4); |
303 | out_op(IL_OP_LDIND_I4); |
304 | } |
304 | } |
305 | } else { |
305 | } else { |
306 | if (v == VT_CONST) { |
306 | if (v == VT_CONST) { |
307 | /* XXX: handle globals */ |
307 | /* XXX: handle globals */ |
308 | if (fc >= -1 && fc <= 8) { |
308 | if (fc >= -1 && fc <= 8) { |
309 | out_op(IL_OP_LDC_I4_M1 + fc + 1); |
309 | out_op(IL_OP_LDC_I4_M1 + fc + 1); |
310 | } else { |
310 | } else { |
311 | out_opi(IL_OP_LDC_I4, fc); |
311 | out_opi(IL_OP_LDC_I4, fc); |
312 | } |
312 | } |
313 | } else if (v == VT_LOCAL) { |
313 | } else if (v == VT_LOCAL) { |
314 | if (fc >= ARG_BASE) { |
314 | if (fc >= ARG_BASE) { |
315 | fc -= ARG_BASE; |
315 | fc -= ARG_BASE; |
316 | if (fc <= 0xff) { |
316 | if (fc <= 0xff) { |
317 | out_opb(IL_OP_LDARGA_S, fc); |
317 | out_opb(IL_OP_LDARGA_S, fc); |
318 | } else { |
318 | } else { |
319 | out_opi(IL_OP_LDARGA, fc); |
319 | out_opi(IL_OP_LDARGA, fc); |
320 | } |
320 | } |
321 | } else { |
321 | } else { |
322 | if (fc <= 0xff) { |
322 | if (fc <= 0xff) { |
323 | out_opb(IL_OP_LDLOCA_S, fc); |
323 | out_opb(IL_OP_LDLOCA_S, fc); |
324 | } else { |
324 | } else { |
325 | out_opi(IL_OP_LDLOCA, fc); |
325 | out_opi(IL_OP_LDLOCA, fc); |
326 | } |
326 | } |
327 | } |
327 | } |
328 | } else { |
328 | } else { |
329 | /* XXX: do it */ |
329 | /* XXX: do it */ |
330 | } |
330 | } |
331 | } |
331 | } |
332 | } |
332 | } |
333 | 333 | ||
334 | /* store register 'r' in lvalue 'v' */ |
334 | /* store register 'r' in lvalue 'v' */ |
335 | void store(int r, SValue *sv) |
335 | void store(int r, SValue *sv) |
336 | { |
336 | { |
337 | int v, fc, ft; |
337 | int v, fc, ft; |
338 | 338 | ||
339 | v = sv->r & VT_VALMASK; |
339 | v = sv->r & VT_VALMASK; |
340 | fc = sv->c.i; |
340 | fc = sv->c.i; |
341 | ft = sv->t; |
341 | ft = sv->t; |
342 | if (v == VT_LOCAL) { |
342 | if (v == VT_LOCAL) { |
343 | if (fc >= ARG_BASE) { |
343 | if (fc >= ARG_BASE) { |
344 | fc -= ARG_BASE; |
344 | fc -= ARG_BASE; |
345 | /* XXX: check IL arg store semantics */ |
345 | /* XXX: check IL arg store semantics */ |
346 | if (fc <= 0xff) { |
346 | if (fc <= 0xff) { |
347 | out_opb(IL_OP_STARG_S, fc); |
347 | out_opb(IL_OP_STARG_S, fc); |
348 | } else { |
348 | } else { |
349 | out_opi(IL_OP_STARG, fc); |
349 | out_opi(IL_OP_STARG, fc); |
350 | } |
350 | } |
351 | } else { |
351 | } else { |
352 | if (fc >= 0 && fc <= 4) { |
352 | if (fc >= 0 && fc <= 4) { |
353 | out_op(IL_OP_STLOC_0 + fc); |
353 | out_op(IL_OP_STLOC_0 + fc); |
354 | } else if (fc <= 0xff) { |
354 | } else if (fc <= 0xff) { |
355 | out_opb(IL_OP_STLOC_S, fc); |
355 | out_opb(IL_OP_STLOC_S, fc); |
356 | } else { |
356 | } else { |
357 | out_opi(IL_OP_STLOC, fc); |
357 | out_opi(IL_OP_STLOC, fc); |
358 | } |
358 | } |
359 | } |
359 | } |
360 | } else if (v == VT_CONST) { |
360 | } else if (v == VT_CONST) { |
361 | /* XXX: handle globals */ |
361 | /* XXX: handle globals */ |
362 | out_opi(IL_OP_STSFLD, 0); |
362 | out_opi(IL_OP_STSFLD, 0); |
363 | } else { |
363 | } else { |
364 | if ((ft & VT_BTYPE) == VT_FLOAT) |
364 | if ((ft & VT_BTYPE) == VT_FLOAT) |
365 | out_op(IL_OP_STIND_R4); |
365 | out_op(IL_OP_STIND_R4); |
366 | else if ((ft & VT_BTYPE) == VT_DOUBLE) |
366 | else if ((ft & VT_BTYPE) == VT_DOUBLE) |
367 | out_op(IL_OP_STIND_R8); |
367 | out_op(IL_OP_STIND_R8); |
368 | else if ((ft & VT_BTYPE) == VT_LDOUBLE) |
368 | else if ((ft & VT_BTYPE) == VT_LDOUBLE) |
369 | out_op(IL_OP_STIND_R8); |
369 | out_op(IL_OP_STIND_R8); |
370 | else if ((ft & VT_BTYPE) == VT_BYTE) |
370 | else if ((ft & VT_BTYPE) == VT_BYTE) |
371 | out_op(IL_OP_STIND_I1); |
371 | out_op(IL_OP_STIND_I1); |
372 | else if ((ft & VT_BTYPE) == VT_SHORT) |
372 | else if ((ft & VT_BTYPE) == VT_SHORT) |
373 | out_op(IL_OP_STIND_I2); |
373 | out_op(IL_OP_STIND_I2); |
374 | else |
374 | else |
375 | out_op(IL_OP_STIND_I4); |
375 | out_op(IL_OP_STIND_I4); |
376 | } |
376 | } |
377 | } |
377 | } |
378 | 378 | ||
379 | /* start function call and return function call context */ |
379 | /* start function call and return function call context */ |
380 | void gfunc_start(GFuncContext *c, int func_call) |
380 | void gfunc_start(GFuncContext *c, int func_call) |
381 | { |
381 | { |
382 | c->func_call = func_call; |
382 | c->func_call = func_call; |
383 | } |
383 | } |
384 | 384 | ||
385 | /* push function parameter which is in (vtop->t, vtop->c). Stack entry |
385 | /* push function parameter which is in (vtop->t, vtop->c). Stack entry |
386 | is then popped. */ |
386 | is then popped. */ |
387 | void gfunc_param(GFuncContext *c) |
387 | void gfunc_param(GFuncContext *c) |
388 | { |
388 | { |
389 | if ((vtop->t & VT_BTYPE) == VT_STRUCT) { |
389 | if ((vtop->t & VT_BTYPE) == VT_STRUCT) { |
390 | error("structures passed as value not handled yet"); |
390 | tcc_error("structures passed as value not handled yet"); |
391 | } else { |
391 | } else { |
392 | /* simply push on stack */ |
392 | /* simply push on stack */ |
393 | gv(RC_ST0); |
393 | gv(RC_ST0); |
394 | } |
394 | } |
395 | vtop--; |
395 | vtop--; |
396 | } |
396 | } |
397 | 397 | ||
398 | /* generate function call with address in (vtop->t, vtop->c) and free function |
398 | /* generate function call with address in (vtop->t, vtop->c) and free function |
399 | context. Stack entry is popped */ |
399 | context. Stack entry is popped */ |
400 | void gfunc_call(GFuncContext *c) |
400 | void gfunc_call(GFuncContext *c) |
401 | { |
401 | { |
402 | char buf[1024]; |
402 | char buf[1024]; |
403 | 403 | ||
404 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
404 | if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { |
405 | /* XXX: more info needed from tcc */ |
405 | /* XXX: more info needed from tcc */ |
406 | il_type_to_str(buf, sizeof(buf), vtop->t, "xxx"); |
406 | il_type_to_str(buf, sizeof(buf), vtop->t, "xxx"); |
407 | fprintf(il_outfile, " call %s\n", buf); |
407 | fprintf(il_outfile, " call %s\n", buf); |
408 | } else { |
408 | } else { |
409 | /* indirect call */ |
409 | /* indirect call */ |
410 | gv(RC_INT); |
410 | gv(RC_INT); |
411 | il_type_to_str(buf, sizeof(buf), vtop->t, NULL); |
411 | il_type_to_str(buf, sizeof(buf), vtop->t, NULL); |
412 | fprintf(il_outfile, " calli %s\n", buf); |
412 | fprintf(il_outfile, " calli %s\n", buf); |
413 | } |
413 | } |
414 | vtop--; |
414 | vtop--; |
415 | } |
415 | } |
416 | 416 | ||
417 | /* generate function prolog of type 't' */ |
417 | /* generate function prolog of type 't' */ |
418 | void gfunc_prolog(int t) |
418 | void gfunc_prolog(int t) |
419 | { |
419 | { |
420 | int addr, u, func_call; |
420 | int addr, u, func_call; |
421 | Sym *sym; |
421 | Sym *sym; |
422 | char buf[1024]; |
422 | char buf[1024]; |
423 | 423 | ||
424 | init_outfile(); |
424 | init_outfile(); |
425 | 425 | ||
426 | /* XXX: pass function name to gfunc_prolog */ |
426 | /* XXX: pass function name to gfunc_prolog */ |
427 | il_type_to_str(buf, sizeof(buf), t, funcname); |
427 | il_type_to_str(buf, sizeof(buf), t, funcname); |
428 | fprintf(il_outfile, ".method static %s il managed\n", buf); |
428 | fprintf(il_outfile, ".method static %s il managed\n", buf); |
429 | fprintf(il_outfile, "{\n"); |
429 | fprintf(il_outfile, "{\n"); |
430 | /* XXX: cannot do better now */ |
430 | /* XXX: cannot do better now */ |
431 | fprintf(il_outfile, " .maxstack %d\n", NB_REGS); |
431 | fprintf(il_outfile, " .maxstack %d\n", NB_REGS); |
432 | fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n"); |
432 | fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n"); |
433 | 433 | ||
434 | if (!strcmp(funcname, "main")) |
434 | if (!strcmp(funcname, "main")) |
435 | fprintf(il_outfile, " .entrypoint\n"); |
435 | fprintf(il_outfile, " .entrypoint\n"); |
436 | 436 | ||
437 | sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
437 | sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT); |
438 | func_call = sym->r; |
438 | func_call = sym->r; |
439 | 439 | ||
440 | addr = ARG_BASE; |
440 | addr = ARG_BASE; |
441 | /* if the function returns a structure, then add an |
441 | /* if the function returns a structure, then add an |
442 | implicit pointer parameter */ |
442 | implicit pointer parameter */ |
443 | func_vt = sym->t; |
443 | func_vt = sym->t; |
- | 444 | func_var = (sym->c == FUNC_ELLIPSIS); |
|
444 | if ((func_vt & VT_BTYPE) == VT_STRUCT) { |
445 | if ((func_vt & VT_BTYPE) == VT_STRUCT) { |
445 | func_vc = addr; |
446 | func_vc = addr; |
446 | addr++; |
447 | addr++; |
447 | } |
448 | } |
448 | /* define parameters */ |
449 | /* define parameters */ |
449 | while ((sym = sym->next) != NULL) { |
450 | while ((sym = sym->next) != NULL) { |
450 | u = sym->t; |
451 | u = sym->t; |
451 | sym_push(sym->v & ~SYM_FIELD, u, |
452 | sym_push(sym->v & ~SYM_FIELD, u, |
452 | VT_LOCAL | VT_LVAL, addr); |
453 | VT_LOCAL | lvalue_type(sym->type.t), addr); |
453 | addr++; |
454 | addr++; |
454 | } |
455 | } |
455 | } |
456 | } |
456 | 457 | ||
457 | /* generate function epilog */ |
458 | /* generate function epilog */ |
458 | void gfunc_epilog(void) |
459 | void gfunc_epilog(void) |
459 | { |
460 | { |
460 | out_op(IL_OP_RET); |
461 | out_op(IL_OP_RET); |
461 | fprintf(il_outfile, "}\n\n"); |
462 | fprintf(il_outfile, "}\n\n"); |
462 | } |
463 | } |
463 | 464 | ||
464 | /* generate a jump to a label */ |
465 | /* generate a jump to a label */ |
465 | int gjmp(int t) |
466 | int gjmp(int t) |
466 | { |
467 | { |
467 | return out_opj(IL_OP_BR, t); |
468 | return out_opj(IL_OP_BR, t); |
468 | } |
469 | } |
469 | 470 | ||
470 | /* generate a jump to a fixed address */ |
471 | /* generate a jump to a fixed address */ |
471 | void gjmp_addr(int a) |
472 | void gjmp_addr(int a) |
472 | { |
473 | { |
473 | /* XXX: handle syms */ |
474 | /* XXX: handle syms */ |
474 | out_opi(IL_OP_BR, a); |
475 | out_opi(IL_OP_BR, a); |
475 | } |
476 | } |
476 | 477 | ||
477 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
478 | /* generate a test. set 'inv' to invert test. Stack entry is popped */ |
478 | int gtst(int inv, int t) |
479 | int gtst(int inv, int t) |
479 | { |
480 | { |
480 | int v, *p, c; |
481 | int v, *p, c; |
481 | 482 | ||
482 | v = vtop->r & VT_VALMASK; |
483 | v = vtop->r & VT_VALMASK; |
483 | if (v == VT_CMP) { |
484 | if (v == VT_CMP) { |
484 | c = vtop->c.i ^ inv; |
485 | c = vtop->c.i ^ inv; |
485 | switch(c) { |
486 | switch(c) { |
486 | case TOK_EQ: |
487 | case TOK_EQ: |
487 | c = IL_OP_BEQ; |
488 | c = IL_OP_BEQ; |
488 | break; |
489 | break; |
489 | case TOK_NE: |
490 | case TOK_NE: |
490 | c = IL_OP_BNE_UN; |
491 | c = IL_OP_BNE_UN; |
491 | break; |
492 | break; |
492 | case TOK_LT: |
493 | case TOK_LT: |
493 | c = IL_OP_BLT; |
494 | c = IL_OP_BLT; |
494 | break; |
495 | break; |
495 | case TOK_LE: |
496 | case TOK_LE: |
496 | c = IL_OP_BLE; |
497 | c = IL_OP_BLE; |
497 | break; |
498 | break; |
498 | case TOK_GT: |
499 | case TOK_GT: |
499 | c = IL_OP_BGT; |
500 | c = IL_OP_BGT; |
500 | break; |
501 | break; |
501 | case TOK_GE: |
502 | case TOK_GE: |
502 | c = IL_OP_BGE; |
503 | c = IL_OP_BGE; |
503 | break; |
504 | break; |
504 | case TOK_ULT: |
505 | case TOK_ULT: |
505 | c = IL_OP_BLT_UN; |
506 | c = IL_OP_BLT_UN; |
506 | break; |
507 | break; |
507 | case TOK_ULE: |
508 | case TOK_ULE: |
508 | c = IL_OP_BLE_UN; |
509 | c = IL_OP_BLE_UN; |
509 | break; |
510 | break; |
510 | case TOK_UGT: |
511 | case TOK_UGT: |
511 | c = IL_OP_BGT_UN; |
512 | c = IL_OP_BGT_UN; |
512 | break; |
513 | break; |
513 | case TOK_UGE: |
514 | case TOK_UGE: |
514 | c = IL_OP_BGE_UN; |
515 | c = IL_OP_BGE_UN; |
515 | break; |
516 | break; |
516 | } |
517 | } |
517 | t = out_opj(c, t); |
518 | t = out_opj(c, t); |
518 | } else if (v == VT_JMP || v == VT_JMPI) { |
519 | } else if (v == VT_JMP || v == VT_JMPI) { |
519 | /* && or || optimization */ |
520 | /* && or || optimization */ |
520 | if ((v & 1) == inv) { |
521 | if ((v & 1) == inv) { |
521 | /* insert vtop->c jump list in t */ |
522 | /* insert vtop->c jump list in t */ |
522 | p = &vtop->c.i; |
523 | p = &vtop->c.i; |
523 | while (*p != 0) |
524 | while (*p != 0) |
524 | p = (int *)*p; |
525 | p = (int *)*p; |
525 | *p = t; |
526 | *p = t; |
526 | t = vtop->c.i; |
527 | t = vtop->c.i; |
527 | } else { |
528 | } else { |
528 | t = gjmp(t); |
529 | t = gjmp(t); |
529 | gsym(vtop->c.i); |
530 | gsym(vtop->c.i); |
530 | } |
531 | } |
531 | } else { |
- | |
532 | if (is_float(vtop->t)) { |
- | |
533 | vpushi(0); |
- | |
534 | gen_op(TOK_NE); |
- | |
535 | } |
- | |
536 | if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) { |
- | |
537 | /* constant jmp optimization */ |
- | |
538 | if ((vtop->c.i != 0) != inv) |
- | |
539 | t = gjmp(t); |
- | |
540 | } else { |
- | |
541 | v = gv(RC_INT); |
- | |
542 | t = out_opj(IL_OP_BRTRUE - inv, t); |
- | |
543 | } |
- | |
544 | } |
532 | } |
545 | vtop--; |
533 | vtop--; |
546 | return t; |
534 | return t; |
547 | } |
535 | } |
548 | 536 | ||
549 | /* generate an integer binary operation */ |
537 | /* generate an integer binary operation */ |
550 | void gen_opi(int op) |
538 | void gen_opi(int op) |
551 | { |
539 | { |
552 | gv2(RC_ST1, RC_ST0); |
540 | gv2(RC_ST1, RC_ST0); |
553 | switch(op) { |
541 | switch(op) { |
554 | case '+': |
542 | case '+': |
555 | out_op(IL_OP_ADD); |
543 | out_op(IL_OP_ADD); |
556 | goto std_op; |
544 | goto std_op; |
557 | case '-': |
545 | case '-': |
558 | out_op(IL_OP_SUB); |
546 | out_op(IL_OP_SUB); |
559 | goto std_op; |
547 | goto std_op; |
560 | case '&': |
548 | case '&': |
561 | out_op(IL_OP_AND); |
549 | out_op(IL_OP_AND); |
562 | goto std_op; |
550 | goto std_op; |
563 | case '^': |
551 | case '^': |
564 | out_op(IL_OP_XOR); |
552 | out_op(IL_OP_XOR); |
565 | goto std_op; |
553 | goto std_op; |
566 | case '|': |
554 | case '|': |
567 | out_op(IL_OP_OR); |
555 | out_op(IL_OP_OR); |
568 | goto std_op; |
556 | goto std_op; |
569 | case '*': |
557 | case '*': |
570 | out_op(IL_OP_MUL); |
558 | out_op(IL_OP_MUL); |
571 | goto std_op; |
559 | goto std_op; |
572 | case TOK_SHL: |
560 | case TOK_SHL: |
573 | out_op(IL_OP_SHL); |
561 | out_op(IL_OP_SHL); |
574 | goto std_op; |
562 | goto std_op; |
575 | case TOK_SHR: |
563 | case TOK_SHR: |
576 | out_op(IL_OP_SHR_UN); |
564 | out_op(IL_OP_SHR_UN); |
577 | goto std_op; |
565 | goto std_op; |
578 | case TOK_SAR: |
566 | case TOK_SAR: |
579 | out_op(IL_OP_SHR); |
567 | out_op(IL_OP_SHR); |
580 | goto std_op; |
568 | goto std_op; |
581 | case '/': |
569 | case '/': |
582 | case TOK_PDIV: |
570 | case TOK_PDIV: |
583 | out_op(IL_OP_DIV); |
571 | out_op(IL_OP_DIV); |
584 | goto std_op; |
572 | goto std_op; |
585 | case TOK_UDIV: |
573 | case TOK_UDIV: |
586 | out_op(IL_OP_DIV_UN); |
574 | out_op(IL_OP_DIV_UN); |
587 | goto std_op; |
575 | goto std_op; |
588 | case '%': |
576 | case '%': |
589 | out_op(IL_OP_REM); |
577 | out_op(IL_OP_REM); |
590 | goto std_op; |
578 | goto std_op; |
591 | case TOK_UMOD: |
579 | case TOK_UMOD: |
592 | out_op(IL_OP_REM_UN); |
580 | out_op(IL_OP_REM_UN); |
593 | std_op: |
581 | std_op: |
594 | vtop--; |
582 | vtop--; |
595 | vtop[0].r = REG_ST0; |
583 | vtop[0].r = REG_ST0; |
596 | break; |
584 | break; |
597 | case TOK_EQ: |
585 | case TOK_EQ: |
598 | case TOK_NE: |
586 | case TOK_NE: |
599 | case TOK_LT: |
587 | case TOK_LT: |
600 | case TOK_LE: |
588 | case TOK_LE: |
601 | case TOK_GT: |
589 | case TOK_GT: |
602 | case TOK_GE: |
590 | case TOK_GE: |
603 | case TOK_ULT: |
591 | case TOK_ULT: |
604 | case TOK_ULE: |
592 | case TOK_ULE: |
605 | case TOK_UGT: |
593 | case TOK_UGT: |
606 | case TOK_UGE: |
594 | case TOK_UGE: |
607 | vtop--; |
595 | vtop--; |
608 | vtop[0].r = VT_CMP; |
596 | vtop[0].r = VT_CMP; |
609 | vtop[0].c.i = op; |
597 | vtop[0].c.i = op; |
610 | break; |
598 | break; |
611 | } |
599 | } |
612 | } |
600 | } |
613 | 601 | ||
614 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
602 | /* generate a floating point operation 'v = t1 op t2' instruction. The |
615 | two operands are guaranted to have the same floating point type */ |
603 | two operands are guaranted to have the same floating point type */ |
616 | void gen_opf(int op) |
604 | void gen_opf(int op) |
617 | { |
605 | { |
618 | /* same as integer */ |
606 | /* same as integer */ |
619 | gen_opi(op); |
607 | gen_opi(op); |
620 | } |
608 | } |
621 | 609 | ||
622 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
610 | /* convert integers to fp 't' type. Must handle 'int', 'unsigned int' |
623 | and 'long long' cases. */ |
611 | and 'long long' cases. */ |
624 | void gen_cvt_itof(int t) |
612 | void gen_cvt_itof(int t) |
625 | { |
613 | { |
626 | gv(RC_ST0); |
614 | gv(RC_ST0); |
627 | if (t == VT_FLOAT) |
615 | if (t == VT_FLOAT) |
628 | out_op(IL_OP_CONV_R4); |
616 | out_op(IL_OP_CONV_R4); |
629 | else |
617 | else |
630 | out_op(IL_OP_CONV_R8); |
618 | out_op(IL_OP_CONV_R8); |
631 | } |
619 | } |
632 | 620 | ||
633 | /* convert fp to int 't' type */ |
621 | /* convert fp to int 't' type */ |
634 | /* XXX: handle long long case */ |
622 | /* XXX: handle long long case */ |
635 | void gen_cvt_ftoi(int t) |
623 | void gen_cvt_ftoi(int t) |
636 | { |
624 | { |
637 | gv(RC_ST0); |
625 | gv(RC_ST0); |
638 | switch(t) { |
626 | switch(t) { |
639 | case VT_INT | VT_UNSIGNED: |
627 | case VT_INT | VT_UNSIGNED: |
640 | out_op(IL_OP_CONV_U4); |
628 | out_op(IL_OP_CONV_U4); |
641 | break; |
629 | break; |
642 | case VT_LLONG: |
630 | case VT_LLONG: |
643 | out_op(IL_OP_CONV_I8); |
631 | out_op(IL_OP_CONV_I8); |
644 | break; |
632 | break; |
645 | case VT_LLONG | VT_UNSIGNED: |
633 | case VT_LLONG | VT_UNSIGNED: |
646 | out_op(IL_OP_CONV_U8); |
634 | out_op(IL_OP_CONV_U8); |
647 | break; |
635 | break; |
648 | default: |
636 | default: |
649 | out_op(IL_OP_CONV_I4); |
637 | out_op(IL_OP_CONV_I4); |
650 | break; |
638 | break; |
651 | } |
639 | } |
652 | } |
640 | } |
653 | 641 | ||
654 | /* convert from one floating point type to another */ |
642 | /* convert from one floating point type to another */ |
655 | void gen_cvt_ftof(int t) |
643 | void gen_cvt_ftof(int t) |
656 | { |
644 | { |
657 | gv(RC_ST0); |
645 | gv(RC_ST0); |
658 | if (t == VT_FLOAT) { |
646 | if (t == VT_FLOAT) { |
659 | out_op(IL_OP_CONV_R4); |
647 | out_op(IL_OP_CONV_R4); |
660 | } else { |
648 | } else { |
661 | out_op(IL_OP_CONV_R8); |
649 | out_op(IL_OP_CONV_R8); |
662 | } |
650 | } |
663 | } |
651 | } |
664 | 652 | ||
665 | /* end of CIL code generator */ |
653 | /* end of CIL code generator */ |
666 | /*************************************************************/=>=>=>=>=>=>=>=>=>=> |
654 | /*************************************************************/=>=>=>=>=>=>=>=>=>=> |