void genbinaryswitch(SNODE *stmt, struct cases *cs) { AMODE *ap1; int size = natural_size(stmt->exp); InitRegs(); ap1 = gen_expr_external(stmt->exp, FALSE, F_DREG, BESZ_DWORD); gather_cases(stmt->s1,cs,FALSE); qsort(cs->ptrs,cs->count, sizeof(cs->ptrs[0]), size < 0 ? sortcmpsigned : sortcmpunsigned); bingen(0, (cs->count) / 2, cs->count, ap1, cs, size); }
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 gen_for(SNODE *stmt) /* * generate code to evaluate a for loop */ { int old_break, old_cont, exit_label, loop_label; old_break = breaklab; old_cont = contlab; loop_label = nextlabel++; exit_label = nextlabel++; contlab = nextlabel++; initstack(); if( stmt->label != 0 ) gen_expr(stmt->label,F_ALL | F_NOVALUE ,natural_size(stmt->label)); gen_code(op_jmp,0,make_label(contlab),0); gen_label(loop_label); if( stmt->s1 != 0 ) { breaklab = exit_label; genstmt(stmt->s1); } initstack(); if( stmt->s2 != 0 ) gen_expr(stmt->s2,F_ALL | F_NOVALUE,natural_size(stmt->s2)); gen_label(contlab); if (stmt->lst) gen_line(stmt->lst); initstack(); if( stmt->exp != 0 ) truejp(stmt->exp,loop_label); else gen_code(op_jmp,0,make_label(loop_label),0); gen_label(exit_label); breaklab = old_break; contlab = old_cont; }
void genbinaryswitch(SNODE *stmt, int deflab) { int curlab, i=0,j,size = natural_size(stmt->exp); AMODE *ap1; long switchbottom=gswitchbottom, switchcount=gswitchcount; long switchtop=gswitchtop; int *switchlabels=0; long *switchids=0; int *switchbinlabels=0; curlab = nextlabel++; initstack(); ap1 = gen_expr(stmt->exp,F_DREG,4); global_flag++; switchlabels = xalloc((switchcount) * sizeof(int)); switchbinlabels = xalloc((switchcount) * sizeof(int)); switchids = xalloc((switchcount) * sizeof(long)); global_flag--; stmt = stmt->s1; while (stmt) { if( stmt->s2 ) /* default case ? */ { stmt->label = (SNODE *) deflab; diddef = TRUE; } else { switchlabels[i] = curlab; switchbinlabels[i] = -1; switchids[i++] = (int)stmt->label; stmt->label = (SNODE *)curlab; } if( stmt->next != 0 ) curlab = nextlabel++; stmt = stmt->next; } 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); }
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 gencompactswitch(SNODE *stmt, struct cases *cs) { int tablab, size; AMODE *ap, *ap2; LLONG_TYPE i; tablab = nextlabel++; InitRegs(); size = natural_size(stmt->exp); if (size == BESZ_QWORD || size == - BESZ_QWORD) { ap = gen_expr_external(stmt->exp, FALSE, F_AXDX, 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 }
void genstmt(STATEMENT *stmt, SYMBOL *funcsp) /* * genstmt will generate a statement and follow the next pointer * until the block is generated. */ { while (stmt != 0) { switch (stmt->type) { case st_varstart: gen_varstart(stmt->select); break; case st_dbgblock: gen_dbgblock(stmt->label); break; case st_tryblock: /* gen_tryblock(stmt->label); */ break; case st_block: genstmt(stmt->lower, funcsp); genstmt(stmt->blockTail, funcsp); break; case st_label: gen_label((int)stmt->label); break; case st_goto: gen_igoto(i_goto, (int)stmt->label); break; case st_asmgoto: gen_igoto(i_asmgoto, (int)stmt->label); break; case st_asmcond: gen_igoto(i_asmcond, (int)stmt->label); break; case st_throw: /* gen_throw((TYPE *)stmt->lst, stmt->select);*/ break; /* case st_functailexpr: gen_icode(i_functailstart, 0, 0, 0); gen_expr(funcsp, stmt->select, F_NOVALUE, natural_size(stmt->select)); * gen_icode(i_functailend, 0, 0, 0); break; */ case st_expr: case st_declare: gen_expr(funcsp, stmt->select, F_NOVALUE, natural_size(stmt->select)); break; case st_return: genreturn(stmt, funcsp, 0, 0, NULL); break; case st_line: gen_line(stmt->lineData); break; case st_select: genselect(stmt, funcsp, TRUE); break; case st_notselect: genselect(stmt, funcsp, FALSE); break; case st_switch: genxswitch(stmt, funcsp); break; case st__genword: gen_genword(stmt, funcsp); break; case st_passthrough: gen_asm(stmt); break; case st_datapassthrough: gen_asmdata(stmt); break; default: diag("unknown statement."); break; } stmt = stmt->next; } }
void genreturn(STATEMENT *stmt, SYMBOL *funcsp, int flag, int noepilogue, IMODE *allocaAP) /* * generate a return statement. */ { IMODE *ap, *ap1, *ap3; EXPRESSION ep; /* returns a value? */ if (stmt != 0 && stmt->select != 0) { if (basetype(funcsp->tp)->btp && (isstructured(basetype(funcsp->tp)->btp) || basetype(basetype(funcsp->tp)->btp)->type == bt_memberptr)) { SYMBOL *sp = anonymousVar(sc_parameter, &stdpointer); EXPRESSION *en = varNode(en_auto, sp); IMODE *ap3 = gen_expr(funcsp, stmt->select, 0, ISZ_ADDR), *ap2, *ap1; DumpIncDec(funcsp); if (!ap3->retval) { ap1 = LookupLoadTemp(NULL, ap3); if (ap1 != ap3) { IMODE *barrier; if (stmt->select->isatomic) { barrier = doatomicFence(funcsp, stmt->select, NULL); } gen_icode(i_assn, ap1, ap3, NULL); if (stmt->select->isatomic) { doatomicFence(funcsp, stmt->select, barrier); } } } else { ap1 = ap3; } if ((funcsp->linkage == lk_pascal) && basetype(funcsp->tp)->syms->table[0] && ((SYMBOL *)basetype(funcsp->tp)->syms->table[0])->tp->type != bt_void) { sp->offset = funcsp->paramsize; } else { sp->offset = chosenAssembler->arch->retblocksize+(funcsp->farproc *getSize(bt_pointer)); if (funcsp->storage_class == sc_member || funcsp->storage_class == sc_virtual) sp->offset += getSize(bt_pointer); } en = exprNode(en_l_p, en, NULL); ap3 = gen_expr(funcsp, en, 0, ISZ_ADDR); ap = LookupLoadTemp(NULL, ap3); if (ap != ap3) { IMODE *barrier; if (en->isatomic) { barrier = doatomicFence(funcsp, en, NULL); } gen_icode(i_assn, ap, ap3, NULL); if (en->isatomic) { doatomicFence(funcsp, en, barrier); } } gen_icode(i_assnblock, make_immed(ISZ_NONE, basetype(funcsp->tp)->btp->size), ap, ap1); ap1 = tempreg(ISZ_ADDR, 0); ap1->retval = TRUE; gen_icode(i_assn, ap1, ap, NULL); } else if (basetype(funcsp->tp)->btp && basetype(funcsp->tp)->btp->type == bt_memberptr) { ap3 = gen_expr(funcsp, stmt->select, F_VOL, ISZ_ADDR); DumpIncDec(funcsp); ap = LookupLoadTemp(NULL, ap3); if (ap != ap3) { IMODE *barrier; if (stmt->select->isatomic) { barrier = doatomicFence(funcsp, stmt->select, NULL); } gen_icode(i_assn, ap, ap3, NULL); if (stmt->select->isatomic) { doatomicFence(funcsp, stmt->select, barrier); } } ap1 = tempreg(ISZ_ADDR, 0); ap1->retval = TRUE; gen_icode(i_assn, ap1, ap, 0); } else { int size = natural_size(stmt->select); ap3 = gen_expr(funcsp, stmt->select, 0, size); DumpIncDec(funcsp); ap = LookupLoadTemp(NULL, ap3); if (ap != ap3) { IMODE *barrier; if (stmt->select->isatomic) { barrier = doatomicFence(funcsp, stmt->select, NULL); } gen_icode(i_assn, ap, ap3, NULL); if (stmt->select->isatomic) { doatomicFence(funcsp, stmt->select, barrier); } } if (abs(size) < ISZ_UINT) size = -ISZ_UINT; ap1 = tempreg(size, 0); ap1->retval = TRUE; gen_icode(i_assn, ap1, ap, 0); } } else { DumpIncDec(funcsp); } /* create the return or a branch to the return * return is put at end of function... */ if (flag) { int retsize = 0; if (funcsp->linkage == lk_pascal || funcsp->linkage == lk_stdcall) { retsize = funcsp->paramsize ; } gen_label(retlab); if (!noepilogue) { if (allocaAP) { gen_icode(i_loadstack, 0, allocaAP, 0); } /* if (funcsp->loadds && funcsp->farproc) gen_icode(i_unloadcontext,0,0,0); */ gen_icode(i_epilogue,0,0,0); if (funcsp->linkage == lk_interrupt || funcsp->linkage == lk_fault) { /* if (funcsp->loadds) gen_icode(i_unloadcontext,0,0,0); */ gen_icode(i_popcontext, 0,0,0); gen_icode(i_rett, 0, make_immed(ISZ_NONE,funcsp->linkage == lk_interrupt), 0); } else { gen_icode(i_ret, 0, make_immed(ISZ_NONE,retsize), 0); } } } else { /* not using gen_igoto because it will make a new block */ gen_icode(i_goto, NULL, NULL, NULL); intermed_tail->dc.v.label = retlab; } }
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; } }
IMODE *genstmt(STATEMENT *stmt, SYMBOL *funcsp) /* * genstmt will generate a statement and follow the next pointer * until the block is generated. */ { IMODE *rv = NULL; while (stmt != 0) { STATEMENT *last = stmt; switch (stmt->type) { case st_varstart: gen_varstart(stmt->select); break; case st_dbgblock: gen_dbgblock(stmt->label); break; break; case st_block: rv = genstmt(stmt->lower, funcsp); genstmt(stmt->blockTail, funcsp); break; case st_label: gen_label((int)stmt->label); break; case st_goto: gen_igoto(i_goto, (int)stmt->label); break; case st_asmgoto: gen_igoto(i_asmgoto, (int)stmt->label); break; case st_asmcond: gen_igoto(i_asmcond, (int)stmt->label); break; case st_try: gen_try(funcsp, stmt, stmt->label, stmt->endlabel, stmt->breaklabel, stmt->lower); break; case st_catch: { STATEMENT *last; while (stmt && stmt->type == st_catch) { gen_catch(funcsp, stmt, stmt->altlabel, stmt->breaklabel, stmt->lower); last = stmt; stmt = stmt->next; } stmt = last; gen_label(stmt->breaklabel); } break; case st_expr: case st_declare: if (stmt->select) rv = gen_expr(funcsp, stmt->select, F_NOVALUE, natural_size(stmt->select)); break; case st_return: genreturn(stmt, funcsp, 0, 0, NULL); break; case st_line: gen_line(stmt->lineData); break; case st_select: genselect(stmt, funcsp, TRUE); break; case st_notselect: genselect(stmt, funcsp, FALSE); break; case st_switch: genxswitch(stmt, funcsp); break; case st__genword: gen_genword(stmt, funcsp); break; case st_passthrough: gen_asm(stmt); break; case st_datapassthrough: gen_asmdata(stmt); break; default: diag("unknown statement."); break; } if (last->type != st_return && last->destexp) { gen_expr(funcsp, last->destexp, F_NOVALUE, ISZ_ADDR); } stmt = stmt->next; } return rv; }
void genreturn(STATEMENT *stmt, SYMBOL *funcsp, int flag, int noepilogue, IMODE *allocaAP) /* * generate a return statement. */ { IMODE *ap = NULL, *ap1, *ap3; EXPRESSION ep; int size; /* returns a value? */ if (stmt != 0 && stmt->select != 0) { if (basetype(funcsp->tp)->btp && (isstructured(basetype(funcsp->tp)->btp) || basetype(basetype(funcsp->tp)->btp)->type == bt_memberptr)) { EXPRESSION *en = anonymousVar(sc_parameter, &stdpointer); SYMBOL *sp = en->v.sp; gen_expr(funcsp, stmt->select, 0, ISZ_ADDR); DumpIncDec(funcsp); sp->offset = chosenAssembler->arch->retblocksize; sp->allocate = FALSE; if ((funcsp->linkage == lk_pascal) && basetype(funcsp->tp)->syms->table[0] && ((SYMBOL *)basetype(funcsp->tp)->syms->table[0])->tp->type != bt_void) sp->offset = funcsp->paramsize; deref(&stdpointer, &en); ap = gen_expr(funcsp, en, 0, ISZ_ADDR); size = ISZ_ADDR; } else { size = natural_size(stmt->select); ap3 = gen_expr(funcsp, stmt->select, 0, size); DumpIncDec(funcsp); ap = LookupLoadTemp(NULL, ap3); if (ap != ap3) { IMODE *barrier; if (stmt->select->isatomic) { barrier = doatomicFence(funcsp, stmt->select, NULL); } gen_icode(i_assn, ap, ap3, NULL); if (stmt->select->isatomic) { doatomicFence(funcsp, stmt->select, barrier); } } if (abs(size) < ISZ_UINT) size = -ISZ_UINT; } } else { DumpIncDec(funcsp); } if (ap) { ap1 = tempreg(size, 0); ap1->retval = TRUE; gen_icode(i_assn, ap1, ap, 0); } if (stmt && stmt->destexp) { gen_expr(funcsp, stmt->destexp, F_NOVALUE, ISZ_ADDR); } /* create the return or a branch to the return * return is put at end of function... */ if (flag) { int retsize = 0; if (funcsp->linkage == lk_pascal || funcsp->linkage == lk_stdcall) { retsize = funcsp->paramsize ; } gen_label(retlab); if (!noepilogue) { if (allocaAP) { gen_icode(i_loadstack, 0, allocaAP, 0); } /* if (funcsp->loadds && funcsp->farproc) gen_icode(i_unloadcontext,0,0,0); */ if (cparams.prm_xcept && funcsp->xc && funcsp->xc->xcRundownFunc) gen_expr(funcsp, funcsp->xc->xcRundownFunc, F_NOVALUE, ISZ_UINT); gen_icode(i_epilogue,0,0,0); if (funcsp->linkage == lk_interrupt || funcsp->linkage == lk_fault) { /* if (funcsp->loadds) gen_icode(i_unloadcontext,0,0,0); */ gen_icode(i_popcontext, 0,0,0); gen_icode(i_rett, 0, make_immed(ISZ_UINT,funcsp->linkage == lk_interrupt), 0); } else { gen_icode(i_ret, 0, make_immed(ISZ_UINT,retsize), 0); } } } else { /* not using gen_igoto because it will make a new block */ gen_icode(i_goto, NULL, NULL, NULL); intermed_tail->dc.v.label = retlab; } }