mirror of
https://github.com/mirror/tinycc.git
synced 2025-02-04 06:30:10 +08:00
added CIL target
This commit is contained in:
parent
421911f921
commit
5a50e73980
681
il-gen.c
Normal file
681
il-gen.c
Normal 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
251
il-opcodes.h
Normal 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
49
tcc.c
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user