Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  CIL code generator for TCC
  3.  *
  4.  *  Copyright (c) 2002 Fabrice Bellard
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program 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
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. 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.         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.         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 | VT_LVAL, 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.  
  668.