Subversion Repositories Kolibri OS

Rev

Rev 145 | Rev 6429 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
145 halyavin 1
/*
2
 *  X86 code generator for TCC
3
 *
4
 *  Copyright (c) 2001-2004 Fabrice Bellard
5
 *
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.
10
 *
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.
15
 *
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
19
 */
20
 
21
/* number of available registers */
22
#define NB_REGS             4
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_INT     0x0001 /* generic integer register */
28
#define RC_FLOAT   0x0002 /* generic float register */
29
#define RC_EAX     0x0004
30
#define RC_ST0     0x0008
31
#define RC_ECX     0x0010
32
#define RC_EDX     0x0020
33
#define RC_IRET    RC_EAX /* function return: integer register */
34
#define RC_LRET    RC_EDX /* 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
    TREG_EAX = 0,
40
    TREG_ECX,
41
    TREG_EDX,
42
    TREG_ST0,
43
};
44
 
45
int reg_classes[NB_REGS] = {
46
    /* eax */ RC_INT | RC_EAX,
47
    /* ecx */ RC_INT | RC_ECX,
48
    /* edx */ RC_INT | RC_EDX,
49
    /* st0 */ RC_FLOAT | RC_ST0,
50
};
51
 
52
/* return registers for function */
53
#define REG_IRET TREG_EAX /* single word int return register */
54
#define REG_LRET TREG_EDX /* second word return register (for long long) */
55
#define REG_FRET TREG_ST0 /* float return register */
56
 
57
/* defined if function parameters must be evaluated in reverse order */
58
#define INVERT_FUNC_PARAMS
59
 
60
/* defined if structures are passed as pointers. Otherwise structures
61
   are directly pushed on stack. */
62
//#define FUNC_STRUCT_PARAM_AS_PTR
63
 
64
/* pointer size, in bytes */
65
#define PTR_SIZE 4
66
 
67
/* long double size and alignment, in bytes */
68
#define LDOUBLE_SIZE  12
69
#define LDOUBLE_ALIGN 4
70
/* maximum alignment (for aligned attribute support) */
71
#define MAX_ALIGN     8
72
 
73
/******************************************************/
74
/* ELF defines */
75
 
76
#define EM_TCC_TARGET EM_386
77
 
78
/* relocation type for 32 bit data relocation */
79
#define R_DATA_32   R_386_32
80
#define R_JMP_SLOT  R_386_JMP_SLOT
81
#define R_COPY      R_386_COPY
82
 
83
#define ELF_START_ADDR 0x08048000
84
#define ELF_PAGE_SIZE  0x1000
85
 
86
/******************************************************/
87
 
88
static unsigned long func_sub_sp_offset;
89
static unsigned long func_bound_offset;
90
static int func_ret_sub;
91
 
92
/* XXX: make it faster ? */
93
void g(int c)
94
{
95
    int ind1;
96
    ind1 = ind + 1;
97
    if (ind1 > cur_text_section->data_allocated)
98
        section_realloc(cur_text_section, ind1);
99
    cur_text_section->data[ind] = c;
100
    ind = ind1;
101
}
102
 
103
void o(unsigned int c)
104
{
105
    while (c) {
106
        g(c);
107
        c = c >> 8;
108
    }
109
}
110
 
111
void gen_le32(int c)
112
{
113
    g(c);
114
    g(c >> 8);
115
    g(c >> 16);
116
    g(c >> 24);
117
}
118
 
119
/* output a symbol and patch all calls to it */
120
void gsym_addr(int t, int a)
121
{
122
    int n, *ptr;
123
    while (t) {
124
        ptr = (int *)(cur_text_section->data + t);
125
        n = *ptr; /* next value */
126
        *ptr = a - t - 4;
127
        t = n;
128
    }
129
}
130
 
131
void gsym(int t)
132
{
133
    gsym_addr(t, ind);
134
}
135
 
136
/* psym is used to put an instruction with a data field which is a
137
   reference to a symbol. It is in fact the same as oad ! */
138
#define psym oad
139
 
140
/* instruction + 4 bytes data. Return the address of the data */
141
static int oad(int c, int s)
142
{
143
    int ind1;
144
 
145
    o(c);
146
    ind1 = ind + 4;
147
    if (ind1 > cur_text_section->data_allocated)
148
        section_realloc(cur_text_section, ind1);
149
    *(int *)(cur_text_section->data + ind) = s;
150
    s = ind;
151
    ind = ind1;
152
    return s;
153
}
154
 
155
/* output constant with relocation if 'r & VT_SYM' is true */
156
static void gen_addr32(int r, Sym *sym, int c)
157
{
158
    if (r & VT_SYM)
159
        greloc(cur_text_section, sym, ind, R_386_32);
160
    gen_le32(c);
161
}
162
 
163
/* generate a modrm reference. 'op_reg' contains the addtionnal 3
164
   opcode bits */
165
static void gen_modrm(int op_reg, int r, Sym *sym, int c)
166
{
167
    op_reg = op_reg << 3;
168
    if ((r & VT_VALMASK) == VT_CONST) {
169
        /* constant memory reference */
170
        o(0x05 | op_reg);
171
        gen_addr32(r, sym, c);
172
    } else if ((r & VT_VALMASK) == VT_LOCAL) {
173
        /* currently, we use only ebp as base */
174
        if (c == (char)c) {
175
            /* short reference */
176
            o(0x45 | op_reg);
177
            g(c);
178
        } else {
179
            oad(0x85 | op_reg, c);
180
        }
181
    } else {
182
        g(0x00 | op_reg | (r & VT_VALMASK));
183
    }
184
}
185
 
186
 
187
/* load 'r' from value 'sv' */
188
void load(int r, SValue *sv)
189
{
190
    int v, t, ft, fc, fr;
191
    SValue v1;
192
 
193
    fr = sv->r;
194
    ft = sv->type.t;
195
    fc = sv->c.ul;
196
 
197
    v = fr & VT_VALMASK;
198
    if (fr & VT_LVAL) {
199
        if (v == VT_LLOCAL) {
200
            v1.type.t = VT_INT;
201
            v1.r = VT_LOCAL | VT_LVAL;
202
            v1.c.ul = fc;
203
            load(r, &v1);
204
            fr = r;
205
        }
206
        if ((ft & VT_BTYPE) == VT_FLOAT) {
207
            o(0xd9); /* flds */
208
            r = 0;
209
        } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
210
            o(0xdd); /* fldl */
211
            r = 0;
212
        } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
213
            o(0xdb); /* fldt */
214
            r = 5;
215
        } else if ((ft & VT_TYPE) == VT_BYTE) {
216
            o(0xbe0f);   /* movsbl */
217
        } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) {
218
            o(0xb60f);   /* movzbl */
219
        } else if ((ft & VT_TYPE) == VT_SHORT) {
220
            o(0xbf0f);   /* movswl */
221
        } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) {
222
            o(0xb70f);   /* movzwl */
223
        } else {
224
            o(0x8b);     /* movl */
225
        }
226
        gen_modrm(r, fr, sv->sym, fc);
227
    } else {
228
        if (v == VT_CONST) {
229
            o(0xb8 + r); /* mov $xx, r */
230
            gen_addr32(fr, sv->sym, fc);
231
        } else if (v == VT_LOCAL) {
232
            o(0x8d); /* lea xxx(%ebp), r */
233
            gen_modrm(r, VT_LOCAL, sv->sym, fc);
234
        } else if (v == VT_CMP) {
235
            oad(0xb8 + r, 0); /* mov $0, r */
236
            o(0x0f); /* setxx %br */
237
            o(fc);
238
            o(0xc0 + r);
239
        } else if (v == VT_JMP || v == VT_JMPI) {
240
            t = v & 1;
241
            oad(0xb8 + r, t); /* mov $1, r */
242
            o(0x05eb); /* jmp after */
243
            gsym(fc);
244
            oad(0xb8 + r, t ^ 1); /* mov $0, r */
245
        } else if (v != r) {
246
            o(0x89);
247
            o(0xc0 + r + v * 8); /* mov v, r */
248
        }
249
    }
250
}
251
 
252
/* store register 'r' in lvalue 'v' */
253
void store(int r, SValue *v)
254
{
255
    int fr, bt, ft, fc;
256
 
257
    ft = v->type.t;
258
    fc = v->c.ul;
259
    fr = v->r & VT_VALMASK;
260
    bt = ft & VT_BTYPE;
261
    /* XXX: incorrect if float reg to reg */
262
    if (bt == VT_FLOAT) {
263
        o(0xd9); /* fsts */
264
        r = 2;
265
    } else if (bt == VT_DOUBLE) {
266
        o(0xdd); /* fstpl */
267
        r = 2;
268
    } else if (bt == VT_LDOUBLE) {
269
        o(0xc0d9); /* fld %st(0) */
270
        o(0xdb); /* fstpt */
271
        r = 7;
272
    } else {
273
        if (bt == VT_SHORT)
274
            o(0x66);
275
        if (bt == VT_BYTE || bt == VT_BOOL)
276
            o(0x88);
277
        else
278
            o(0x89);
279
    }
280
    if (fr == VT_CONST ||
281
        fr == VT_LOCAL ||
282
        (v->r & VT_LVAL)) {
283
        gen_modrm(r, v->r, v->sym, fc);
284
    } else if (fr != r) {
285
        o(0xc0 + fr + r * 8); /* mov r, fr */
286
    }
287
}
288
 
289
static void gadd_sp(int val)
290
{
291
    if (val == (char)val) {
292
        o(0xc483);
293
        g(val);
294
    } else {
295
        oad(0xc481, val); /* add $xxx, %esp */
296
    }
297
}
298
 
299
/* 'is_jmp' is '1' if it is a jump */
300
static void gcall_or_jmp(int is_jmp)
301
{
302
    int r;
303
    if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
304
        /* constant case */
305
        if (vtop->r & VT_SYM) {
306
            /* relocation case */
307
            greloc(cur_text_section, vtop->sym,
308
                   ind + 1, R_386_PC32);
309
        } else {
310
            /* put an empty PC32 relocation */
311
            put_elf_reloc(symtab_section, cur_text_section,
312
                          ind + 1, R_386_PC32, 0);
313
        }
314
        oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
315
    } else {
316
        /* otherwise, indirect call */
317
        r = gv(RC_INT);
318
        o(0xff); /* call/jmp *r */
319
        o(0xd0 + r + (is_jmp << 4));
320
    }
321
}
322
 
323
static uint8_t fastcall_regs[3] = { TREG_EAX, TREG_EDX, TREG_ECX };
324
 
325
/* Generate function call. The function address is pushed first, then
326
   all the parameters in call order. This functions pops all the
327
   parameters and the function address. */
328
void gfunc_call(int nb_args)
329
{
330
    int size, align, r, args_size, i, func_call;
331
    Sym *func_sym;
332
 
333
    args_size = 0;
334
    for(i = 0;i < nb_args; i++) {
335
        if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
336
            size = type_size(&vtop->type, &align);
337
            /* align to stack align size */
338
            size = (size + 3) & ~3;
339
            /* allocate the necessary size on stack */
340
            oad(0xec81, size); /* sub $xxx, %esp */
341
            /* generate structure store */
342
            r = get_reg(RC_INT);
343
            o(0x89); /* mov %esp, r */
344
            o(0xe0 + r);
345
            vset(&vtop->type, r | VT_LVAL, 0);
346
            vswap();
347
            vstore();
348
            args_size += size;
349
        } else if (is_float(vtop->type.t)) {
350
            gv(RC_FLOAT); /* only one float register */
351
            if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
352
                size = 4;
353
            else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
354
                size = 8;
355
            else
356
                size = 12;
357
            oad(0xec81, size); /* sub $xxx, %esp */
358
            if (size == 12)
359
                o(0x7cdb);
360
            else
361
                o(0x5cd9 + size - 4); /* fstp[s|l] 0(%esp) */
362
            g(0x24);
363
            g(0x00);
364
            args_size += size;
365
        } else {
366
            /* simple type (currently always same size) */
367
            /* XXX: implicit cast ? */
368
            r = gv(RC_INT);
369
            if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
370
                size = 8;
371
                o(0x50 + vtop->r2); /* push r */
372
            } else {
373
                size = 4;
374
            }
375
            o(0x50 + r); /* push r */
376
            args_size += size;
377
        }
378
        vtop--;
379
    }
380
    save_regs(0); /* save used temporary registers */
381
    func_sym = vtop->type.ref;
382
    func_call = func_sym->r;
383
    /* fast call case */
384
    if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
385
        int fastcall_nb_regs;
386
        fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
387
        for(i = 0;i < fastcall_nb_regs; i++) {
388
            if (args_size <= 0)
389
                break;
390
            o(0x58 + fastcall_regs[i]); /* pop r */
391
            /* XXX: incorrect for struct/floats */
392
            args_size -= 4;
393
        }
394
    }
395
    gcall_or_jmp(0);
396
    if (args_size && func_sym->r != FUNC_STDCALL)
397
        gadd_sp(args_size);
398
    vtop--;
399
}
400
 
401
#ifdef TCC_TARGET_PE
402
#define FUNC_PROLOG_SIZE 10
403
#else
404
#define FUNC_PROLOG_SIZE 9
405
#endif
406
 
407
/* generate function prolog of type 't' */
408
void gfunc_prolog(CType *func_type)
409
{
410
    int addr, align, size, func_call, fastcall_nb_regs;
411
    int param_index, param_addr;
412
    Sym *sym;
413
    CType *type;
414
 
415
    sym = func_type->ref;
416
    func_call = sym->r;
417
    addr = 8;
418
    loc = 0;
419
    if (func_call >= FUNC_FASTCALL1 && func_call <= FUNC_FASTCALL3) {
420
        fastcall_nb_regs = func_call - FUNC_FASTCALL1 + 1;
421
    } else {
422
        fastcall_nb_regs = 0;
423
    }
424
    param_index = 0;
425
 
426
    ind += FUNC_PROLOG_SIZE;
427
    func_sub_sp_offset = ind;
428
    /* if the function returns a structure, then add an
429
       implicit pointer parameter */
430
    func_vt = sym->type;
431
    if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
432
        /* XXX: fastcall case ? */
433
        func_vc = addr;
434
        addr += 4;
435
        param_index++;
436
    }
437
    /* define parameters */
438
    while ((sym = sym->next) != NULL) {
439
        type = &sym->type;
440
        size = type_size(type, &align);
441
        size = (size + 3) & ~3;
442
#ifdef FUNC_STRUCT_PARAM_AS_PTR
443
        /* structs are passed as pointer */
444
        if ((type->t & VT_BTYPE) == VT_STRUCT) {
445
            size = 4;
446
        }
447
#endif
448
        if (param_index < fastcall_nb_regs) {
449
            /* save FASTCALL register */
450
            loc -= 4;
451
            o(0x89);     /* movl */
452
            gen_modrm(fastcall_regs[param_index], VT_LOCAL, NULL, loc);
453
            param_addr = loc;
454
        } else {
455
            param_addr = addr;
456
            addr += size;
457
        }
458
        sym_push(sym->v & ~SYM_FIELD, type,
459
                 VT_LOCAL | VT_LVAL, param_addr);
460
        param_index++;
461
    }
462
    func_ret_sub = 0;
463
    /* pascal type call ? */
464
    if (func_call == FUNC_STDCALL)
465
        func_ret_sub = addr - 8;
466
 
467
    /* leave some room for bound checking code */
468
    if (do_bounds_check) {
469
        oad(0xb8, 0); /* lbound section pointer */
470
        oad(0xb8, 0); /* call to function */
471
        func_bound_offset = lbounds_section->data_offset;
472
    }
473
}
474
 
475
/* generate function epilog */
476
void gfunc_epilog(void)
477
{
478
    int v, saved_ind;
479
 
480
#ifdef CONFIG_TCC_BCHECK
481
    if (do_bounds_check && func_bound_offset != lbounds_section->data_offset) {
482
        int saved_ind;
483
        int *bounds_ptr;
484
        Sym *sym, *sym_data;
485
        /* add end of table info */
486
        bounds_ptr = section_ptr_add(lbounds_section, sizeof(int));
487
        *bounds_ptr = 0;
488
        /* generate bound local allocation */
489
        saved_ind = ind;
490
        ind = func_sub_sp_offset;
491
        sym_data = get_sym_ref(&char_pointer_type, lbounds_section,
492
                               func_bound_offset, lbounds_section->data_offset);
493
        greloc(cur_text_section, sym_data,
494
               ind + 1, R_386_32);
495
        oad(0xb8, 0); /* mov %eax, xxx */
496
        sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0);
497
        greloc(cur_text_section, sym,
498
               ind + 1, R_386_PC32);
499
        oad(0xe8, -4);
500
        ind = saved_ind;
501
        /* generate bound check local freeing */
502
        o(0x5250); /* save returned value, if any */
503
        greloc(cur_text_section, sym_data,
504
               ind + 1, R_386_32);
505
        oad(0xb8, 0); /* mov %eax, xxx */
506
        sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0);
507
        greloc(cur_text_section, sym,
508
               ind + 1, R_386_PC32);
509
        oad(0xe8, -4);
510
        o(0x585a); /* restore returned value, if any */
511
    }
512
#endif
513
    o(0xc9); /* leave */
514
    if (func_ret_sub == 0) {
515
        o(0xc3); /* ret */
516
    } else {
517
        o(0xc2); /* ret n */
518
        g(func_ret_sub);
519
        g(func_ret_sub >> 8);
520
    }
521
    /* align local size to word & save local variables */
522
 
523
    v = (-loc + 3) & -4;
524
    saved_ind = ind;
525
    ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
526
#ifdef TCC_TARGET_PE
527
    if (v >= 4096) {
528
        Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0);
529
        oad(0xb8, v); /* mov stacksize, %eax */
530
        oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */
531
        greloc(cur_text_section, sym, ind-4, R_386_PC32);
532
    } else
533
#endif
534
    {
535
        o(0xe58955);  /* push %ebp, mov %esp, %ebp */
536
        o(0xec81);  /* sub esp, stacksize */
537
        gen_le32(v);
538
#if FUNC_PROLOG_SIZE == 10
539
        o(0x90);  /* adjust to FUNC_PROLOG_SIZE */
540
#endif
541
    }
542
    ind = saved_ind;
543
}
544
 
545
/* generate a jump to a label */
546
int gjmp(int t)
547
{
548
    return psym(0xe9, t);
549
}
550
 
551
/* generate a jump to a fixed address */
552
void gjmp_addr(int a)
553
{
554
    int r;
555
    r = a - ind - 2;
556
    if (r == (char)r) {
557
        g(0xeb);
558
        g(r);
559
    } else {
560
        oad(0xe9, a - ind - 5);
561
    }
562
}
563
 
564
/* generate a test. set 'inv' to invert test. Stack entry is popped */
565
int gtst(int inv, int t)
566
{
567
    int v, *p;
568
 
569
    v = vtop->r & VT_VALMASK;
570
    if (v == VT_CMP) {
571
        /* fast case : can jump directly since flags are set */
572
        g(0x0f);
573
        t = psym((vtop->c.i - 16) ^ inv, t);
574
    } else if (v == VT_JMP || v == VT_JMPI) {
575
        /* && or || optimization */
576
        if ((v & 1) == inv) {
577
            /* insert vtop->c jump list in t */
578
            p = &vtop->c.i;
579
            while (*p != 0)
580
                p = (int *)(cur_text_section->data + *p);
581
            *p = t;
582
            t = vtop->c.i;
583
        } else {
584
            t = gjmp(t);
585
            gsym(vtop->c.i);
586
        }
587
    } else {
588
        if (is_float(vtop->type.t)) {
589
            vpushi(0);
590
            gen_op(TOK_NE);
591
        }
592
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
593
            /* constant jmp optimization */
594
            if ((vtop->c.i != 0) != inv)
595
                t = gjmp(t);
596
        } else {
597
            v = gv(RC_INT);
598
            o(0x85);
599
            o(0xc0 + v * 9);
600
            g(0x0f);
601
            t = psym(0x85 ^ inv, t);
602
        }
603
    }
604
    vtop--;
605
    return t;
606
}
607
 
608
/* generate an integer binary operation */
609
void gen_opi(int op)
610
{
611
    int r, fr, opc, c;
612
 
613
    switch(op) {
614
    case '+':
615
    case TOK_ADDC1: /* add with carry generation */
616
        opc = 0;
617
    gen_op8:
618
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
619
            /* constant case */
620
            vswap();
621
            r = gv(RC_INT);
622
            vswap();
623
            c = vtop->c.i;
624
            if (c == (char)c) {
625
                /* XXX: generate inc and dec for smaller code ? */
626
                o(0x83);
627
                o(0xc0 | (opc << 3) | r);
628
                g(c);
629
            } else {
630
                o(0x81);
631
                oad(0xc0 | (opc << 3) | r, c);
632
            }
633
        } else {
634
            gv2(RC_INT, RC_INT);
635
            r = vtop[-1].r;
636
            fr = vtop[0].r;
637
            o((opc << 3) | 0x01);
638
            o(0xc0 + r + fr * 8);
639
        }
640
        vtop--;
641
        if (op >= TOK_ULT && op <= TOK_GT) {
642
            vtop->r = VT_CMP;
643
            vtop->c.i = op;
644
        }
645
        break;
646
    case '-':
647
    case TOK_SUBC1: /* sub with carry generation */
648
        opc = 5;
649
        goto gen_op8;
650
    case TOK_ADDC2: /* add with carry use */
651
        opc = 2;
652
        goto gen_op8;
653
    case TOK_SUBC2: /* sub with carry use */
654
        opc = 3;
655
        goto gen_op8;
656
    case '&':
657
        opc = 4;
658
        goto gen_op8;
659
    case '^':
660
        opc = 6;
661
        goto gen_op8;
662
    case '|':
663
        opc = 1;
664
        goto gen_op8;
665
    case '*':
666
        gv2(RC_INT, RC_INT);
667
        r = vtop[-1].r;
668
        fr = vtop[0].r;
669
        vtop--;
670
        o(0xaf0f); /* imul fr, r */
671
        o(0xc0 + fr + r * 8);
672
        break;
673
    case TOK_SHL:
674
        opc = 4;
675
        goto gen_shift;
676
    case TOK_SHR:
677
        opc = 5;
678
        goto gen_shift;
679
    case TOK_SAR:
680
        opc = 7;
681
    gen_shift:
682
        opc = 0xc0 | (opc << 3);
683
        if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
684
            /* constant case */
685
            vswap();
686
            r = gv(RC_INT);
687
            vswap();
688
            c = vtop->c.i & 0x1f;
689
            o(0xc1); /* shl/shr/sar $xxx, r */
690
            o(opc | r);
691
            g(c);
692
        } else {
693
            /* we generate the shift in ecx */
694
            gv2(RC_INT, RC_ECX);
695
            r = vtop[-1].r;
696
            o(0xd3); /* shl/shr/sar %cl, r */
697
            o(opc | r);
698
        }
699
        vtop--;
700
        break;
701
    case '/':
702
    case TOK_UDIV:
703
    case TOK_PDIV:
704
    case '%':
705
    case TOK_UMOD:
706
    case TOK_UMULL:
707
        /* first operand must be in eax */
708
        /* XXX: need better constraint for second operand */
709
        gv2(RC_EAX, RC_ECX);
710
        r = vtop[-1].r;
711
        fr = vtop[0].r;
712
        vtop--;
713
        save_reg(TREG_EDX);
714
        if (op == TOK_UMULL) {
715
            o(0xf7); /* mul fr */
716
            o(0xe0 + fr);
717
            vtop->r2 = TREG_EDX;
718
            r = TREG_EAX;
719
        } else {
720
            if (op == TOK_UDIV || op == TOK_UMOD) {
721
                o(0xf7d231); /* xor %edx, %edx, div fr, %eax */
722
                o(0xf0 + fr);
723
            } else {
724
                o(0xf799); /* cltd, idiv fr, %eax */
725
                o(0xf8 + fr);
726
            }
727
            if (op == '%' || op == TOK_UMOD)
728
                r = TREG_EDX;
729
            else
730
                r = TREG_EAX;
731
        }
732
        vtop->r = r;
733
        break;
734
    default:
735
        opc = 7;
736
        goto gen_op8;
737
    }
738
}
739
 
740
/* generate a floating point operation 'v = t1 op t2' instruction. The
741
   two operands are guaranted to have the same floating point type */
742
/* XXX: need to use ST1 too */
743
void gen_opf(int op)
744
{
745
    int a, ft, fc, swapped, r;
746
 
747
    /* convert constants to memory references */
748
    if ((vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
749
        vswap();
750
        gv(RC_FLOAT);
751
        vswap();
752
    }
753
    if ((vtop[0].r & (VT_VALMASK | VT_LVAL)) == VT_CONST)
754
        gv(RC_FLOAT);
755
 
756
    /* must put at least one value in the floating point register */
757
    if ((vtop[-1].r & VT_LVAL) &&
758
        (vtop[0].r & VT_LVAL)) {
759
        vswap();
760
        gv(RC_FLOAT);
761
        vswap();
762
    }
763
    swapped = 0;
764
    /* swap the stack if needed so that t1 is the register and t2 is
765
       the memory reference */
766
    if (vtop[-1].r & VT_LVAL) {
767
        vswap();
768
        swapped = 1;
769
    }
770
    if (op >= TOK_ULT && op <= TOK_GT) {
771
        /* load on stack second operand */
772
        load(TREG_ST0, vtop);
773
        save_reg(TREG_EAX); /* eax is used by FP comparison code */
774
        if (op == TOK_GE || op == TOK_GT)
775
            swapped = !swapped;
776
        else if (op == TOK_EQ || op == TOK_NE)
777
            swapped = 0;
778
        if (swapped)
779
            o(0xc9d9); /* fxch %st(1) */
780
        o(0xe9da); /* fucompp */
781
        o(0xe0df); /* fnstsw %ax */
782
        if (op == TOK_EQ) {
783
            o(0x45e480); /* and $0x45, %ah */
784
            o(0x40fC80); /* cmp $0x40, %ah */
785
        } else if (op == TOK_NE) {
786
            o(0x45e480); /* and $0x45, %ah */
787
            o(0x40f480); /* xor $0x40, %ah */
788
            op = TOK_NE;
789
        } else if (op == TOK_GE || op == TOK_LE) {
790
            o(0x05c4f6); /* test $0x05, %ah */
791
            op = TOK_EQ;
792
        } else {
793
            o(0x45c4f6); /* test $0x45, %ah */
794
            op = TOK_EQ;
795
        }
796
        vtop--;
797
        vtop->r = VT_CMP;
798
        vtop->c.i = op;
799
    } else {
800
        /* no memory reference possible for long double operations */
801
        if ((vtop->type.t & VT_BTYPE) == VT_LDOUBLE) {
802
            load(TREG_ST0, vtop);
803
            swapped = !swapped;
804
        }
805
 
806
        switch(op) {
807
        default:
808
        case '+':
809
            a = 0;
810
            break;
811
        case '-':
812
            a = 4;
813
            if (swapped)
814
                a++;
815
            break;
816
        case '*':
817
            a = 1;
818
            break;
819
        case '/':
820
            a = 6;
821
            if (swapped)
822
                a++;
823
            break;
824
        }
825
        ft = vtop->type.t;
826
        fc = vtop->c.ul;
827
        if ((ft & VT_BTYPE) == VT_LDOUBLE) {
828
            o(0xde); /* fxxxp %st, %st(1) */
829
            o(0xc1 + (a << 3));
830
        } else {
831
            /* if saved lvalue, then we must reload it */
832
            r = vtop->r;
833
            if ((r & VT_VALMASK) == VT_LLOCAL) {
834
                SValue v1;
835
                r = get_reg(RC_INT);
836
                v1.type.t = VT_INT;
837
                v1.r = VT_LOCAL | VT_LVAL;
838
                v1.c.ul = fc;
839
                load(r, &v1);
840
                fc = 0;
841
            }
842
 
843
            if ((ft & VT_BTYPE) == VT_DOUBLE)
844
                o(0xdc);
845
            else
846
                o(0xd8);
847
            gen_modrm(a, r, vtop->sym, fc);
848
        }
849
        vtop--;
850
    }
851
}
852
 
853
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
854
   and 'long long' cases. */
855
void gen_cvt_itof(int t)
856
{
857
    save_reg(TREG_ST0);
858
    gv(RC_INT);
859
    if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
860
        /* signed long long to float/double/long double (unsigned case
861
           is handled generically) */
862
        o(0x50 + vtop->r2); /* push r2 */
863
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
864
        o(0x242cdf); /* fildll (%esp) */
865
        o(0x08c483); /* add $8, %esp */
866
    } else if ((vtop->type.t & (VT_BTYPE | VT_UNSIGNED)) ==
867
               (VT_INT | VT_UNSIGNED)) {
868
        /* unsigned int to float/double/long double */
869
        o(0x6a); /* push $0 */
870
        g(0x00);
871
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
872
        o(0x242cdf); /* fildll (%esp) */
873
        o(0x08c483); /* add $8, %esp */
874
    } else {
875
        /* int to float/double/long double */
876
        o(0x50 + (vtop->r & VT_VALMASK)); /* push r */
877
        o(0x2404db); /* fildl (%esp) */
878
        o(0x04c483); /* add $4, %esp */
879
    }
880
    vtop->r = TREG_ST0;
881
}
882
 
883
/* convert fp to int 't' type */
884
/* XXX: handle long long case */
885
void gen_cvt_ftoi(int t)
886
{
887
    int r, r2, size;
888
    Sym *sym;
889
    CType ushort_type;
890
 
891
    ushort_type.t = VT_SHORT | VT_UNSIGNED;
892
 
893
    gv(RC_FLOAT);
894
    if (t != VT_INT)
895
        size = 8;
896
    else
897
        size = 4;
898
 
899
    o(0x2dd9); /* ldcw xxx */
900
    sym = external_global_sym(TOK___tcc_int_fpu_control,
901
                              &ushort_type, VT_LVAL);
902
    greloc(cur_text_section, sym,
903
           ind, R_386_32);
904
    gen_le32(0);
905
 
906
    oad(0xec81, size); /* sub $xxx, %esp */
907
    if (size == 4)
908
        o(0x1cdb); /* fistpl */
909
    else
910
        o(0x3cdf); /* fistpll */
911
    o(0x24);
912
    o(0x2dd9); /* ldcw xxx */
913
    sym = external_global_sym(TOK___tcc_fpu_control,
914
                              &ushort_type, VT_LVAL);
915
    greloc(cur_text_section, sym,
916
           ind, R_386_32);
917
    gen_le32(0);
918
 
919
    r = get_reg(RC_INT);
920
    o(0x58 + r); /* pop r */
921
    if (size == 8) {
922
        if (t == VT_LLONG) {
923
            vtop->r = r; /* mark reg as used */
924
            r2 = get_reg(RC_INT);
925
            o(0x58 + r2); /* pop r2 */
926
            vtop->r2 = r2;
927
        } else {
928
            o(0x04c483); /* add $4, %esp */
929
        }
930
    }
931
    vtop->r = r;
932
}
933
 
934
/* convert from one floating point type to another */
935
void gen_cvt_ftof(int t)
936
{
937
    /* all we have to do on i386 is to put the float in a register */
938
    gv(RC_FLOAT);
939
}
940
 
941
/* computed goto support */
942
void ggoto(void)
943
{
944
    gcall_or_jmp(1);
945
    vtop--;
946
}
947
 
948
/* bound check support functions */
949
#ifdef CONFIG_TCC_BCHECK
950
 
951
/* generate a bounded pointer addition */
952
void gen_bounded_ptr_add(void)
953
{
954
    Sym *sym;
955
 
956
    /* prepare fast i386 function call (args in eax and edx) */
957
    gv2(RC_EAX, RC_EDX);
958
    /* save all temporary registers */
959
    vtop -= 2;
960
    save_regs(0);
961
    /* do a fast function call */
962
    sym = external_global_sym(TOK___bound_ptr_add, &func_old_type, 0);
963
    greloc(cur_text_section, sym,
964
           ind + 1, R_386_PC32);
965
    oad(0xe8, -4);
966
    /* returned pointer is in eax */
967
    vtop++;
968
    vtop->r = TREG_EAX | VT_BOUNDED;
969
    /* address of bounding function call point */
970
    vtop->c.ul = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
971
}
972
 
973
/* patch pointer addition in vtop so that pointer dereferencing is
974
   also tested */
975
void gen_bounded_ptr_deref(void)
976
{
977
    int func;
978
    int size, align;
979
    Elf32_Rel *rel;
980
    Sym *sym;
981
 
982
    size = 0;
983
    /* XXX: put that code in generic part of tcc */
984
    if (!is_float(vtop->type.t)) {
985
        if (vtop->r & VT_LVAL_BYTE)
986
            size = 1;
987
        else if (vtop->r & VT_LVAL_SHORT)
988
            size = 2;
989
    }
990
    if (!size)
991
        size = type_size(&vtop->type, &align);
992
    switch(size) {
993
    case  1: func = TOK___bound_ptr_indir1; break;
994
    case  2: func = TOK___bound_ptr_indir2; break;
995
    case  4: func = TOK___bound_ptr_indir4; break;
996
    case  8: func = TOK___bound_ptr_indir8; break;
997
    case 12: func = TOK___bound_ptr_indir12; break;
998
    case 16: func = TOK___bound_ptr_indir16; break;
999
    default:
1000
        error("unhandled size when derefencing bounded pointer");
1001
        func = 0;
1002
        break;
1003
    }
1004
 
1005
    /* patch relocation */
1006
    /* XXX: find a better solution ? */
1007
    rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
1008
    sym = external_global_sym(func, &func_old_type, 0);
1009
    if (!sym->c)
1010
        put_extern_sym(sym, NULL, 0, 0);
1011
    rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
1012
}
1013
#endif
1014
 
1015
/* end of X86 code generator */
1016
/*************************************************************/
1017