📄 gstmt386.c
字号:
stmt = stmt->next;
}
}
//-------------------------------------------------------------------------
int analyzeswitch(SNODE *stmt, struct cases *cs)
{
int size = natural_size(stmt->exp);
count_cases(stmt->s1,cs) ;
cs->top++;
if (cs->count == 0)
return (0);
if (cs->count < 5)
return 3;
if (cs->count *10 / (cs->top - cs->bottom) >= 8)
return (1);
// do a simple switch instead of a binary if it is a long long
if (size == BESZ_QWORD || size == - BESZ_QWORD)
return 3;
return (2);
}
//-------------------------------------------------------------------------
void bingen(int lower, int avg, int higher, AMODE *ap1, struct cases *cs)
{
AMODE *ap2 = make_immed(cs->ptrs[avg].id);
AMODE *ap3 = make_label(cs->ptrs[avg].label);
if (cs->ptrs[avg].binlabel != - 1)
gen_label(cs->ptrs[avg].binlabel);
gen_coden(op_cmp, ap1->length, ap1, ap2);
gen_code(op_je, ap3, 0);
if (avg == lower)
{
if (cs->deflab < 0)
cs->deflab = nextlabel++;
ap3 = make_label(cs->deflab);
gen_code(op_jmp, ap3, 0);
}
else
{
int avg1 = (lower + avg) / 2;
int avg2 = (higher + avg + 1) / 2;
if (avg + 1 < higher)
ap3 = make_label(cs->ptrs[avg2].binlabel = nextlabel++);
else
ap3 = make_label(cs->deflab);
if (ap1->length < 0)
gen_code(op_jg, ap3, 0);
else
gen_code(op_ja, ap3, 0);
bingen(lower, avg1, avg, ap1, cs);
if (avg + 1 < higher)
bingen(avg + 1, avg2, higher, ap1, cs);
}
}
//-------------------------------------------------------------------------
int sortcmp(const void *one, const void *two)
{
if (((struct caseptrs *)one)->id < ((struct caseptrs *)two)->id)
return -1;
if (((struct caseptrs *)one)->id > ((struct caseptrs *)two)->id)
return 1;
return 0;
}
void genbinaryswitch(SNODE *stmt, struct cases *cs)
{
AMODE *ap1;
initstack();
ap1 = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
do_extend(ap1, ap1->length, F_DREG);
gather_cases(stmt->s1,cs,FALSE);
qsort(cs->ptrs,cs->count, sizeof(cs->ptrs[0]), sortcmp);
bingen(0, (cs->count) / 2, cs->count, ap1, cs);
freeop(ap1);
}
//-------------------------------------------------------------------------
void gencompactswitch(SNODE *stmt, struct cases *cs)
{
int tablab, size;
AMODE *ap, *ap2;
LLONG_TYPE i;
tablab = nextlabel++;
initstack();
ap = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
size = ap->length;
if (size == BESZ_QWORD || size == - BESZ_QWORD)
do_extend(ap, BESZ_QWORD, F_AXDX);
else
do_extend(ap, BESZ_DWORD, F_DREG | F_VOL);
initstack();
if (size == BESZ_QWORD || size == - BESZ_QWORD)
{
if (cs->bottom)
{
gen_codes(op_sub, BESZ_DWORD, makedreg(EAX), make_immed(cs->bottom));
#if sizeof(LLONG_TYPE) == 4
gen_codes(op_sbb, BESZ_DWORD, makedreg(EDX), make_immed(cs->bottom < 0
? - 1: 0));
#else
gen_codes(op_sbb, BESZ_DWORD, makedreg(EDX), make_immed(cs->bottom >>
32));
#endif
if (size < 0)
gen_codes(op_jl, 0, make_label(cs->deflab), 0);
else
{
peep_tail->noopt = TRUE;
gen_codes(op_jb, 0, make_label(cs->deflab), 0);
}
}
else
if (size < 0)
{
gen_codes(op_test, BESZ_DWORD, makedreg(EDX), makedreg(EDX));
gen_codes(op_jl, 0, make_label(cs->deflab), 0);
}
gen_codes(op_cmp, BESZ_DWORD, makedreg(EAX), make_immed(cs->top - cs->bottom)
);
}
else
{
if (cs->bottom)
{
gen_codes(op_sub, BESZ_DWORD, ap, make_immed(cs->bottom));
if (size < 0)
gen_codes(op_jl, 0, make_label(cs->deflab), 0);
else
{
peep_tail->noopt = TRUE;
gen_codes(op_jb, 0, make_label(cs->deflab), 0);
}
}
else
if (size < 0)
{
gen_codes(op_test, BESZ_DWORD, ap, ap);
gen_codes(op_jl, 0, make_label(cs->deflab), 0);
}
gen_codes(op_cmp, BESZ_DWORD, ap, make_immed(cs->top - cs->bottom));
}
if (size < 0)
gen_codes(op_jge, 0, make_label(cs->deflab), 0);
else
gen_codes(op_jnc, 0, make_label(cs->deflab), 0);
ap->mode = am_indispscale;
ap->sreg = ap->preg;
ap->preg = - 1;
ap->scale = 2;
ap->offset = makeintnode(en_labcon, tablab);
gen_codes(op_jmp, BESZ_DWORD, ap, 0);
initstack();
align(stdaddrsize);
gen_label(tablab);
gather_cases(stmt->s1,cs,TRUE);
for (i = 0; i < cs->top - cs->bottom; i++)
gen_codes(op_dd, 4, make_label(cs->ptrs[i].label), 0);
}
//-------------------------------------------------------------------------
void gensimpleswitch(SNODE *stmt, struct cases *cs)
{
int i = 0, j;
AMODE *ap1, *ap2, *ap3, *ap4;
int size = natural_size(stmt->exp);
initstack();
ap1 = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
if (size == BESZ_QWORD || size == - BESZ_QWORD)
do_extend(ap1, ap1->length, F_AXDX);
else
do_extend(ap1, ap1->length, F_DREG);
gather_cases(stmt->s1,cs,FALSE);
qsort(cs->ptrs,cs->count, sizeof(cs->ptrs[0]), sortcmp);
for (i = 0; i < cs->count; i++)
{
if (size == BESZ_QWORD || size == - BESZ_QWORD)
{
int lab = nextlabel++;
ap2 = make_immed(cs->ptrs[i].id);
#if sizeof(LLONG_TYPE) == 4
ap4 = make_immed(cs->ptrs[i].id < 0 ? 0xffffffff : 0);
#else
ap4 = make_immed(cs->ptrs[i].id >> 32);
#endif
ap3 = make_label(cs->ptrs[i].label);
gen_coden(op_cmp, BESZ_DWORD, makedreg(EAX), ap2);
gen_code(op_jne, make_label(lab), 0);
gen_coden(op_cmp, BESZ_DWORD, makedreg(EDX), ap4);
gen_code(op_je, ap3, 0);
gen_label(lab);
}
else
{
ap2 = make_immed(cs->ptrs[i].id);
ap3 = make_label(cs->ptrs[i].label);
gen_coden(op_cmp, ap1->length, ap1, ap2);
gen_code(op_je, ap3, 0);
}
}
gen_codes(op_jmp, 0, make_label(cs->deflab), 0);
freeop(ap1);
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
void genxswitch(SNODE *stmt)
/*
* analyze and generate best switch statement.
*/
{
int oldbreak;
struct cases cs;
int a = 1;
OCODE *result;
oldbreak = breaklab;
breaklab = nextlabel++;
memset(&cs,0,sizeof(cs));
#if sizeof(LLONG_TYPE) == 4
cs.top = INT_MIN;
cs.bottom = INT_MAX;
#else
cs.top = (a << 63); // LLONG_MIN
cs.bottom = cs.top - 1; // LLONG_MAX
#endif
cs.deflab = nextlabel++;
switch (analyzeswitch(stmt,&cs))
{
case 3:
gensimpleswitch(stmt, &cs);
break;
case 2:
genbinaryswitch(stmt, &cs);
break;
case 1:
gencompactswitch(stmt, &cs);
break;
case 0:
break;
}
result = gen_codes(op_blockstart, 0, 0, 0);
result->blocknum = (int)stmt->label;
genstmt(stmt->s1);
result = gen_codes(op_blockend, 0, 0, 0);
result->blocknum = (int)stmt->label;
if (!cs.diddef)
gen_label(cs.deflab);
gen_label(breaklab);
breaklab = oldbreak;
}
//-------------------------------------------------------------------------
void AddProfilerData(void)
{
char pname[256];
if (prm_profiler)
{
sprintf(pname, "%s", currentfunc->name);
plabel = stringlit(pname, FALSE, strlen(pname + 1));
gen_codes(op_push, BESZ_DWORD , make_label(plabel), 0);
call_library("__profile_in");
gen_codes(op_pop, BESZ_DWORD , makedreg(ECX), 0);
}
}
//-------------------------------------------------------------------------
void SubProfilerData(void)
{
if (prm_profiler)
{
gen_codes(op_push, BESZ_DWORD , make_label(plabel), 0);
call_library("__profile_out");
gen_codes(op_pop, BESZ_DWORD , makedreg(ECX), 0);
}
}
//-------------------------------------------------------------------------
OCODE *ThunkAddPeep(OCODE *after, int op, AMODE *ap1, AMODE *ap2)
{
OCODE *new;
new = xalloc(sizeof(OCODE));
new->opcode = op;
if (op == op_label)
{
new->oper1 = ap1;
new->oper2 = 0;
}
else
{
new->oper1 = copy_addr(ap1);
new->oper2 = copy_addr(ap2);
}
// fixlen(new->oper1);
// fixlen(new->oper2);
new->fwd = after->fwd;
after->fwd->back = new;
new->back = after;
after->fwd = new;
return new;
}
//-------------------------------------------------------------------------
void ThunkUncommittedStack(void)
{
if (lc_maxauto >= 4096)
{
OCODE *after = frame_ins->back;
AMODE *ap;
remove_peep_entry(frame_ins);
after = ThunkAddPeep(after, op_mov, makedreg(ECX), make_immed
(lc_maxauto));
ap = set_symbol("___substack", 1);
after = ThunkAddPeep(after, op_call, ap, 0);
}
}
//-------------------------------------------------------------------------
AMODE *genreturn(SNODE *stmt, int flag)
/*
* generate a return statement.
*/
{
AMODE *ap = 0, *ap1, *ap2;
ENODE ep;
int size, esize, t, q;
SubProfilerData();
ThunkUncommittedStack();
if (stmt != 0 && stmt->exp != 0)
{
if (!genning_inline)
initstack();
if (currentfunc->tp->btp && isstructured(currentfunc->tp->btp))
{
size = currentfunc->tp->btp->size;
ep.nodetype = en_ul_ref;
ep.v.p[0] = stmt->exp;
ap = gen_expr(&ep, FALSE, FALSE, 0);
returndreg = TRUE;
}
else if (currentfunc->tp->btp && currentfunc->tp->btp->type ==
bt_memberptr)
{
size = 4;
ap = gen_expr(stmt->exp, FALSE, TRUE, BESZ_DWORD );
returndreg = TRUE;
}
else
{
{
if (currentfunc->tp->btp->type == bt_bool)
size = 5;
else
size = currentfunc->tp->btp->size;
if (size == 4 && currentfunc->tp->btp->type == bt_float)
size = 7;
if (currentfunc->tp->btp->type == bt_farpointer)
{
size = currentfunc->tp->btp->type == bt_long ? - 6: 6;
ap = gen_expr(stmt->exp, FALSE, FALSE, size);
do_extend(ap, size, F_AXDX);
ap->length = BESZ_QWORD;
retsize = 8;
}
else if (currentfunc->tp->btp->type == bt_longlong ||
currentfunc->tp->btp->type == bt_unsignedlonglong)
{
size = currentfunc->tp->btp->type == bt_long ? - BESZ_QWORD: BESZ_QWORD;
ap = gen_expr(stmt->exp, FALSE, FALSE, size);
do_extend(ap, size, F_AXDX);
}
else if (currentfunc->tp->btp->type == bt_float || currentfunc->tp->btp->type == bt_double
|| currentfunc->tp->btp->type == bt_longdouble)
{
retsize = 10;
ap = gen_expr(stmt->exp, FALSE, FALSE, 10);
do_extend(ap, 10, F_FREG);
}
else if (currentfunc->tp->btp->type == bt_fimaginary || currentfunc->tp->btp->type == bt_rimaginary
|| currentfunc->tp->btp->type == bt_lrimaginary)
{
retsize = 17;
ap = gen_expr(stmt->exp, FALSE, FALSE, 17);
do_extend(ap, 17, F_FREG);
}
else if (currentfunc->tp->btp->type == bt_fcomplex || currentfunc->tp->btp->type == bt_rcomplex
|| currentfunc->tp->btp->type == bt_lrcomplex)
{
retsize = 22;
ap = gen_expr(stmt->exp, FALSE, FALSE, 22);
do_extend(ap, 22, 0);
}
else
{
returndreg = TRUE;
retsize = 4;
ap = gen_expr(stmt->exp, FALSE, FALSE, size);
do_extend(ap, size, F_DREG | F_VOL);
if (!genning_inline && ap->preg != 0)
{
gen_codes(op_mov, size, makedreg(0), ap);
ap = makedreg(EAX);
}
}
}
}
}
if (flag &1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -