Define __ARM_PCS_VFP in hardfloat compilation mode
[tinycc.git] / il-gen.c
1 /*
2  *  CIL code generator for TCC
3  * 
4  *  Copyright (c) 2002 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             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
44 const int reg_classes[NB_REGS] = {
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 */
56 /* #define INVERT_FUNC_PARAMS */
57
58 /* defined if structures are passed as pointers. Otherwise structures
59    are directly pushed on stack. */
60 /* #define FUNC_STRUCT_PARAM_AS_PTR */
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:
196         tcc_error("structures not handled yet");
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) {
390         tcc_error("structures passed as value not handled yet");
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;
444     if ((func_vt & VT_BTYPE) == VT_STRUCT) {
445         func_vc = addr;
446         addr++;
447     }
448     /* define parameters */
449     while ((sym = sym->next) != NULL) {
450         u = sym->t;
451         sym_push(sym->v & ~SYM_FIELD, u,
452                  VT_LOCAL | lvalue_type(sym->type.t), addr);
453         addr++;
454     }
455 }
456
457 /* generate function epilog */
458 void gfunc_epilog(void)
459 {
460     out_op(IL_OP_RET);
461     fprintf(il_outfile, "}\n\n");
462 }
463
464 /* generate a jump to a label */
465 int gjmp(int t)
466 {
467     return out_opj(IL_OP_BR, t);
468 }
469
470 /* generate a jump to a fixed address */
471 void gjmp_addr(int a)
472 {
473     /* XXX: handle syms */
474     out_opi(IL_OP_BR, a);
475 }
476
477 /* generate a test. set 'inv' to invert test. Stack entry is popped */
478 int gtst(int inv, int t)
479 {
480     int v, *p, c;
481
482     v = vtop->r & VT_VALMASK;
483     if (v == VT_CMP) {
484         c = vtop->c.i ^ inv;
485         switch(c) {
486         case TOK_EQ:
487             c = IL_OP_BEQ;
488             break;
489         case TOK_NE:
490             c = IL_OP_BNE_UN;
491             break;
492         case TOK_LT:
493             c = IL_OP_BLT;
494             break;
495         case TOK_LE:
496             c = IL_OP_BLE;
497             break;
498         case TOK_GT:
499             c = IL_OP_BGT;
500             break;
501         case TOK_GE:
502             c = IL_OP_BGE;
503             break;
504         case TOK_ULT:
505             c = IL_OP_BLT_UN;
506             break;
507         case TOK_ULE:
508             c = IL_OP_BLE_UN;
509             break;
510         case TOK_UGT:
511             c = IL_OP_BGT_UN;
512             break;
513         case TOK_UGE:
514             c = IL_OP_BGE_UN;
515             break;
516         }
517         t = out_opj(c, t);
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 */
522             p = &vtop->c.i;
523             while (*p != 0)
524                 p = (int *)*p;
525             *p = t;
526             t = vtop->c.i;
527         } else {
528             t = gjmp(t);
529             gsym(vtop->c.i);
530         }
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     }
545     vtop--;
546     return t;
547 }
548
549 /* generate an integer binary operation */
550 void gen_opi(int op)
551 {
552     gv2(RC_ST1, RC_ST0);
553     switch(op) {
554     case '+':
555         out_op(IL_OP_ADD);
556         goto std_op;
557     case '-':
558         out_op(IL_OP_SUB);
559         goto std_op;
560     case '&':
561         out_op(IL_OP_AND);
562         goto std_op;
563     case '^':
564         out_op(IL_OP_XOR);
565         goto std_op;
566     case '|':
567         out_op(IL_OP_OR);
568         goto std_op;
569     case '*':
570         out_op(IL_OP_MUL);
571         goto std_op;
572     case TOK_SHL:
573         out_op(IL_OP_SHL);
574         goto std_op;
575     case TOK_SHR:
576         out_op(IL_OP_SHR_UN);
577         goto std_op;
578     case TOK_SAR:
579         out_op(IL_OP_SHR);
580         goto std_op;
581     case '/':
582     case TOK_PDIV:
583         out_op(IL_OP_DIV);
584         goto std_op;
585     case TOK_UDIV:
586         out_op(IL_OP_DIV_UN);
587         goto std_op;
588     case '%':
589         out_op(IL_OP_REM);
590         goto std_op;
591     case TOK_UMOD:
592         out_op(IL_OP_REM_UN);
593     std_op:
594         vtop--;
595         vtop[0].r = REG_ST0;
596         break;
597     case TOK_EQ:
598     case TOK_NE:
599     case TOK_LT:
600     case TOK_LE:
601     case TOK_GT:
602     case TOK_GE:
603     case TOK_ULT:
604     case TOK_ULE:
605     case TOK_UGT:
606     case TOK_UGE:
607         vtop--;
608         vtop[0].r = VT_CMP;
609         vtop[0].c.i = op;
610         break;
611     }
612 }
613
614 /* generate a floating point operation 'v = t1 op t2' instruction. The
615    two operands are guaranted to have the same floating point type */
616 void gen_opf(int op)
617 {
618     /* same as integer */
619     gen_opi(op);
620 }
621
622 /* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
623    and 'long long' cases. */
624 void gen_cvt_itof(int t)
625 {
626     gv(RC_ST0);
627     if (t == VT_FLOAT)
628         out_op(IL_OP_CONV_R4);
629     else
630         out_op(IL_OP_CONV_R8);
631 }
632
633 /* convert fp to int 't' type */
634 /* XXX: handle long long case */
635 void gen_cvt_ftoi(int t)
636 {
637     gv(RC_ST0);
638     switch(t) {
639     case VT_INT | VT_UNSIGNED:
640         out_op(IL_OP_CONV_U4);
641         break;
642     case VT_LLONG:
643         out_op(IL_OP_CONV_I8);
644         break;
645     case VT_LLONG | VT_UNSIGNED:
646         out_op(IL_OP_CONV_U8);
647         break;
648     default:
649         out_op(IL_OP_CONV_I4);
650         break;
651     }
652 }
653
654 /* convert from one floating point type to another */
655 void gen_cvt_ftof(int t)
656 {
657     gv(RC_ST0);
658     if (t == VT_FLOAT) {
659         out_op(IL_OP_CONV_R4);
660     } else {
661         out_op(IL_OP_CONV_R8);
662     }
663 }
664
665 /* end of CIL code generator */
666 /*************************************************************/
667