forked from Mirrors/tinycc
added local bound generation - fixed binary ops - added bound check dereference
parent
7e51b6607d
commit
b7fed2f2d4
131
i386-gen.c
131
i386-gen.c
|
@ -21,15 +21,18 @@
|
||||||
/* number of available registers */
|
/* number of available registers */
|
||||||
#define NB_REGS 4
|
#define NB_REGS 4
|
||||||
|
|
||||||
/* a register can belong to several classes */
|
/* 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_INT 0x0001 /* generic integer register */
|
#define RC_INT 0x0001 /* generic integer register */
|
||||||
#define RC_FLOAT 0x0002 /* generic float register */
|
#define RC_FLOAT 0x0002 /* generic float register */
|
||||||
#define RC_EAX 0x0004
|
#define RC_EAX 0x0004
|
||||||
#define RC_FRET 0x0008 /* function return: float register */
|
#define RC_ST0 0x0008
|
||||||
#define RC_ECX 0x0010
|
#define RC_ECX 0x0010
|
||||||
#define RC_EDX 0x0020
|
#define RC_EDX 0x0020
|
||||||
#define RC_IRET RC_EAX /* function return: integer register */
|
#define RC_IRET RC_EAX /* function return: integer register */
|
||||||
#define RC_LRET RC_EDX /* function return: second integer register */
|
#define RC_LRET RC_EDX /* function return: second integer register */
|
||||||
|
#define RC_FRET RC_ST0 /* function return: float register */
|
||||||
|
|
||||||
/* pretty names for the registers */
|
/* pretty names for the registers */
|
||||||
enum {
|
enum {
|
||||||
|
@ -40,10 +43,10 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
int reg_classes[NB_REGS] = {
|
int reg_classes[NB_REGS] = {
|
||||||
/* eax */ RC_INT | RC_IRET,
|
/* eax */ RC_INT | RC_EAX,
|
||||||
/* ecx */ RC_INT | RC_ECX,
|
/* ecx */ RC_INT | RC_ECX,
|
||||||
/* edx */ RC_INT | RC_EDX,
|
/* edx */ RC_INT | RC_EDX,
|
||||||
/* st0 */ RC_FLOAT | RC_FRET,
|
/* st0 */ RC_FLOAT | RC_ST0,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* return registers for function */
|
/* return registers for function */
|
||||||
|
@ -73,6 +76,7 @@ typedef struct GFuncContext {
|
||||||
/******************************************************/
|
/******************************************************/
|
||||||
|
|
||||||
static int *func_sub_sp_ptr;
|
static int *func_sub_sp_ptr;
|
||||||
|
static unsigned char *func_bound_ptr;
|
||||||
|
|
||||||
void g(int c)
|
void g(int c)
|
||||||
{
|
{
|
||||||
|
@ -389,14 +393,39 @@ void gfunc_prolog(int t)
|
||||||
}
|
}
|
||||||
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
o(0xe58955); /* push %ebp, mov %esp, %ebp */
|
||||||
func_sub_sp_ptr = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
func_sub_sp_ptr = (int *)oad(0xec81, 0); /* sub $xxx, %esp */
|
||||||
|
/* leave some room for bound checking code */
|
||||||
|
if (do_bounds_check) {
|
||||||
|
oad(0xb8, 0); /* lbound section pointer */
|
||||||
|
oad(0xb8, 0); /* call to function */
|
||||||
|
func_bound_ptr = lbounds_section->data_ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* generate function epilog */
|
/* generate function epilog */
|
||||||
void gfunc_epilog(void)
|
void gfunc_epilog(void)
|
||||||
{
|
{
|
||||||
|
if (do_bounds_check && func_bound_ptr != lbounds_section->data_ptr) {
|
||||||
|
int saved_ind;
|
||||||
|
int *bounds_ptr;
|
||||||
|
/* add end of table info */
|
||||||
|
bounds_ptr = (int *)lbounds_section->data_ptr;
|
||||||
|
*bounds_ptr++ = 0;
|
||||||
|
lbounds_section->data_ptr = (unsigned char *)bounds_ptr;
|
||||||
|
/* generate bound local allocation */
|
||||||
|
saved_ind = ind;
|
||||||
|
ind = (int)func_sub_sp_ptr + 4;
|
||||||
|
oad(0xb8, (int)func_bound_ptr); /* mov %eax, xxx */
|
||||||
|
oad(0xe8, (int)__bound_local_new - ind - 5);
|
||||||
|
ind = saved_ind;
|
||||||
|
/* generate bound check local freeing */
|
||||||
|
o(0x5250); /* save returned value, if any */
|
||||||
|
oad(0xb8, (int)func_bound_ptr); /* mov %eax, xxx */
|
||||||
|
oad(0xe8, (int)__bound_local_delete - ind - 5);
|
||||||
|
o(0x585a); /* restore returned value, if any */
|
||||||
|
}
|
||||||
o(0xc3c9); /* leave, ret */
|
o(0xc3c9); /* leave, ret */
|
||||||
*func_sub_sp_ptr = (-loc + 3) & -4; /* align local size to word &
|
/* align local size to word & save local variables */
|
||||||
save local variables */
|
*func_sub_sp_ptr = (-loc + 3) & -4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gjmp(int t)
|
int gjmp(int t)
|
||||||
|
@ -457,11 +486,11 @@ void gen_opi(int op)
|
||||||
case TOK_ADDC1: /* add with carry generation */
|
case TOK_ADDC1: /* add with carry generation */
|
||||||
opc = 0;
|
opc = 0;
|
||||||
gen_op8:
|
gen_op8:
|
||||||
vswap();
|
|
||||||
r = gv(RC_INT);
|
|
||||||
vswap();
|
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
||||||
/* constant case */
|
/* constant case */
|
||||||
|
vswap();
|
||||||
|
r = gv(RC_INT);
|
||||||
|
vswap();
|
||||||
c = vtop->c.i;
|
c = vtop->c.i;
|
||||||
if (c == (char)c) {
|
if (c == (char)c) {
|
||||||
/* XXX: generate inc and dec for smaller code ? */
|
/* XXX: generate inc and dec for smaller code ? */
|
||||||
|
@ -473,7 +502,9 @@ void gen_opi(int op)
|
||||||
oad(0xc0 | (opc << 3) | r, c);
|
oad(0xc0 | (opc << 3) | r, c);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fr = gv(RC_INT);
|
gv2(RC_INT, RC_INT);
|
||||||
|
r = vtop[-1].r;
|
||||||
|
fr = vtop[0].r;
|
||||||
o((opc << 3) | 0x01);
|
o((opc << 3) | 0x01);
|
||||||
o(0xc0 + r + fr * 8);
|
o(0xc0 + r + fr * 8);
|
||||||
}
|
}
|
||||||
|
@ -503,10 +534,9 @@ void gen_opi(int op)
|
||||||
opc = 1;
|
opc = 1;
|
||||||
goto gen_op8;
|
goto gen_op8;
|
||||||
case '*':
|
case '*':
|
||||||
vswap();
|
gv2(RC_INT, RC_INT);
|
||||||
r = gv(RC_INT);
|
r = vtop[-1].r;
|
||||||
vswap();
|
fr = vtop[0].r;
|
||||||
fr = gv(RC_INT);
|
|
||||||
vtop--;
|
vtop--;
|
||||||
o(0xaf0f); /* imul fr, r */
|
o(0xaf0f); /* imul fr, r */
|
||||||
o(0xc0 + fr + r * 8);
|
o(0xc0 + fr + r * 8);
|
||||||
|
@ -520,29 +550,24 @@ void gen_opi(int op)
|
||||||
case TOK_SAR:
|
case TOK_SAR:
|
||||||
opc = 7;
|
opc = 7;
|
||||||
gen_shift:
|
gen_shift:
|
||||||
vswap();
|
|
||||||
r = gv(RC_INT);
|
|
||||||
vswap();
|
|
||||||
opc = 0xc0 | (opc << 3);
|
opc = 0xc0 | (opc << 3);
|
||||||
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
|
||||||
/* constant case */
|
/* constant case */
|
||||||
|
vswap();
|
||||||
|
r = gv(RC_INT);
|
||||||
|
vswap();
|
||||||
c = vtop->c.i & 0x1f;
|
c = vtop->c.i & 0x1f;
|
||||||
o(0xc1); /* shl/shr/sar $xxx, r */
|
o(0xc1); /* shl/shr/sar $xxx, r */
|
||||||
o(opc | r);
|
o(opc | r);
|
||||||
g(c);
|
g(c);
|
||||||
} else {
|
} else {
|
||||||
/* we generate the shift in ecx */
|
/* we generate the shift in ecx */
|
||||||
gv(RC_ECX);
|
gv2(RC_INT, RC_ECX);
|
||||||
/* the first op may have been spilled, so we reload it if
|
r = vtop[-1].r;
|
||||||
needed */
|
|
||||||
vswap();
|
|
||||||
r = gv(RC_INT);
|
|
||||||
vswap();
|
|
||||||
o(0xd3); /* shl/shr/sar %cl, r */
|
o(0xd3); /* shl/shr/sar %cl, r */
|
||||||
o(opc | r);
|
o(opc | r);
|
||||||
}
|
}
|
||||||
vtop--;
|
vtop--;
|
||||||
vtop->r = r;
|
|
||||||
break;
|
break;
|
||||||
case '/':
|
case '/':
|
||||||
case TOK_UDIV:
|
case TOK_UDIV:
|
||||||
|
@ -550,14 +575,11 @@ void gen_opi(int op)
|
||||||
case '%':
|
case '%':
|
||||||
case TOK_UMOD:
|
case TOK_UMOD:
|
||||||
case TOK_UMULL:
|
case TOK_UMULL:
|
||||||
vswap();
|
/* first operand must be in eax */
|
||||||
r = gv(RC_EAX); /* first operand must be in eax */
|
/* XXX: need better constraint for second operand */
|
||||||
vswap();
|
gv2(RC_EAX, RC_ECX);
|
||||||
/* XXX: need better constraint */
|
r = vtop[-1].r;
|
||||||
fr = gv(RC_ECX); /* second operand in ecx */
|
fr = vtop[0].r;
|
||||||
vswap();
|
|
||||||
r = gv(RC_EAX); /* reload first operand if flushed */
|
|
||||||
vswap();
|
|
||||||
vtop--;
|
vtop--;
|
||||||
save_reg(REG_EDX);
|
save_reg(REG_EDX);
|
||||||
if (op == TOK_UMULL) {
|
if (op == TOK_UMULL) {
|
||||||
|
@ -588,7 +610,7 @@ void gen_opi(int op)
|
||||||
|
|
||||||
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
/* generate a floating point operation 'v = t1 op t2' instruction. The
|
||||||
two operands are guaranted to have the same floating point type */
|
two operands are guaranted to have the same floating point type */
|
||||||
/* NOTE: currently floats can only be lvalues */
|
/* XXX: need to use ST1 too */
|
||||||
void gen_opf(int op)
|
void gen_opf(int op)
|
||||||
{
|
{
|
||||||
int a, ft, fc, swapped;
|
int a, ft, fc, swapped;
|
||||||
|
@ -759,6 +781,49 @@ void gen_cvt_ftof(int t)
|
||||||
gv(RC_FLOAT);
|
gv(RC_FLOAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* bound check support functions */
|
||||||
|
|
||||||
|
/* generate first part of bounded pointer addition */
|
||||||
|
void gen_bounded_ptr_add1(void)
|
||||||
|
{
|
||||||
|
/* prepare fast i386 function call (args in eax and edx) */
|
||||||
|
gv2(RC_EAX, RC_EDX);
|
||||||
|
/* save all temporary registers */
|
||||||
|
vtop--;
|
||||||
|
vtop->r = VT_CONST;
|
||||||
|
save_regs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if deref is true, then also test dereferencing */
|
||||||
|
void gen_bounded_ptr_add2(int deref)
|
||||||
|
{
|
||||||
|
void *func;
|
||||||
|
int size, align;
|
||||||
|
|
||||||
|
if (deref) {
|
||||||
|
size = type_size(vtop->t, &align);
|
||||||
|
switch(size) {
|
||||||
|
case 1: func = __bound_ptr_indir1; break;
|
||||||
|
case 2: func = __bound_ptr_indir2; break;
|
||||||
|
case 4: func = __bound_ptr_indir4; break;
|
||||||
|
case 8: func = __bound_ptr_indir8; break;
|
||||||
|
case 12: func = __bound_ptr_indir12; break;
|
||||||
|
case 16: func = __bound_ptr_indir16; break;
|
||||||
|
default:
|
||||||
|
error("unhandled size when derefencing bounded pointer");
|
||||||
|
func = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func = __bound_ptr_add;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do a fast function call */
|
||||||
|
oad(0xe8, (int)func - ind - 5);
|
||||||
|
/* return pointer is there */
|
||||||
|
vtop->r = REG_EAX;
|
||||||
|
}
|
||||||
|
|
||||||
/* end of X86 code generator */
|
/* end of X86 code generator */
|
||||||
/*************************************************************/
|
/*************************************************************/
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue