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 genxswitch(STATEMENT *stmt, SYMBOL *funcsp) /* * analyze and generate best switch statement. */ { int oldbreak, i; struct cases cs; IMODE *ap, *ap3; #ifdef USE_LONGLONG ULLONG_TYPE a = 1; #endif oldbreak = breaklab; breaklab = stmt->breaklabel; memset(&cs,0,sizeof(cs)); #ifndef USE_LONGLONG cs.top = INT_MIN; cs.bottom = INT_MAX; #else cs.top = (a << 63); /* LLONG_MIN*/ cs.bottom = cs.top - 1; /* LLONG_MAX*/ #endif count_cases(stmt->cases,&cs) ; cs.top++; ap3 = gen_expr(funcsp, stmt->select, F_VOL | F_NOVALUE, ISZ_UINT); 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); } } gen_icode2(i_coswitch, make_immed(ISZ_NONE,cs.count), ap, make_immed(ISZ_NONE,cs.top - cs.bottom), stmt->label); gather_cases(stmt->cases,&cs); qsort(cs.ptrs, cs.count, sizeof(cs.ptrs[0]), gcs_compare); for (i = 0; i < cs.count; i++) { gen_icode2(i_swbranch,0,make_immed(ISZ_NONE,cs.ptrs[i].id),0,cs.ptrs[i].label); } breaklab = oldbreak; }
//------------------------------------------------------------------------- void gather_cases(SNODE *stmt, struct cases *cs, int compact) { if (!cs->ptrs) { global_flag++; if (compact) { unsigned i; cs->ptrs = xalloc((cs->top - cs->bottom) * sizeof(struct caseptrs)); for (i = 0; i < cs->top-cs->bottom; i++) { cs->ptrs[i].label = cs->deflab; } } else cs->ptrs = xalloc((cs->count) * sizeof(struct caseptrs)); 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; } }