Subversion Repositories Kolibri OS

Rev

Rev 647 | Details | Compare with Previous | Last modification | View Log | RSS feed

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