2 * CIL code generator for TCC
4 * Copyright (c) 2002 Fabrice Bellard
6 * 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.
11 * 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.
16 * 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
21 /* number of available registers */
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
26 assumptions on it). */
27 #define RC_ST 0x0001 /* any stack entry */
28 #define RC_ST0 0x0002 /* top of stack */
29 #define RC_ST1 0x0004 /* top - 1 */
32 #define RC_FLOAT RC_ST
33 #define RC_IRET RC_ST0 /* function return: integer register */
34 #define RC_LRET RC_ST0 /* function return: second integer register */
35 #define RC_FRET RC_ST0 /* function return: float register */
37 /* pretty names for the registers */
44 const int reg_classes
[NB_REGS
] = {
45 /* ST0 */ RC_ST
| RC_ST0
,
46 /* ST1 */ RC_ST
| RC_ST1
,
50 /* return registers for function */
51 #define REG_IRET REG_ST0 /* single word int return register */
52 #define REG_LRET REG_ST0 /* second word return register (for long long) */
53 #define REG_FRET REG_ST0 /* float return register */
55 /* defined if function parameters must be evaluated in reverse order */
56 //#define INVERT_FUNC_PARAMS
58 /* defined if structures are passed as pointers. Otherwise structures
59 are directly pushed on stack. */
60 //#define FUNC_STRUCT_PARAM_AS_PTR
62 /* pointer size, in bytes */
65 /* long double size and alignment, in bytes */
66 #define LDOUBLE_SIZE 8
67 #define LDOUBLE_ALIGN 8
69 /* function call context */
70 typedef struct GFuncContext
{
71 int func_call
; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
74 /******************************************************/
75 /* opcode definitions */
77 #define IL_OP_PREFIX 0xFE
80 #define OP(name, str, n) IL_OP_ ## name = n,
81 #include "il-opcodes.h"
85 char *il_opcodes_str
[] = {
86 #define OP(name, str, n) [n] = str,
87 #include "il-opcodes.h"
91 /******************************************************/
93 /* arguments variable numbers start from there */
94 #define ARG_BASE 0x70000000
96 static FILE *il_outfile
;
98 static void out_byte(int c
)
103 static void out_le32(int c
)
111 static void init_outfile(void)
116 ".assembly extern mscorlib\n"
123 static void out_op1(int op
)
126 out_byte(IL_OP_PREFIX
);
130 /* output an opcode with prefix */
131 static void out_op(int op
)
134 fprintf(il_outfile
, " %s\n", il_opcodes_str
[op
]);
137 static void out_opb(int op
, int c
)
141 fprintf(il_outfile
, " %s %d\n", il_opcodes_str
[op
], c
);
144 static void out_opi(int op
, int c
)
148 fprintf(il_outfile
, " %s 0x%x\n", il_opcodes_str
[op
], c
);
151 /* XXX: not complete */
152 static void il_type_to_str(char *buf
, int buf_size
,
153 int t
, const char *varstr
)
164 pstrcat(buf
, buf_size
, "unsigned ");
193 pstrcat(buf
, buf_size
, tstr
);
196 error("structures not handled yet");
199 s
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
200 il_type_to_str(buf
, buf_size
, s
->t
, varstr
);
201 pstrcat(buf
, buf_size
, "(");
204 il_type_to_str(buf1
, sizeof(buf1
), sa
->t
, NULL
);
205 pstrcat(buf
, buf_size
, buf1
);
208 pstrcat(buf
, buf_size
, ", ");
210 pstrcat(buf
, buf_size
, ")");
213 s
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
214 pstrcpy(buf1
, sizeof(buf1
), "*");
216 pstrcat(buf1
, sizeof(buf1
), varstr
);
217 il_type_to_str(buf
, buf_size
, s
->t
, buf1
);
221 pstrcat(buf
, buf_size
, " ");
222 pstrcat(buf
, buf_size
, varstr
);
228 /* patch relocation entry with value 'val' */
229 void greloc_patch1(Reloc
*p
, int val
)
233 /* output a symbol and patch all calls to it */
238 /* output jump and return symbol */
239 static int out_opj(int op
, int c
)
244 c
= ind
- (int)cur_text_section
->data
;
246 fprintf(il_outfile
, " %s L%d\n", il_opcodes_str
[op
], c
);
252 fprintf(il_outfile
, "L%d:\n", t
);
255 /* load 'r' from value 'sv' */
256 void load(int r
, SValue
*sv
)
260 v
= sv
->r
& VT_VALMASK
;
264 if (sv
->r
& VT_LVAL
) {
266 if (fc
>= ARG_BASE
) {
268 if (fc
>= 0 && fc
<= 4) {
269 out_op(IL_OP_LDARG_0
+ fc
);
270 } else if (fc
<= 0xff) {
271 out_opb(IL_OP_LDARG_S
, fc
);
273 out_opi(IL_OP_LDARG
, fc
);
276 if (fc
>= 0 && fc
<= 4) {
277 out_op(IL_OP_LDLOC_0
+ fc
);
278 } else if (fc
<= 0xff) {
279 out_opb(IL_OP_LDLOC_S
, fc
);
281 out_opi(IL_OP_LDLOC
, fc
);
284 } else if (v
== VT_CONST
) {
285 /* XXX: handle globals */
286 out_opi(IL_OP_LDSFLD
, 0);
288 if ((ft
& VT_BTYPE
) == VT_FLOAT
) {
289 out_op(IL_OP_LDIND_R4
);
290 } else if ((ft
& VT_BTYPE
) == VT_DOUBLE
) {
291 out_op(IL_OP_LDIND_R8
);
292 } else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
) {
293 out_op(IL_OP_LDIND_R8
);
294 } else if ((ft
& VT_TYPE
) == VT_BYTE
)
295 out_op(IL_OP_LDIND_I1
);
296 else if ((ft
& VT_TYPE
) == (VT_BYTE
| VT_UNSIGNED
))
297 out_op(IL_OP_LDIND_U1
);
298 else if ((ft
& VT_TYPE
) == VT_SHORT
)
299 out_op(IL_OP_LDIND_I2
);
300 else if ((ft
& VT_TYPE
) == (VT_SHORT
| VT_UNSIGNED
))
301 out_op(IL_OP_LDIND_U2
);
303 out_op(IL_OP_LDIND_I4
);
307 /* XXX: handle globals */
308 if (fc
>= -1 && fc
<= 8) {
309 out_op(IL_OP_LDC_I4_M1
+ fc
+ 1);
311 out_opi(IL_OP_LDC_I4
, fc
);
313 } else if (v
== VT_LOCAL
) {
314 if (fc
>= ARG_BASE
) {
317 out_opb(IL_OP_LDARGA_S
, fc
);
319 out_opi(IL_OP_LDARGA
, fc
);
323 out_opb(IL_OP_LDLOCA_S
, fc
);
325 out_opi(IL_OP_LDLOCA
, fc
);
334 /* store register 'r' in lvalue 'v' */
335 void store(int r
, SValue
*sv
)
339 v
= sv
->r
& VT_VALMASK
;
343 if (fc
>= ARG_BASE
) {
345 /* XXX: check IL arg store semantics */
347 out_opb(IL_OP_STARG_S
, fc
);
349 out_opi(IL_OP_STARG
, fc
);
352 if (fc
>= 0 && fc
<= 4) {
353 out_op(IL_OP_STLOC_0
+ fc
);
354 } else if (fc
<= 0xff) {
355 out_opb(IL_OP_STLOC_S
, fc
);
357 out_opi(IL_OP_STLOC
, fc
);
360 } else if (v
== VT_CONST
) {
361 /* XXX: handle globals */
362 out_opi(IL_OP_STSFLD
, 0);
364 if ((ft
& VT_BTYPE
) == VT_FLOAT
)
365 out_op(IL_OP_STIND_R4
);
366 else if ((ft
& VT_BTYPE
) == VT_DOUBLE
)
367 out_op(IL_OP_STIND_R8
);
368 else if ((ft
& VT_BTYPE
) == VT_LDOUBLE
)
369 out_op(IL_OP_STIND_R8
);
370 else if ((ft
& VT_BTYPE
) == VT_BYTE
)
371 out_op(IL_OP_STIND_I1
);
372 else if ((ft
& VT_BTYPE
) == VT_SHORT
)
373 out_op(IL_OP_STIND_I2
);
375 out_op(IL_OP_STIND_I4
);
379 /* start function call and return function call context */
380 void gfunc_start(GFuncContext
*c
, int func_call
)
382 c
->func_call
= func_call
;
385 /* push function parameter which is in (vtop->t, vtop->c). Stack entry
387 void gfunc_param(GFuncContext
*c
)
389 if ((vtop
->t
& VT_BTYPE
) == VT_STRUCT
) {
390 error("structures passed as value not handled yet");
392 /* simply push on stack */
398 /* generate function call with address in (vtop->t, vtop->c) and free function
399 context. Stack entry is popped */
400 void gfunc_call(GFuncContext
*c
)
404 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
) {
405 /* XXX: more info needed from tcc */
406 il_type_to_str(buf
, sizeof(buf
), vtop
->t
, "xxx");
407 fprintf(il_outfile
, " call %s\n", buf
);
411 il_type_to_str(buf
, sizeof(buf
), vtop
->t
, NULL
);
412 fprintf(il_outfile
, " calli %s\n", buf
);
417 /* generate function prolog of type 't' */
418 void gfunc_prolog(int t
)
420 int addr
, u
, func_call
;
426 /* XXX: pass function name to gfunc_prolog */
427 il_type_to_str(buf
, sizeof(buf
), t
, funcname
);
428 fprintf(il_outfile
, ".method static %s il managed\n", buf
);
429 fprintf(il_outfile
, "{\n");
430 /* XXX: cannot do better now */
431 fprintf(il_outfile
, " .maxstack %d\n", NB_REGS
);
432 fprintf(il_outfile
, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n");
434 if (!strcmp(funcname
, "main"))
435 fprintf(il_outfile
, " .entrypoint\n");
437 sym
= sym_find((unsigned)t
>> VT_STRUCT_SHIFT
);
441 /* if the function returns a structure, then add an
442 implicit pointer parameter */
444 if ((func_vt
& VT_BTYPE
) == VT_STRUCT
) {
448 /* define parameters */
449 while ((sym
= sym
->next
) != NULL
) {
451 sym_push(sym
->v
& ~SYM_FIELD
, u
,
452 VT_LOCAL
| lvalue_type(sym
->type
.t
), addr
);
457 /* generate function epilog */
458 void gfunc_epilog(void)
461 fprintf(il_outfile
, "}\n\n");
464 /* generate a jump to a label */
467 return out_opj(IL_OP_BR
, t
);
470 /* generate a jump to a fixed address */
471 void gjmp_addr(int a
)
473 /* XXX: handle syms */
474 out_opi(IL_OP_BR
, a
);
477 /* generate a test. set 'inv' to invert test. Stack entry is popped */
478 int gtst(int inv
, int t
)
482 v
= vtop
->r
& VT_VALMASK
;
518 } else if (v
== VT_JMP
|| v
== VT_JMPI
) {
519 /* && or || optimization */
520 if ((v
& 1) == inv
) {
521 /* insert vtop->c jump list in t */
532 if (is_float(vtop
->t
)) {
536 if ((vtop
->r
& (VT_VALMASK
| VT_LVAL
| VT_FORWARD
)) == VT_CONST
) {
537 /* constant jmp optimization */
538 if ((vtop
->c
.i
!= 0) != inv
)
542 t
= out_opj(IL_OP_BRTRUE
- inv
, t
);
549 /* generate an integer binary operation */
576 out_op(IL_OP_SHR_UN
);
586 out_op(IL_OP_DIV_UN
);
592 out_op(IL_OP_REM_UN
);
614 /* generate a floating point operation 'v = t1 op t2' instruction. The
615 two operands are guaranted to have the same floating point type */
618 /* same as integer */
622 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
623 and 'long long' cases. */
624 void gen_cvt_itof(int t
)
628 out_op(IL_OP_CONV_R4
);
630 out_op(IL_OP_CONV_R8
);
633 /* convert fp to int 't' type */
634 /* XXX: handle long long case */
635 void gen_cvt_ftoi(int t
)
639 case VT_INT
| VT_UNSIGNED
:
640 out_op(IL_OP_CONV_U4
);
643 out_op(IL_OP_CONV_I8
);
645 case VT_LLONG
| VT_UNSIGNED
:
646 out_op(IL_OP_CONV_U8
);
649 out_op(IL_OP_CONV_I4
);
654 /* convert from one floating point type to another */
655 void gen_cvt_ftof(int t
)
659 out_op(IL_OP_CONV_R4
);
661 out_op(IL_OP_CONV_R8
);
665 /* end of CIL code generator */
666 /*************************************************************/