added CIL target

This commit is contained in:
bellard 2002-02-10 16:14:03 +00:00
parent 421911f921
commit 5a50e73980
3 changed files with 973 additions and 8 deletions

681
il-gen.c Normal file
View File

@ -0,0 +1,681 @@
/*
* CIL code generator for TCC
*
* Copyright (c) 2002 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* number of available registers */
#define NB_REGS 3
/* a register can belong to several classes. The classes must be
sorted from more general to more precise (see gv2() code which does
assumptions on it). */
#define RC_ST 0x0001 /* any stack entry */
#define RC_ST0 0x0002 /* top of stack */
#define RC_ST1 0x0004 /* top - 1 */
#define RC_INT RC_ST
#define RC_FLOAT RC_ST
#define RC_IRET RC_ST0 /* function return: integer register */
#define RC_LRET RC_ST0 /* function return: second integer register */
#define RC_FRET RC_ST0 /* function return: float register */
/* pretty names for the registers */
enum {
REG_ST0 = 0,
REG_ST1,
REG_ST2,
};
int reg_classes[NB_REGS] = {
/* ST0 */ RC_ST | RC_ST0,
/* ST1 */ RC_ST | RC_ST1,
/* ST2 */ RC_ST,
};
/* return registers for function */
#define REG_IRET REG_ST0 /* single word int return register */
#define REG_LRET REG_ST0 /* second word return register (for long long) */
#define REG_FRET REG_ST0 /* float return register */
/* defined if function parameters must be evaluated in reverse order */
//#define INVERT_FUNC_PARAMS
/* defined if structures are passed as pointers. Otherwise structures
are directly pushed on stack. */
//#define FUNC_STRUCT_PARAM_AS_PTR
/* pointer size, in bytes */
#define PTR_SIZE 4
/* long double size and alignment, in bytes */
#define LDOUBLE_SIZE 8
#define LDOUBLE_ALIGN 8
/* function call context */
typedef struct GFuncContext {
int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
} GFuncContext;
/******************************************************/
/* opcode definitions */
#define IL_OP_PREFIX 0xFE
enum ILOPCodes {
#define OP(name, str, n) IL_OP_ ## name = n,
#include "il-opcodes.h"
#undef OP
};
char *il_opcodes_str[] = {
#define OP(name, str, n) [n] = str,
#include "il-opcodes.h"
#undef OP
};
/******************************************************/
/* arguments variable numbers start from there */
#define ARG_BASE 0x70000000
static FILE *il_outfile;
static void out_byte(int c)
{
*(char *)ind++ = c;
}
static void out_le32(int c)
{
out_byte(c);
out_byte(c >> 8);
out_byte(c >> 16);
out_byte(c >> 24);
}
static void init_outfile(void)
{
if (!il_outfile) {
il_outfile = stdout;
fprintf(il_outfile,
".assembly extern mscorlib\n"
"{\n"
".ver 1:0:2411:0\n"
"}\n\n");
}
}
static void out_op1(int op)
{
if (op & 0x100)
out_byte(IL_OP_PREFIX);
out_byte(op & 0xff);
}
/* output an opcode with prefix */
static void out_op(int op)
{
out_op1(op);
fprintf(il_outfile, " %s\n", il_opcodes_str[op]);
}
static void out_opb(int op, int c)
{
out_op1(op);
out_byte(c);
fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c);
}
static void out_opi(int op, int c)
{
out_op1(op);
out_le32(c);
fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c);
}
/* XXX: not complete */
static void il_type_to_str(char *buf, int buf_size,
int t, const char *varstr)
{
int bt;
Sym *s, *sa;
char buf1[256];
const char *tstr;
t = t & VT_TYPE;
bt = t & VT_BTYPE;
buf[0] = '\0';
if (t & VT_UNSIGNED)
pstrcat(buf, buf_size, "unsigned ");
switch(bt) {
case VT_VOID:
tstr = "void";
goto add_tstr;
case VT_BOOL:
tstr = "bool";
goto add_tstr;
case VT_BYTE:
tstr = "int8";
goto add_tstr;
case VT_SHORT:
tstr = "int16";
goto add_tstr;
case VT_ENUM:
case VT_INT:
case VT_LONG:
tstr = "int32";
goto add_tstr;
case VT_LLONG:
tstr = "int64";
goto add_tstr;
case VT_FLOAT:
tstr = "float32";
goto add_tstr;
case VT_DOUBLE:
case VT_LDOUBLE:
tstr = "float64";
add_tstr:
pstrcat(buf, buf_size, tstr);
break;
case VT_STRUCT:
error("structures not handled yet");
break;
case VT_FUNC:
s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
il_type_to_str(buf, buf_size, s->t, varstr);
pstrcat(buf, buf_size, "(");
sa = s->next;
while (sa != NULL) {
il_type_to_str(buf1, sizeof(buf1), sa->t, NULL);
pstrcat(buf, buf_size, buf1);
sa = sa->next;
if (sa)
pstrcat(buf, buf_size, ", ");
}
pstrcat(buf, buf_size, ")");
goto no_var;
case VT_PTR:
s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
pstrcpy(buf1, sizeof(buf1), "*");
if (varstr)
pstrcat(buf1, sizeof(buf1), varstr);
il_type_to_str(buf, buf_size, s->t, buf1);
goto no_var;
}
if (varstr) {
pstrcat(buf, buf_size, " ");
pstrcat(buf, buf_size, varstr);
}
no_var: ;
}
/* patch relocation entry with value 'val' */
void greloc_patch1(Reloc *p, int val)
{
}
/* output a symbol and patch all calls to it */
void gsym_addr(t, a)
{
}
/* output jump and return symbol */
static int out_opj(int op, int c)
{
out_op1(op);
out_le32(0);
if (c == 0) {
c = ind - (int)cur_text_section->data;
}
fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c);
return c;
}
void gsym(int t)
{
fprintf(il_outfile, "L%d:\n", t);
}
/* load 'r' from value 'sv' */
void load(int r, SValue *sv)
{
int v, fc, ft;
v = sv->r & VT_VALMASK;
fc = sv->c.i;
ft = sv->t;
if (sv->r & VT_LVAL) {
if (v == VT_LOCAL) {
if (fc >= ARG_BASE) {
fc -= ARG_BASE;
if (fc >= 0 && fc <= 4) {
out_op(IL_OP_LDARG_0 + fc);
} else if (fc <= 0xff) {
out_opb(IL_OP_LDARG_S, fc);
} else {
out_opi(IL_OP_LDARG, fc);
}
} else {
if (fc >= 0 && fc <= 4) {
out_op(IL_OP_LDLOC_0 + fc);
} else if (fc <= 0xff) {
out_opb(IL_OP_LDLOC_S, fc);
} else {
out_opi(IL_OP_LDLOC, fc);
}
}
} else if (v == VT_CONST) {
/* XXX: handle globals */
out_opi(IL_OP_LDSFLD, 0);
} else {
if ((ft & VT_BTYPE) == VT_FLOAT) {
out_op(IL_OP_LDIND_R4);
} else if ((ft & VT_BTYPE) == VT_DOUBLE) {
out_op(IL_OP_LDIND_R8);
} else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
out_op(IL_OP_LDIND_R8);
} else if ((ft & VT_TYPE) == VT_BYTE)
out_op(IL_OP_LDIND_I1);
else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
out_op(IL_OP_LDIND_U1);
else if ((ft & VT_TYPE) == VT_SHORT)
out_op(IL_OP_LDIND_I2);
else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
out_op(IL_OP_LDIND_U2);
else
out_op(IL_OP_LDIND_I4);
}
} else {
if (v == VT_CONST) {
/* XXX: handle globals */
if (fc >= -1 && fc <= 8) {
out_op(IL_OP_LDC_I4_M1 + fc + 1);
} else {
out_opi(IL_OP_LDC_I4, fc);
}
} else if (v == VT_LOCAL) {
if (fc >= ARG_BASE) {
fc -= ARG_BASE;
if (fc <= 0xff) {
out_opb(IL_OP_LDARGA_S, fc);
} else {
out_opi(IL_OP_LDARGA, fc);
}
} else {
if (fc <= 0xff) {
out_opb(IL_OP_LDLOCA_S, fc);
} else {
out_opi(IL_OP_LDLOCA, fc);
}
}
} else {
/* XXX: do it */
}
}
}
/* store register 'r' in lvalue 'v' */
void store(int r, SValue *sv)
{
int v, fc, ft;
v = sv->r & VT_VALMASK;
fc = sv->c.i;
ft = sv->t;
if (v == VT_LOCAL) {
if (fc >= ARG_BASE) {
fc -= ARG_BASE;
/* XXX: check IL arg store semantics */
if (fc <= 0xff) {
out_opb(IL_OP_STARG_S, fc);
} else {
out_opi(IL_OP_STARG, fc);
}
} else {
if (fc >= 0 && fc <= 4) {
out_op(IL_OP_STLOC_0 + fc);
} else if (fc <= 0xff) {
out_opb(IL_OP_STLOC_S, fc);
} else {
out_opi(IL_OP_STLOC, fc);
}
}
} else if (v == VT_CONST) {
/* XXX: handle globals */
out_opi(IL_OP_STSFLD, 0);
} else {
if ((ft & VT_BTYPE) == VT_FLOAT)
out_op(IL_OP_STIND_R4);
else if ((ft & VT_BTYPE) == VT_DOUBLE)
out_op(IL_OP_STIND_R8);
else if ((ft & VT_BTYPE) == VT_LDOUBLE)
out_op(IL_OP_STIND_R8);
else if ((ft & VT_BTYPE) == VT_BYTE)
out_op(IL_OP_STIND_I1);
else if ((ft & VT_BTYPE) == VT_SHORT)
out_op(IL_OP_STIND_I2);
else
out_op(IL_OP_STIND_I4);
}
}
/* start function call and return function call context */
void gfunc_start(GFuncContext *c, int func_call)
{
c->func_call = func_call;
}
/* push function parameter which is in (vtop->t, vtop->c). Stack entry
is then popped. */
void gfunc_param(GFuncContext *c)
{
if ((vtop->t & VT_BTYPE) == VT_STRUCT) {
error("structures passed as value not handled yet");
} else {
/* simply push on stack */
gv(RC_ST0);
}
vtop--;
}
/* generate function call with address in (vtop->t, vtop->c) and free function
context. Stack entry is popped */
void gfunc_call(GFuncContext *c)
{
char buf[1024];
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* XXX: more info needed from tcc */
il_type_to_str(buf, sizeof(buf), vtop->t, "xxx");
fprintf(il_outfile, " call %s\n", buf);
} else {
/* indirect call */
gv(RC_INT);
il_type_to_str(buf, sizeof(buf), vtop->t, NULL);
fprintf(il_outfile, " calli %s\n", buf);
}
vtop--;
}
/* generate function prolog of type 't' */
void gfunc_prolog(int t)
{
int addr, u, func_call;
Sym *sym;
char buf[1024];
init_outfile();
/* XXX: pass function name to gfunc_prolog */
il_type_to_str(buf, sizeof(buf), t, funcname);
fprintf(il_outfile, ".method static %s il managed\n", buf);
fprintf(il_outfile, "{\n");
/* XXX: cannot do better now */
fprintf(il_outfile, " .maxstack %d\n", NB_REGS);
fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n");
if (!strcmp(funcname, "main"))
fprintf(il_outfile, " .entrypoint\n");
sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
func_call = sym->r;
addr = ARG_BASE;
/* if the function returns a structure, then add an
implicit pointer parameter */
func_vt = sym->t;
if ((func_vt & VT_BTYPE) == VT_STRUCT) {
func_vc = addr;
addr++;
}
/* define parameters */
while ((sym = sym->next) != NULL) {
u = sym->t;
sym_push(sym->v & ~SYM_FIELD, u,
VT_LOCAL | VT_LVAL, addr);
addr++;
}
}
/* generate function epilog */
void gfunc_epilog(void)
{
out_op(IL_OP_RET);
fprintf(il_outfile, "}\n\n");
}
/* generate a jump to a label */
int gjmp(int t)
{
return out_opj(IL_OP_BR, t);
}
/* generate a jump to a fixed address */
void gjmp_addr(int a)
{
/* XXX: handle syms */
out_opi(IL_OP_BR, a);
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t)
{
int v, *p, c;
v = vtop->r & VT_VALMASK;
if (v == VT_CMP) {
c = vtop->c.i ^ inv;
switch(c) {
case TOK_EQ:
c = IL_OP_BEQ;
break;
case TOK_NE:
c = IL_OP_BNE_UN;
break;
case TOK_LT:
c = IL_OP_BLT;
break;
case TOK_LE:
c = IL_OP_BLE;
break;
case TOK_GT:
c = IL_OP_BGT;
break;
case TOK_GE:
c = IL_OP_BGE;
break;
case TOK_ULT:
c = IL_OP_BLT_UN;
break;
case TOK_ULE:
c = IL_OP_BLE_UN;
break;
case TOK_UGT:
c = IL_OP_BGT_UN;
break;
case TOK_UGE:
c = IL_OP_BGE_UN;
break;
}
t = out_opj(c, t);
} else if (v == VT_JMP || v == VT_JMPI) {
/* && or || optimization */
if ((v & 1) == inv) {
/* insert vtop->c jump list in t */
p = &vtop->c.i;
while (*p != 0)
p = (int *)*p;
*p = t;
t = vtop->c.i;
} else {
t = gjmp(t);
gsym(vtop->c.i);
}
} else {
if (is_float(vtop->t)) {
vpushi(0);
gen_op(TOK_NE);
}
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
/* constant jmp optimization */
if ((vtop->c.i != 0) != inv)
t = gjmp(t);
} else {
v = gv(RC_INT);
t = out_opj(IL_OP_BRTRUE - inv, t);
}
}
vtop--;
return t;
}
/* generate an integer binary operation */
void gen_opi(int op)
{
gv2(RC_ST1, RC_ST0);
switch(op) {
case '+':
out_op(IL_OP_ADD);
goto std_op;
case '-':
out_op(IL_OP_SUB);
goto std_op;
case '&':
out_op(IL_OP_AND);
goto std_op;
case '^':
out_op(IL_OP_XOR);
goto std_op;
case '|':
out_op(IL_OP_OR);
goto std_op;
case '*':
out_op(IL_OP_MUL);
goto std_op;
case TOK_SHL:
out_op(IL_OP_SHL);
goto std_op;
case TOK_SHR:
out_op(IL_OP_SHR_UN);
goto std_op;
case TOK_SAR:
out_op(IL_OP_SHR);
goto std_op;
case '/':
case TOK_PDIV:
out_op(IL_OP_DIV);
goto std_op;
case TOK_UDIV:
out_op(IL_OP_DIV_UN);
goto std_op;
case '%':
out_op(IL_OP_REM);
goto std_op;
case TOK_UMOD:
out_op(IL_OP_REM_UN);
std_op:
vtop--;
vtop[0].r = REG_ST0;
break;
case TOK_EQ:
case TOK_NE:
case TOK_LT:
case TOK_LE:
case TOK_GT:
case TOK_GE:
case TOK_ULT:
case TOK_ULE:
case TOK_UGT:
case TOK_UGE:
vtop--;
vtop[0].r = VT_CMP;
vtop[0].c.i = op;
break;
}
}
/* generate a floating point operation 'v = t1 op t2' instruction. The
two operands are guaranted to have the same floating point type */
void gen_opf(int op)
{
/* same as integer */
gen_opi(op);
}
/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
and 'long long' cases. */
void gen_cvt_itof(int t)
{
gv(RC_ST0);
if (t == VT_FLOAT)
out_op(IL_OP_CONV_R4);
else
out_op(IL_OP_CONV_R8);
}
/* convert fp to int 't' type */
/* XXX: handle long long case */
void gen_cvt_ftoi(int t)
{
gv(RC_ST0);
switch(t) {
case VT_INT | VT_UNSIGNED:
out_op(IL_OP_CONV_U4);
break;
case VT_LLONG:
out_op(IL_OP_CONV_I8);
break;
case VT_LLONG | VT_UNSIGNED:
out_op(IL_OP_CONV_U8);
break;
default:
out_op(IL_OP_CONV_I4);
break;
}
}
/* convert from one floating point type to another */
void gen_cvt_ftof(int t)
{
gv(RC_ST0);
if (t == VT_FLOAT) {
out_op(IL_OP_CONV_R4);
} else {
out_op(IL_OP_CONV_R8);
}
}
/* bound check support functions */
/* generate first part of bounded pointer addition */
void gen_bounded_ptr_add1(void)
{
/* not handled */
}
/* if deref is true, then also test dereferencing */
void gen_bounded_ptr_add2(int deref)
{
/* not handled */
}
/* end of X86 code generator */
/*************************************************************/

251
il-opcodes.h Normal file
View File

@ -0,0 +1,251 @@
/*
* CIL opcode definition
*
* Copyright (c) 2002 Fabrice Bellard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
OP(NOP, "nop", 0x00)
OP(BREAK, "break", 0x01)
OP(LDARG_0, "ldarg.0", 0x02)
OP(LDARG_1, "ldarg.1", 0x03)
OP(LDARG_2, "ldarg.2", 0x04)
OP(LDARG_3, "ldarg.3", 0x05)
OP(LDLOC_0, "ldloc.0", 0x06)
OP(LDLOC_1, "ldloc.1", 0x07)
OP(LDLOC_2, "ldloc.2", 0x08)
OP(LDLOC_3, "ldloc.3", 0x09)
OP(STLOC_0, "stloc.0", 0x0a)
OP(STLOC_1, "stloc.1", 0x0b)
OP(STLOC_2, "stloc.2", 0x0c)
OP(STLOC_3, "stloc.3", 0x0d)
OP(LDARG_S, "ldarg.s", 0x0e)
OP(LDARGA_S, "ldarga.s", 0x0f)
OP(STARG_S, "starg.s", 0x10)
OP(LDLOC_S, "ldloc.s", 0x11)
OP(LDLOCA_S, "ldloca.s", 0x12)
OP(STLOC_S, "stloc.s", 0x13)
OP(LDNULL, "ldnull", 0x14)
OP(LDC_I4_M1, "ldc.i4.m1", 0x15)
OP(LDC_I4_0, "ldc.i4.0", 0x16)
OP(LDC_I4_1, "ldc.i4.1", 0x17)
OP(LDC_I4_2, "ldc.i4.2", 0x18)
OP(LDC_I4_3, "ldc.i4.3", 0x19)
OP(LDC_I4_4, "ldc.i4.4", 0x1a)
OP(LDC_I4_5, "ldc.i4.5", 0x1b)
OP(LDC_I4_6, "ldc.i4.6", 0x1c)
OP(LDC_I4_7, "ldc.i4.7", 0x1d)
OP(LDC_I4_8, "ldc.i4.8", 0x1e)
OP(LDC_I4_S, "ldc.i4.s", 0x1f)
OP(LDC_I4, "ldc.i4", 0x20)
OP(LDC_I8, "ldc.i8", 0x21)
OP(LDC_R4, "ldc.r4", 0x22)
OP(LDC_R8, "ldc.r8", 0x23)
OP(LDPTR, "ldptr", 0x24)
OP(DUP, "dup", 0x25)
OP(POP, "pop", 0x26)
OP(JMP, "jmp", 0x27)
OP(CALL, "call", 0x28)
OP(CALLI, "calli", 0x29)
OP(RET, "ret", 0x2a)
OP(BR_S, "br.s", 0x2b)
OP(BRFALSE_S, "brfalse.s", 0x2c)
OP(BRTRUE_S, "brtrue.s", 0x2d)
OP(BEQ_S, "beq.s", 0x2e)
OP(BGE_S, "bge.s", 0x2f)
OP(BGT_S, "bgt.s", 0x30)
OP(BLE_S, "ble.s", 0x31)
OP(BLT_S, "blt.s", 0x32)
OP(BNE_UN_S, "bne.un.s", 0x33)
OP(BGE_UN_S, "bge.un.s", 0x34)
OP(BGT_UN_S, "bgt.un.s", 0x35)
OP(BLE_UN_S, "ble.un.s", 0x36)
OP(BLT_UN_S, "blt.un.s", 0x37)
OP(BR, "br", 0x38)
OP(BRFALSE, "brfalse", 0x39)
OP(BRTRUE, "brtrue", 0x3a)
OP(BEQ, "beq", 0x3b)
OP(BGE, "bge", 0x3c)
OP(BGT, "bgt", 0x3d)
OP(BLE, "ble", 0x3e)
OP(BLT, "blt", 0x3f)
OP(BNE_UN, "bne.un", 0x40)
OP(BGE_UN, "bge.un", 0x41)
OP(BGT_UN, "bgt.un", 0x42)
OP(BLE_UN, "ble.un", 0x43)
OP(BLT_UN, "blt.un", 0x44)
OP(SWITCH, "switch", 0x45)
OP(LDIND_I1, "ldind.i1", 0x46)
OP(LDIND_U1, "ldind.u1", 0x47)
OP(LDIND_I2, "ldind.i2", 0x48)
OP(LDIND_U2, "ldind.u2", 0x49)
OP(LDIND_I4, "ldind.i4", 0x4a)
OP(LDIND_U4, "ldind.u4", 0x4b)
OP(LDIND_I8, "ldind.i8", 0x4c)
OP(LDIND_I, "ldind.i", 0x4d)
OP(LDIND_R4, "ldind.r4", 0x4e)
OP(LDIND_R8, "ldind.r8", 0x4f)
OP(LDIND_REF, "ldind.ref", 0x50)
OP(STIND_REF, "stind.ref", 0x51)
OP(STIND_I1, "stind.i1", 0x52)
OP(STIND_I2, "stind.i2", 0x53)
OP(STIND_I4, "stind.i4", 0x54)
OP(STIND_I8, "stind.i8", 0x55)
OP(STIND_R4, "stind.r4", 0x56)
OP(STIND_R8, "stind.r8", 0x57)
OP(ADD, "add", 0x58)
OP(SUB, "sub", 0x59)
OP(MUL, "mul", 0x5a)
OP(DIV, "div", 0x5b)
OP(DIV_UN, "div.un", 0x5c)
OP(REM, "rem", 0x5d)
OP(REM_UN, "rem.un", 0x5e)
OP(AND, "and", 0x5f)
OP(OR, "or", 0x60)
OP(XOR, "xor", 0x61)
OP(SHL, "shl", 0x62)
OP(SHR, "shr", 0x63)
OP(SHR_UN, "shr.un", 0x64)
OP(NEG, "neg", 0x65)
OP(NOT, "not", 0x66)
OP(CONV_I1, "conv.i1", 0x67)
OP(CONV_I2, "conv.i2", 0x68)
OP(CONV_I4, "conv.i4", 0x69)
OP(CONV_I8, "conv.i8", 0x6a)
OP(CONV_R4, "conv.r4", 0x6b)
OP(CONV_R8, "conv.r8", 0x6c)
OP(CONV_U4, "conv.u4", 0x6d)
OP(CONV_U8, "conv.u8", 0x6e)
OP(CALLVIRT, "callvirt", 0x6f)
OP(CPOBJ, "cpobj", 0x70)
OP(LDOBJ, "ldobj", 0x71)
OP(LDSTR, "ldstr", 0x72)
OP(NEWOBJ, "newobj", 0x73)
OP(CASTCLASS, "castclass", 0x74)
OP(ISINST, "isinst", 0x75)
OP(CONV_R_UN, "conv.r.un", 0x76)
OP(ANN_DATA_S, "ann.data.s", 0x77)
OP(UNBOX, "unbox", 0x79)
OP(THROW, "throw", 0x7a)
OP(LDFLD, "ldfld", 0x7b)
OP(LDFLDA, "ldflda", 0x7c)
OP(STFLD, "stfld", 0x7d)
OP(LDSFLD, "ldsfld", 0x7e)
OP(LDSFLDA, "ldsflda", 0x7f)
OP(STSFLD, "stsfld", 0x80)
OP(STOBJ, "stobj", 0x81)
OP(CONV_OVF_I1_UN, "conv.ovf.i1.un", 0x82)
OP(CONV_OVF_I2_UN, "conv.ovf.i2.un", 0x83)
OP(CONV_OVF_I4_UN, "conv.ovf.i4.un", 0x84)
OP(CONV_OVF_I8_UN, "conv.ovf.i8.un", 0x85)
OP(CONV_OVF_U1_UN, "conv.ovf.u1.un", 0x86)
OP(CONV_OVF_U2_UN, "conv.ovf.u2.un", 0x87)
OP(CONV_OVF_U4_UN, "conv.ovf.u4.un", 0x88)
OP(CONV_OVF_U8_UN, "conv.ovf.u8.un", 0x89)
OP(CONV_OVF_I_UN, "conv.ovf.i.un", 0x8a)
OP(CONV_OVF_U_UN, "conv.ovf.u.un", 0x8b)
OP(BOX, "box", 0x8c)
OP(NEWARR, "newarr", 0x8d)
OP(LDLEN, "ldlen", 0x8e)
OP(LDELEMA, "ldelema", 0x8f)
OP(LDELEM_I1, "ldelem.i1", 0x90)
OP(LDELEM_U1, "ldelem.u1", 0x91)
OP(LDELEM_I2, "ldelem.i2", 0x92)
OP(LDELEM_U2, "ldelem.u2", 0x93)
OP(LDELEM_I4, "ldelem.i4", 0x94)
OP(LDELEM_U4, "ldelem.u4", 0x95)
OP(LDELEM_I8, "ldelem.i8", 0x96)
OP(LDELEM_I, "ldelem.i", 0x97)
OP(LDELEM_R4, "ldelem.r4", 0x98)
OP(LDELEM_R8, "ldelem.r8", 0x99)
OP(LDELEM_REF, "ldelem.ref", 0x9a)
OP(STELEM_I, "stelem.i", 0x9b)
OP(STELEM_I1, "stelem.i1", 0x9c)
OP(STELEM_I2, "stelem.i2", 0x9d)
OP(STELEM_I4, "stelem.i4", 0x9e)
OP(STELEM_I8, "stelem.i8", 0x9f)
OP(STELEM_R4, "stelem.r4", 0xa0)
OP(STELEM_R8, "stelem.r8", 0xa1)
OP(STELEM_REF, "stelem.ref", 0xa2)
OP(CONV_OVF_I1, "conv.ovf.i1", 0xb3)
OP(CONV_OVF_U1, "conv.ovf.u1", 0xb4)
OP(CONV_OVF_I2, "conv.ovf.i2", 0xb5)
OP(CONV_OVF_U2, "conv.ovf.u2", 0xb6)
OP(CONV_OVF_I4, "conv.ovf.i4", 0xb7)
OP(CONV_OVF_U4, "conv.ovf.u4", 0xb8)
OP(CONV_OVF_I8, "conv.ovf.i8", 0xb9)
OP(CONV_OVF_U8, "conv.ovf.u8", 0xba)
OP(REFANYVAL, "refanyval", 0xc2)
OP(CKFINITE, "ckfinite", 0xc3)
OP(MKREFANY, "mkrefany", 0xc6)
OP(ANN_CALL, "ann.call", 0xc7)
OP(ANN_CATCH, "ann.catch", 0xc8)
OP(ANN_DEAD, "ann.dead", 0xc9)
OP(ANN_HOISTED, "ann.hoisted", 0xca)
OP(ANN_HOISTED_CALL, "ann.hoisted.call", 0xcb)
OP(ANN_LAB, "ann.lab", 0xcc)
OP(ANN_DEF, "ann.def", 0xcd)
OP(ANN_REF_S, "ann.ref.s", 0xce)
OP(ANN_PHI, "ann.phi", 0xcf)
OP(LDTOKEN, "ldtoken", 0xd0)
OP(CONV_U2, "conv.u2", 0xd1)
OP(CONV_U1, "conv.u1", 0xd2)
OP(CONV_I, "conv.i", 0xd3)
OP(CONV_OVF_I, "conv.ovf.i", 0xd4)
OP(CONV_OVF_U, "conv.ovf.u", 0xd5)
OP(ADD_OVF, "add.ovf", 0xd6)
OP(ADD_OVF_UN, "add.ovf.un", 0xd7)
OP(MUL_OVF, "mul.ovf", 0xd8)
OP(MUL_OVF_UN, "mul.ovf.un", 0xd9)
OP(SUB_OVF, "sub.ovf", 0xda)
OP(SUB_OVF_UN, "sub.ovf.un", 0xdb)
OP(ENDFINALLY, "endfinally", 0xdc)
OP(LEAVE, "leave", 0xdd)
OP(LEAVE_S, "leave.s", 0xde)
OP(STIND_I, "stind.i", 0xdf)
OP(CONV_U, "conv.u", 0xe0)
/* prefix instructions. we use an opcode >= 256 to ease coding */
OP(ARGLIST, "arglist", 0x100)
OP(CEQ, "ceq", 0x101)
OP(CGT, "cgt", 0x102)
OP(CGT_UN, "cgt.un", 0x103)
OP(CLT, "clt", 0x104)
OP(CLT_UN, "clt.un", 0x105)
OP(LDFTN, "ldftn", 0x106)
OP(LDVIRTFTN, "ldvirtftn", 0x107)
OP(JMPI, "jmpi", 0x108)
OP(LDARG, "ldarg", 0x109)
OP(LDARGA, "ldarga", 0x10a)
OP(STARG, "starg", 0x10b)
OP(LDLOC, "ldloc", 0x10c)
OP(LDLOCA, "ldloca", 0x10d)
OP(STLOC, "stloc", 0x10e)
OP(LOCALLOC, "localloc", 0x10f)
OP(ENDFILTER, "endfilter", 0x111)
OP(UNALIGNED, "unaligned", 0x112)
OP(VOLATILE, "volatile", 0x113)
OP(TAIL, "tail", 0x114)
OP(INITOBJ, "initobj", 0x115)
OP(ANN_LIVE, "ann.live", 0x116)
OP(CPBLK, "cpblk", 0x117)
OP(INITBLK, "initblk", 0x118)
OP(ANN_REF, "ann.ref", 0x119)
OP(RETHROW, "rethrow", 0x11a)
OP(SIZEOF, "sizeof", 0x11c)
OP(REFANYTYPE, "refanytype", 0x11d)
OP(ANN_DATA, "ann.data", 0x122)
OP(ANN_ARG, "ann.arg", 0x123)

49
tcc.c
View File

@ -42,6 +42,15 @@
/* preprocessor debug */
//#define PP_DEBUG
/* target selection */
//#define TCC_TARGET_I386 /* i386 code generator */
//#define TCC_TARGET_IL /* .NET CLI generator */
/* default target is I386 */
#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_IL)
#define TCC_TARGET_I386
#endif
/* amount of virtual memory associated to a section (currently, we do
not realloc them) */
#define SECTION_VSIZE (1024 * 1024)
@ -460,6 +469,9 @@ extern float strtof (const char *__nptr, char **__endptr);
extern long double strtold (const char *__nptr, char **__endptr);
#endif
char *pstrcpy(char *buf, int buf_size, const char *s);
char *pstrcat(char *buf, int buf_size, const char *s);
void sum(int l);
void next(void);
void next_nomacro(void);
@ -524,7 +536,12 @@ static inline int is_float(int t)
#include "bcheck.c"
#ifdef TCC_TARGET_I386
#include "i386-gen.c"
#endif
#ifdef TCC_TARGET_IL
#include "il-gen.c"
#endif
#ifdef CONFIG_TCC_STATIC
@ -2404,10 +2421,12 @@ void save_reg(int r)
sv.r = VT_LOCAL | VT_LVAL;
sv.c.ul = loc;
store(r, &sv);
/* XXX: x86 specific: need to pop fp register ST0 if saved */
#ifdef TCC_TARGET_I386
/* x86 specific: need to pop fp register ST0 if saved */
if (r == REG_ST0) {
o(0xd9dd); /* fstp %st(1) */
}
#endif
/* special long long case */
if ((p->t & VT_BTYPE) == VT_LLONG) {
sv.c.ul += 4;
@ -2677,10 +2696,12 @@ void vrotb(int n)
/* pop stack value */
void vpop(void)
{
#ifdef TCC_TARGET_I386
/* for x86, we need to pop the FP stack */
if ((vtop->r & VT_VALMASK) == REG_ST0) {
o(0xd9dd); /* fstp %st(1) */
}
#endif
vtop--;
}
@ -2920,10 +2941,15 @@ void gen_opl(int op)
if (op != TOK_EQ) {
/* generate non equal test */
/* XXX: NOT PORTABLE yet */
if (a == 0)
if (a == 0) {
b = gtst(0, 0);
else
} else {
#ifdef TCC_TARGET_I386
b = psym(0x850f, 0);
#else
error("not implemented");
#endif
}
}
/* compare low */
gen_op(op);
@ -4880,7 +4906,7 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
a = gtst(1, 0);
b = 0;
block(&a, &b, case_sym, def_sym, case_reg);
oad(0xe9, d - ind - 5); /* jmp */
gjmp_addr(d);
gsym(a);
gsym_addr(b, d);
} else if (tok == '{') {
@ -4954,12 +4980,12 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
c = ind;
gexpr();
vpop();
oad(0xe9, d - ind - 5); /* jmp */
gjmp_addr(d);
gsym(e);
}
skip(')');
block(&a, &b, case_sym, def_sym, case_reg);
oad(0xe9, c - ind - 5); /* jmp */
gjmp_addr(c);
gsym(a);
gsym_addr(b, c);
} else
@ -5050,9 +5076,9 @@ void block(int *bsym, int *csym, int *case_sym, int *def_sym, int case_reg)
s = sym_push1(&label_stack, tok, VT_FORWARD, 0);
/* label already defined */
if (s->t & VT_FORWARD)
s->c = gjmp(s->c); /* jmp xxx */
s->c = gjmp(s->c);
else
oad(0xe9, s->c - ind - 5); /* jmp xxx */
gjmp_addr(s->c);
next();
skip(';');
} else {
@ -5449,8 +5475,15 @@ int decl_initializer_alloc(int t, AttributeDef *ad, int r, int has_init)
if ((r & VT_VALMASK) == VT_LOCAL) {
if (do_bounds_check && (t & VT_ARRAY))
loc--;
#ifdef TCC_TARGET_IL
/* XXX: ugly patch to allocate local variables for IL, just
for testing */
addr = loc;
loc++;
#else
loc = (loc - size) & -align;
addr = loc;
#endif
/* handles bounds */
/* XXX: currently, since we do only one pass, we cannot track
'&' operators, so we add only arrays */