📄 gstmt386.c
字号:
}
for (i=0; i < switchcount; i++)
for (j=i+1; j < switchcount; j++)
if (switchids[j] < switchids[i]) {
int temp = switchids[i];
switchids[i] = switchids[j];
switchids[j] = temp;
temp = switchlabels[i];
switchlabels[i] = switchlabels[j];
switchlabels[j] = temp;
}
bingen(0,(switchcount)/2,switchcount,ap1,deflab,size,switchids,switchlabels,switchbinlabels);
freeop(ap1);
}
void gencompactswitch(SNODE *stmt, int deflab)
{ int tablab,curlab,i, size = natural_size(stmt->exp);
AMODE *ap,*ap2;
long switchbottom=gswitchbottom, switchcount=gswitchcount;
long switchtop=gswitchtop;
int *switchlabels=0;
tablab = nextlabel++;
curlab = nextlabel++;
initstack();
ap = gen_expr(stmt->exp,F_DREG | F_VOL,4);
initstack();
if (switchbottom)
gen_code(op_sub,4,ap,make_immed(switchbottom));
if (size < 0)
gen_code(op_jl,0,make_label(deflab),0);
else
gen_code(op_jb,0,make_label(deflab),0);
gen_code(op_cmp,4,ap,make_immed(switchtop-switchbottom));
if (size < 0)
gen_code(op_jge,0,make_label(deflab),0);
else
gen_code(op_jnc,0,make_label(deflab),0);
gen_code(op_shl,4,ap,make_immed(2));
ap2 = xalloc(sizeof(AMODE));
ap->mode = am_indisp;
ap2->preg = ap->preg;
ap->offset = makenode(en_labcon,(char *)tablab,0);
gen_code(op_jmp,4,ap,0);
initstack();
align(4);
gen_label(tablab);
switchlabels = xalloc((switchtop-switchbottom) * sizeof(int));
for (i=switchbottom; i < switchtop; i++) {
switchlabels[i-switchbottom] = deflab;
}
stmt = stmt->s1;
while (stmt) {
if( stmt->s2 ) /* default case ? */
{
stmt->label = (SNODE *)deflab;
diddef = TRUE;
}
else
{
switchlabels[(int)stmt->label-switchbottom] = curlab;
stmt->label = (SNODE *)curlab;
}
if(stmt->next != 0 )
curlab = nextlabel++;
stmt = stmt->next;
}
for (i=0; i < switchtop-switchbottom; i++)
gen_code(op_dd,4,make_label(switchlabels[i]),0);
}
void gencase(SNODE *stmt)
/*
* generate all cases for a switch statement.
*/
{ while( stmt != 0 )
{
gen_label((int)stmt->label);
if( stmt->s1 != 0 )
{
genstmt(stmt->s1);
}
stmt = stmt->next;
}
}
void genxswitch(SNODE *stmt)
/*
* analyze and generate best switch statement.
*/
{ int oldbreak;
int olddiddef = diddef;
int deflab = nextlabel++;
oldbreak = breaklab;
breaklab = nextlabel++;
diddef = FALSE;
switch (analyzeswitch(stmt)) {
case 2:
genbinaryswitch(stmt,deflab);
break;
case 1:
gencompactswitch(stmt,deflab);
break;
case 0:
if (stmt->s1)
stmt->s1->label = (SNODE *) nextlabel++;
break;
}
gencase(stmt->s1);
if (!diddef)
gen_label(deflab);
gen_label(breaklab);
breaklab = oldbreak;
diddef = olddiddef;
}
void genreturn(SNODE *stmt, int flag)
/*
* generate a return statement.
*/
{ AMODE *ap,*ap1;
int size;
if( stmt != 0 && stmt->exp != 0 ) {
initstack();
if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union)) {
size = currentfunc->tp->btp->size;
ap = gen_expr(stmt->exp,F_ALL,4);
if (!(save_mask & 0x40))
gen_push(ESI,am_dreg,0);
if (!(save_mask & 0x80))
gen_push(EDI,am_dreg,0);
if (prm_linkreg) {
ap1 = xalloc(sizeof(AMODE));
ap1->preg = EBP;
ap1->mode = am_indisp;
if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *) -1)
ap1->offset = makenode(en_icon,(char *)(currentfunc->tp->lst.head->value.i+((currentfunc->tp->lst.head->tp->size+3) &0xFFFFFFFCL)),0);
else
ap1->offset = makenode(en_icon,(char *)8,0);
}
else
if (currentfunc->pascaldefn && currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *) -1)
ap1 = make_stack(-stackdepth-framedepth-currentfunc->tp->lst.head->value.i-((currentfunc->tp->lst.head->tp->size+3) & 0xfffffffcL));
else
ap1 = make_stack(-stackdepth-framedepth);
gen_code(op_mov,4,makedreg(ESI),ap);
gen_code(op_mov,4,makedreg(EDI),ap1);
gen_code(op_mov,4,makedreg(EAX),makedreg(EDI));
gen_code(op_mov,4,makedreg(ECX),make_immed(size));
gen_code(op_cld,0,0,0);
gen_code(op_rep,1,0,0);
gen_code(op_movsb,1,0,0);
if (!(save_mask & 0x80))
gen_pop(EDI,am_dreg,0);
if (!(save_mask & 0x40))
gen_pop(ESI,am_dreg,0);
}
else {
size = currentfunc->tp->btp->size;
ap = gen_expr(stmt->exp,F_DREG | F_FREG,size);
if (size > 4) {
if (ap->mode != am_freg)
gen_code(op_fld,size,ap,0);
}
else
if( ap->mode != am_dreg || ap->preg != 0 )
gen_code(op_mov,size,makedreg(0),ap);
}
freeop(ap);
}
if (flag) {
if( retlab != -1 )
gen_label(retlab);
if( fsave_mask != 0 )
diag("Float restore in return");
if (!prm_linkreg && lc_maxauto)
gen_code(op_add,4,makedreg(ESP),make_immed(lc_maxauto));
if (currentfunc->intflag) {
gen_code(op_popad,0,0,0);
if (prm_linkreg && (lc_maxauto || currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1)) {
gen_code(op_leave,0,0,0);
}
gen_code(op_iretd,0,0,0);
}
else {
if( save_mask != 0 )
popregs(save_mask);
if (prm_linkreg && (lc_maxauto || currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1)) {
gen_code(op_leave,0,0,0);
}
if (currentfunc->pascaldefn) {
long retsize = 0;
if (currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM *)-1) {
retsize = currentfunc->tp->lst.head->value.i+((currentfunc->tp->lst.head->tp->size + 3) & 0xfffffffcL);
if (prm_linkreg)
retsize -= 8;
}
if (currentfunc->tp->btp && currentfunc->tp->btp->type != bt_void && (currentfunc->tp->btp->type == bt_struct || currentfunc->tp->btp->type == bt_union))
retsize += 4;
if (retsize) {
gen_code(op_ret,0,make_immed(retsize),0);
return;
}
}
gen_code(op_ret,0,0,0);
}
}
else {
if (retlab == -1)
retlab = nextlabel++;
gen_code(op_jmp,0,make_label(retlab),0);
}
}
void genstmt(SNODE *stmt)
/*
* genstmt will generate a statement and follow the next pointer
* until the block is generated.
*/
{
while( stmt != 0 )
{
switch( stmt->stype )
{
case st_block:
genstmt(stmt->exp);
break;
case st_label:
gen_label((int)stmt->label);
break;
case st_goto:
gen_code(op_jmp,0,make_label((int)stmt->label),0);
break;
case st_expr:
initstack();
gen_expr(stmt->exp,F_ALL | F_NOVALUE,
natural_size(stmt->exp));
break;
case st_return:
genreturn(stmt,0);
break;
case st_if:
genif(stmt);
break;
case st_while:
genwhile(stmt);
break;
case st_do:
gendo(stmt);
break;
case st_for:
gen_for(stmt);
break;
case st_continue:
gen_code(op_jmp,0,make_label(contlab),0);
break;
case st_break:
gen_code(op_jmp,0,make_label(breaklab),0);
break;
case st_switch:
genxswitch(stmt);
break;
case st_line:
gen_line(stmt);
break;
case st_asm:
if (stmt->exp)
add_peep(stmt->exp);
break;
case st__genword:
gen_code(op_genword,0,make_immed((int)stmt->exp),0);
break;
default:
diag("unknown statement.");
break;
}
stmt = stmt->next;
}
}
#ifdef CPLUSPLUS
void scppinit(void)
{
if (!strcmp(currentfunc->name,"_main")) {
AMODE *ap1,*ap2,*ap3,*ap4;
int lbl = nextlabel++;
initstack();
ap1 = temp_data();
ap4 = xalloc(sizeof(AMODE));
ap4->preg = ap1->preg;
ap4->mode = am_indisp;
ap4->offset = makenode(en_icon,0,0);
ap2 = set_symbol("cppistart",0);
ap3 = set_symbol("cppiend",0);
gen_code(op_mov,4,ap1,ap2);
gen_label(lbl);
gen_code(op_push,4,ap1,0);
gen_code(op_call,4,ap4,0);
gen_code(op_pop,4,ap1,0);
gen_code(op_add,4,ap1,make_immed(4));
gen_code(op_cmp,4,ap1,ap3);
gen_code(op_jb,0,make_label(lbl),0);
freeop(ap1);
}
}
#endif
void genfunc(SNODE *stmt)
/*
* generate a function body.
*/
{ retlab = contlab = breaklab = -1;
funcfloat = 0;
init_muldivval();
stackdepth = 0;
if (stmt->stype == st_line) {
gen_line(stmt);
stmt = stmt->next;
}
gen_codelab(currentfunc); /* name of function */
opt1(stmt); /* push args & also subtracts SP */
#ifdef CPLUSPLUS
if (prm_cplusplus)
scppinit();
#endif
genstmt(stmt);
genreturn(0,1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -