📄 gstmt68.c
字号:
if (compact) {
int i;
cs->ptrs = xalloc((cs->top - cs->bottom) * sizeof(struct cases));
for (i = cs->bottom; i < cs->top; i++)
cs->ptrs[i - cs->bottom].label = cs->deflab;
} else
cs->ptrs = xalloc((cs->count) * sizeof(struct cases));
global_flag--;
}
while (stmt)
{
switch(stmt->stype) {
case st_tryblock:
break;
case st_throw:
break;
case st_return:
case st_expr:
break;
case st_while:
case st_do:
gather_cases(stmt->s1,cs,compact);
break;
case st_for:
gather_cases(stmt->s1,cs,compact);
break;
case st_if:
gather_cases(stmt->s1,cs,compact);
gather_cases(stmt->s2,cs,compact);
break;
case st_switch:
break;
case st_block:
gather_cases(stmt->exp,cs,compact);
break;
case st_asm:
break;
case st_case:
if (stmt->s2)
/* default case */
{
cs->diddef = TRUE;
stmt->label = (SNODE*)cs->deflab;
}
else
{
if (compact) {
cs->ptrs[stmt->switchid - cs->bottom].label = nextlabel;
stmt->label = (SNODE*)nextlabel++;
} else {
cs->ptrs[cs->tablepos].label = nextlabel;
cs->ptrs[cs->tablepos].binlabel = - 1;
cs->ptrs[cs->tablepos++].id = stmt->switchid;
stmt->label = (SNODE*)nextlabel++;
}
}
break;
}
stmt = stmt->next;
}
}
//-------------------------------------------------------------------------
int analyzeswitch(SNODE *stmt, struct cases *cs)
/*
* Decide whitch type of switch statement to use
*/
{
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)
/*
* Recursively output the compare/jump tree for a type of binary search
* on the case value
*/
{
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_codes(op_cmp, BESZ_DWORD, ap2, ap1);
gen_codes(op_beq, 0, ap3, 0);
if (avg == lower)
{
if (cs->deflab < 0)
cs->deflab = nextlabel++;
ap3 = make_label(cs->deflab);
gen_codes(op_bra, 0, 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_codes(op_bgt, 0, ap3, 0);
else
gen_codes(op_bhi, 0, 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)
/*
* Main routine for handling the binary switch setup
*/
{
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)
/*
* Generate a table lookup mechanism if the switch table isn't too sparse
*/
{
int tablab, i, size;
AMODE *ap, *ap1, *ap2, *ap3;
tablab = nextlabel++;
initstack();
ap = gen_expr(stmt->exp, FALSE, FALSE, BESZ_DWORD);
size = ap->length;
do_extend(ap, BESZ_DWORD, F_DREG | F_VOL);
initstack();
if (size == BESZ_QWORD || size == - BESZ_QWORD)
{
if (cs->bottom)
{
int label = nextlabel++;
#if sizeof(LLONG_TYPE) == 4
gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom < 0
? - 1: 0), makedreg(1));
#else
gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom >>
32), makedreg(1));
#endif
if (size < 0)
gen_1branch(op_blt, make_label(cs->deflab));
else
{
peep_tail->noopt = TRUE;
gen_1branch(op_bcs, make_label(cs->deflab));
}
gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom), makedreg(0));
gen_1branch(op_bcc, make_label(label));
gen_code(op_subq, make_immed(1), makedreg(1));
if (size < 0)
gen_1branch(op_blt, make_label(cs->deflab));
else
{
peep_tail->noopt = TRUE;
gen_1branch(op_bcs, make_label(cs->deflab));
}
gen_label(label);
}
else
if (size < 0)
{
gen_codes(op_tst, BESZ_DWORD, makedreg(1), makedreg(1));
gen_1branch(op_blt, make_label(cs->deflab));
}
gen_codes(op_cmp, BESZ_DWORD, make_immed(cs->top - cs->bottom), makedreg(0));
}
else {
if (cs->bottom)
{
gen_codes(op_sub, BESZ_DWORD, make_immed(cs->bottom), ap);
if (size < 0)
gen_codes(op_blt, 0, make_label(cs->deflab), 0);
else
{
peep_tail->noopt = TRUE;
gen_codes(op_bcs, 0, make_label(cs->deflab), 0);
}
}
else
{
if (size < 0)
{
gen_codes(op_tst, BESZ_DWORD, ap, 0);
gen_codes(op_blt, 0, make_label(cs->deflab), 0);
}
}
gen_codes(op_cmp, BESZ_DWORD, make_immed(cs->top - cs->bottom), ap);
}
if (size < 0)
gen_codes(op_bhs, 0, make_label(cs->deflab), 0);
else
gen_codes(op_bcc, 0, make_label(cs->deflab), 0);
ap1 = temp_addr();
if (prm_68020 || prm_coldfire)
{
ap2 = xalloc(sizeof(AMODE));
ap2->preg = ap1->preg;
ap2->mode = am_pcindxdata;
ap2->scale = 2;
ap2->offset = makenode(en_labcon, (char*)tablab, 0);
gen_codes(op_lea, BESZ_DWORD, ap2, ap1);
ap3 = xalloc(sizeof(AMODE));
ap3->sreg = ap->preg;
ap3->preg = ap1->preg;
ap3->scale = 0;
ap3->offset = makeintnode(en_icon, 0);
ap3->mode = am_ind;
gen_codes(op_adda, BESZ_DWORD, ap3, ap1);
}
else
{
ap2 = xalloc(sizeof(AMODE));
if (prm_pcrel)
{
ap2->preg = ap1->preg;
ap2->mode = am_pcindx;
}
else
{
ap2->mode = am_adirect;
if (prm_smallcode)
ap2->preg = 2;
else
ap2->preg = 4;
}
ap2->offset = makeintnode(en_labcon, tablab);
gen_codes(op_lea, 0, ap2, ap1);
if (prm_datarel || prm_smallcode)
gen_codes(op_asl, BESZ_DWORD, make_immed(1), ap);
else
gen_codes(op_asl, BESZ_DWORD, make_immed(2), ap);
if (prm_datarel)
{
gen_codes(op_add, BESZ_DWORD, ap, ap1);
ap2->mode = am_ind;
gen_codes(op_add, 2, ap2, ap1);
}
else
{
ap3 = xalloc(sizeof(AMODE));
ap3->sreg = ap->preg;
ap3->preg = ap1->preg;
ap3->scale = 0;
ap3->offset = makeintnode(en_icon, 0);
ap3->mode = am_baseindxdata;
gen_codes(op_move, BESZ_DWORD, ap3, ap1);
}
}
ap1->mode = am_ind;
gen_codes(op_jmp, 0, ap1, 0);
initstack();
gen_label(tablab);
gather_cases(stmt->s1,cs,TRUE);
for (i = 0; i < cs->top - cs->bottom; i++)
if (!prm_coldfire && (prm_smallcode || prm_pcrel))
gen_codes(op_dcl, 2, make_label(cs->ptrs[i].label), 0);
else
gen_codes(op_dcl, BESZ_DWORD, 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);
do_extend(ap1, BESZ_DWORD, 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, ap2, makedreg(0));
gen_1branch(op_bne, make_label(lab));
gen_codes(op_cmp, BESZ_DWORD, ap4, makedreg(1));
gen_1branch(op_beq, ap3);
gen_label(lab);
}
else {
AMODE *ap2 = make_immed(cs->ptrs[i].id);
AMODE *ap3 = make_label(cs->ptrs[i].label);
gen_codes(op_cmp, ap1->length, ap2, ap1);
gen_code(op_beq, ap3, 0);
}
}
gen_1branch(op_bra, make_label(cs->deflab));
freeop(ap1);
}
//-------------------------------------------------------------------------
void genxswitch(SNODE *stmt)
/*
* analyze and generate best switch statement.
*/
{
int oldbreak;
struct cases cs;
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_pea, BESZ_DWORD, make_label(plabel), 0);
call_library("__profile_in", 4);
}
}
//-------------------------------------------------------------------------
void SubProfilerData(void)
{
if (prm_profiler)
{
gen_codes(op_pea, BESZ_DWORD, make_label(plabel), 0);
call_library("__profile_out", 4);
}
}
//-------------------------------------------------------------------------
void genreturn(SNODE *stmt, int flag)
/*
* generate a return statement.
*/
{
AMODE *ap, *ap1, *ap2, *ap3;
ENODE *mvn1;
int size;
SubProfilerData();
if (stmt != 0 && stmt->exp != 0)
{
if (!genning_inline)
initstack();
if (currentfunc->tp->btp && isstructured(currentfunc->tp->btp))
{
size = currentfunc->tp->btp->size;
ap = gen_expr(stmt->exp, FALSE, TRUE, BESZ_DWORD);
returndreg = TRUE;
}
else if (currentfunc->tp->btp && currentfunc->tp->btp->type ==
bt_memberptr)
{
size = BESZ_DWORD;
ap = gen_expr(stmt->exp, FALSE, TRUE, BESZ_DWORD);
returndreg = TRUE;
}
else
{
size = currentfunc->tp->btp->size;
if (size == BESZ_DWORD && currentfunc->tp->btp->type == bt_float)
size = BESZ_FLOAT;
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_DOUBLEREG);
}
else if (size > BESZ_QWORD)
{
retsize = BESZ_LDOUBLE;
ap = gen_expr(stmt->exp, FALSE, FALSE, size);
do_extend(ap, size, F_FREG);
}
else
{
returndreg = TRUE;
retsize = BESZ_DWORD;
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_move, size, makedreg(0), ap);
ap = makedreg(0);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -