From: divverent Date: Tue, 7 Jan 2014 19:22:59 +0000 (+0000) Subject: Use an explicit jump table for QCVM instruction dispatch. X-Git-Tag: xonotic-v0.8.1~29^2~114 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=91efd4d4260983eae86f644ff1813cc391d3c27e;p=xonotic%2Fdarkplaces.git Use an explicit jump table for QCVM instruction dispatch. Also, duplicate the dispatch into the end of each case for additional speedup (each of these branches gets a separate branch prediction slot on many CPUs, which pays off quickly). git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12044 d7cf8633-e32d-0410-b094-e92efae38249 --- diff --git a/prvm_exec.c b/prvm_exec.c index b926f26c..65ee31b2 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -716,6 +716,9 @@ static void PRVM_StatementCoverageEvent(prvm_prog_t *prog, mfunction_t *func, in Con_Printf("prvm_coverage: %s just executed a statement at %s for the first time. Coverage: %.2f%%.\n", prog->name, PRVM_WhereAmI(vabuf, sizeof(vabuf), prog, func, statement), prog->statements_covered * 100.0 / prog->numstatements); } +#ifdef __GNUC__ +#define HAVE_COMPUTED_GOTOS 1 +#endif #define OPA ((prvm_eval_t *)&prog->globals.fp[st->operand[0]]) #define OPB ((prvm_eval_t *)&prog->globals.fp[st->operand[1]]) diff --git a/prvm_execprogram.h b/prvm_execprogram.h index d7182fc7..5e94073d 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -12,6 +12,100 @@ // This code isn't #ifdef/#define protectable, don't try. +#if HAVE_COMPUTED_GOTOS && !(PRVMSLOWINTERPRETER || PRVMTIMEPROFILING) + // NOTE: Due to otherwise duplicate labels, only ONE interpreter path may + // ever hit this! +# define USE_COMPUTED_GOTOS 1 +#endif + +#if USE_COMPUTED_GOTOS + // Must exactly match opcode_e enum in pr_comp.h + const static void *dispatchtable[] = { + &&handle_OP_DONE, + &&handle_OP_MUL_F, + &&handle_OP_MUL_V, + &&handle_OP_MUL_FV, + &&handle_OP_MUL_VF, + &&handle_OP_DIV_F, + &&handle_OP_ADD_F, + &&handle_OP_ADD_V, + &&handle_OP_SUB_F, + &&handle_OP_SUB_V, + + &&handle_OP_EQ_F, + &&handle_OP_EQ_V, + &&handle_OP_EQ_S, + &&handle_OP_EQ_E, + &&handle_OP_EQ_FNC, + + &&handle_OP_NE_F, + &&handle_OP_NE_V, + &&handle_OP_NE_S, + &&handle_OP_NE_E, + &&handle_OP_NE_FNC, + + &&handle_OP_LE, + &&handle_OP_GE, + &&handle_OP_LT, + &&handle_OP_GT, + + &&handle_OP_LOAD_F, + &&handle_OP_LOAD_V, + &&handle_OP_LOAD_S, + &&handle_OP_LOAD_ENT, + &&handle_OP_LOAD_FLD, + &&handle_OP_LOAD_FNC, + + &&handle_OP_ADDRESS, + + &&handle_OP_STORE_F, + &&handle_OP_STORE_V, + &&handle_OP_STORE_S, + &&handle_OP_STORE_ENT, + &&handle_OP_STORE_FLD, + &&handle_OP_STORE_FNC, + + &&handle_OP_STOREP_F, + &&handle_OP_STOREP_V, + &&handle_OP_STOREP_S, + &&handle_OP_STOREP_ENT, + &&handle_OP_STOREP_FLD, + &&handle_OP_STOREP_FNC, + + &&handle_OP_RETURN, + &&handle_OP_NOT_F, + &&handle_OP_NOT_V, + &&handle_OP_NOT_S, + &&handle_OP_NOT_ENT, + &&handle_OP_NOT_FNC, + &&handle_OP_IF, + &&handle_OP_IFNOT, + &&handle_OP_CALL0, + &&handle_OP_CALL1, + &&handle_OP_CALL2, + &&handle_OP_CALL3, + &&handle_OP_CALL4, + &&handle_OP_CALL5, + &&handle_OP_CALL6, + &&handle_OP_CALL7, + &&handle_OP_CALL8, + &&handle_OP_STATE, + &&handle_OP_GOTO, + &&handle_OP_AND, + &&handle_OP_OR, + + &&handle_OP_BITAND, + &&handle_OP_BITOR + }; +#define DISPATCH_OPCODE() \ + goto *dispatchtable[(++st)->op] +#define HANDLE_OPCODE(opcode) handle_##opcode + + DISPATCH_OPCODE(); // jump to first opcode +#else // USE_COMPUTED_GOTOS +#define DISPATCH_OPCODE() break +#define HANDLE_OPCODE(opcode) case opcode + #if PRVMSLOWINTERPRETER { if (prog->watch_global_type != ev_void) @@ -32,6 +126,9 @@ while (1) { st++; +#endif // USE_COMPUTED_GOTOS + +#if !USE_COMPUTED_GOTOS #if PRVMSLOWINTERPRETER if (prog->trace) @@ -45,44 +142,44 @@ PRVM_Breakpoint(prog, prog->break_stack_index, "Breakpoint hit"); } #endif - switch (st->op) { - case OP_ADD_F: +#endif + HANDLE_OPCODE(OP_ADD_F): OPC->_float = OPA->_float + OPB->_float; - break; - case OP_ADD_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_ADD_V): OPC->vector[0] = OPA->vector[0] + OPB->vector[0]; OPC->vector[1] = OPA->vector[1] + OPB->vector[1]; OPC->vector[2] = OPA->vector[2] + OPB->vector[2]; - break; - case OP_SUB_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_SUB_F): OPC->_float = OPA->_float - OPB->_float; - break; - case OP_SUB_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_SUB_V): OPC->vector[0] = OPA->vector[0] - OPB->vector[0]; OPC->vector[1] = OPA->vector[1] - OPB->vector[1]; OPC->vector[2] = OPA->vector[2] - OPB->vector[2]; - break; - case OP_MUL_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_F): OPC->_float = OPA->_float * OPB->_float; - break; - case OP_MUL_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_V): OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2]; - break; - case OP_MUL_FV: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_FV): tempfloat = OPA->_float; OPC->vector[0] = tempfloat * OPB->vector[0]; OPC->vector[1] = tempfloat * OPB->vector[1]; OPC->vector[2] = tempfloat * OPB->vector[2]; - break; - case OP_MUL_VF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_VF): tempfloat = OPB->_float; OPC->vector[0] = tempfloat * OPA->vector[0]; OPC->vector[1] = tempfloat * OPA->vector[1]; OPC->vector[2] = tempfloat * OPA->vector[2]; - break; - case OP_DIV_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_DIV_F): if( OPB->_float != 0.0f ) { OPC->_float = OPA->_float / OPB->_float; @@ -98,96 +195,96 @@ } OPC->_float = 0.0f; } - break; - case OP_BITAND: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITAND): OPC->_float = (prvm_int_t)OPA->_float & (prvm_int_t)OPB->_float; - break; - case OP_BITOR: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITOR): OPC->_float = (prvm_int_t)OPA->_float | (prvm_int_t)OPB->_float; - break; - case OP_GE: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GE): OPC->_float = OPA->_float >= OPB->_float; - break; - case OP_LE: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LE): OPC->_float = OPA->_float <= OPB->_float; - break; - case OP_GT: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GT): OPC->_float = OPA->_float > OPB->_float; - break; - case OP_LT: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LT): OPC->_float = OPA->_float < OPB->_float; - break; - case OP_AND: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_AND): OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) && FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add AND_I to be used by fteqcc for anything not a float - break; - case OP_OR: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_OR): OPC->_float = FLOAT_IS_TRUE_FOR_INT(OPA->_int) || FLOAT_IS_TRUE_FOR_INT(OPB->_int); // TODO change this back to float, and add OR_I to be used by fteqcc for anything not a float - break; - case OP_NOT_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_F): OPC->_float = !FLOAT_IS_TRUE_FOR_INT(OPA->_int); - break; - case OP_NOT_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_V): OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]; - break; - case OP_NOT_S: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_S): OPC->_float = !OPA->string || !*PRVM_GetString(prog, OPA->string); - break; - case OP_NOT_FNC: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_FNC): OPC->_float = !OPA->function; - break; - case OP_NOT_ENT: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_ENT): OPC->_float = (OPA->edict == 0); - break; - case OP_EQ_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_F): OPC->_float = OPA->_float == OPB->_float; - break; - case OP_EQ_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_V): OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]); - break; - case OP_EQ_S: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_S): OPC->_float = !strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string)); - break; - case OP_EQ_E: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_E): OPC->_float = OPA->_int == OPB->_int; - break; - case OP_EQ_FNC: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_FNC): OPC->_float = OPA->function == OPB->function; - break; - case OP_NE_F: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_F): OPC->_float = OPA->_float != OPB->_float; - break; - case OP_NE_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_V): OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]); - break; - case OP_NE_S: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_S): OPC->_float = strcmp(PRVM_GetString(prog, OPA->string),PRVM_GetString(prog, OPB->string)); - break; - case OP_NE_E: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_E): OPC->_float = OPA->_int != OPB->_int; - break; - case OP_NE_FNC: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_FNC): OPC->_float = OPA->function != OPB->function; - break; + DISPATCH_OPCODE(); //================== - case OP_STORE_F: - case OP_STORE_ENT: - case OP_STORE_FLD: // integers - case OP_STORE_S: - case OP_STORE_FNC: // pointers + HANDLE_OPCODE(OP_STORE_F): + HANDLE_OPCODE(OP_STORE_ENT): + HANDLE_OPCODE(OP_STORE_FLD): // integers + HANDLE_OPCODE(OP_STORE_S): + HANDLE_OPCODE(OP_STORE_FNC): // pointers OPB->_int = OPA->_int; - break; - case OP_STORE_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_STORE_V): OPB->ivector[0] = OPA->ivector[0]; OPB->ivector[1] = OPA->ivector[1]; OPB->ivector[2] = OPA->ivector[2]; - break; + DISPATCH_OPCODE(); - case OP_STOREP_F: - case OP_STOREP_ENT: - case OP_STOREP_FLD: // integers - case OP_STOREP_S: - case OP_STOREP_FNC: // pointers + HANDLE_OPCODE(OP_STOREP_F): + HANDLE_OPCODE(OP_STOREP_ENT): + HANDLE_OPCODE(OP_STOREP_FLD): // integers + HANDLE_OPCODE(OP_STOREP_S): + HANDLE_OPCODE(OP_STOREP_FNC): // pointers if ((prvm_uint_t)OPB->_int - cached_entityfields >= cached_entityfieldsarea_entityfields) { if ((prvm_uint_t)OPB->_int >= cached_entityfieldsarea) @@ -204,8 +301,8 @@ } ptr = (prvm_eval_t *)(cached_edictsfields + OPB->_int); ptr->_int = OPA->_int; - break; - case OP_STOREP_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_STOREP_V): if ((prvm_uint_t)OPB->_int - cached_entityfields > (prvm_uint_t)cached_entityfieldsarea_entityfields_3) { if ((prvm_uint_t)OPB->_int > cached_entityfieldsarea_3) @@ -224,9 +321,9 @@ ptr->ivector[0] = OPA->ivector[0]; ptr->ivector[1] = OPA->ivector[1]; ptr->ivector[2] = OPA->ivector[2]; - break; + DISPATCH_OPCODE(); - case OP_ADDRESS: + HANDLE_OPCODE(OP_ADDRESS): if ((prvm_uint_t)OPA->edict >= cached_max_edicts) { PreError(); @@ -248,13 +345,13 @@ } #endif OPC->_int = OPA->edict * cached_entityfields + OPB->_int; - break; + DISPATCH_OPCODE(); - case OP_LOAD_F: - case OP_LOAD_FLD: - case OP_LOAD_ENT: - case OP_LOAD_S: - case OP_LOAD_FNC: + HANDLE_OPCODE(OP_LOAD_F): + HANDLE_OPCODE(OP_LOAD_FLD): + HANDLE_OPCODE(OP_LOAD_ENT): + HANDLE_OPCODE(OP_LOAD_S): + HANDLE_OPCODE(OP_LOAD_FNC): if ((prvm_uint_t)OPA->edict >= cached_max_edicts) { PreError(); @@ -269,9 +366,9 @@ } ed = PRVM_PROG_TO_EDICT(OPA->edict); OPC->_int = ((prvm_eval_t *)(ed->fields.ip + OPB->_int))->_int; - break; + DISPATCH_OPCODE(); - case OP_LOAD_V: + HANDLE_OPCODE(OP_LOAD_V): if ((prvm_uint_t)OPA->edict >= cached_max_edicts) { PreError(); @@ -289,11 +386,11 @@ OPC->ivector[0] = ptr->ivector[0]; OPC->ivector[1] = ptr->ivector[1]; OPC->ivector[2] = ptr->ivector[2]; - break; + DISPATCH_OPCODE(); //================== - case OP_IFNOT: + HANDLE_OPCODE(OP_IFNOT): if(!FLOAT_IS_TRUE_FOR_INT(OPA->_int)) // TODO add an "int-if", and change this one to OPA->_float // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) @@ -310,9 +407,9 @@ prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); } } - break; + DISPATCH_OPCODE(); - case OP_IF: + HANDLE_OPCODE(OP_IF): if(FLOAT_IS_TRUE_FOR_INT(OPA->_int)) // TODO add an "int-if", and change this one, as well as the FLOAT_IS_TRUE_FOR_INT usages, to OPA->_float // although mostly unneeded, thanks to the only float being false being 0x0 and 0x80000000 (negative zero) @@ -329,9 +426,9 @@ prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); } } - break; + DISPATCH_OPCODE(); - case OP_GOTO: + HANDLE_OPCODE(OP_GOTO): prog->xfunction->profile += (st - startst); st = cached_statements + st->jumpabsolute - 1; // offset the st++ startst = st; @@ -342,17 +439,17 @@ PRVM_Profile(prog, 1<<30, 0.01, 0); prog->error_cmd("%s runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", prog->name, jumpcount); } - break; - - case OP_CALL0: - case OP_CALL1: - case OP_CALL2: - case OP_CALL3: - case OP_CALL4: - case OP_CALL5: - case OP_CALL6: - case OP_CALL7: - case OP_CALL8: + DISPATCH_OPCODE(); + + HANDLE_OPCODE(OP_CALL0): + HANDLE_OPCODE(OP_CALL1): + HANDLE_OPCODE(OP_CALL2): + HANDLE_OPCODE(OP_CALL3): + HANDLE_OPCODE(OP_CALL4): + HANDLE_OPCODE(OP_CALL5): + HANDLE_OPCODE(OP_CALL6): + HANDLE_OPCODE(OP_CALL7): + HANDLE_OPCODE(OP_CALL8): #ifdef PRVMTIMEPROFILING tm = Sys_DirtyTime(); prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; @@ -413,10 +510,10 @@ else st = cached_statements + PRVM_EnterFunction(prog, newf); startst = st; - break; + DISPATCH_OPCODE(); - case OP_DONE: - case OP_RETURN: + HANDLE_OPCODE(OP_DONE): + HANDLE_OPCODE(OP_RETURN): #ifdef PRVMTIMEPROFILING tm = Sys_DirtyTime(); prog->xfunction->tprofile += (tm - starttm >= 0 && tm - starttm < 1800) ? (tm - starttm) : 0; @@ -433,9 +530,9 @@ startst = st; if (prog->depth <= exitdepth) goto cleanup; // all done - break; + DISPATCH_OPCODE(); - case OP_STATE: + HANDLE_OPCODE(OP_STATE): if(cached_flag & PRVM_OP_STATE) { ed = PRVM_PROG_TO_EDICT(PRVM_gameglobaledict(self)); @@ -449,162 +546,162 @@ prog->xstatement = st - cached_statements; prog->error_cmd("OP_STATE not supported by %s", prog->name); } - break; + DISPATCH_OPCODE(); // LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized /* - case OP_ADD_I: + HANDLE_OPCODE(OP_ADD_I): OPC->_int = OPA->_int + OPB->_int; - break; - case OP_ADD_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_ADD_IF): OPC->_int = OPA->_int + (prvm_int_t) OPB->_float; - break; - case OP_ADD_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_ADD_FI): OPC->_float = OPA->_float + (prvm_vec_t) OPB->_int; - break; - case OP_SUB_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_SUB_I): OPC->_int = OPA->_int - OPB->_int; - break; - case OP_SUB_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_SUB_IF): OPC->_int = OPA->_int - (prvm_int_t) OPB->_float; - break; - case OP_SUB_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_SUB_FI): OPC->_float = OPA->_float - (prvm_vec_t) OPB->_int; - break; - case OP_MUL_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_I): OPC->_int = OPA->_int * OPB->_int; - break; - case OP_MUL_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_IF): OPC->_int = OPA->_int * (prvm_int_t) OPB->_float; - break; - case OP_MUL_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_FI): OPC->_float = OPA->_float * (prvm_vec_t) OPB->_int; - break; - case OP_MUL_VI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_MUL_VI): OPC->vector[0] = (prvm_vec_t) OPB->_int * OPA->vector[0]; OPC->vector[1] = (prvm_vec_t) OPB->_int * OPA->vector[1]; OPC->vector[2] = (prvm_vec_t) OPB->_int * OPA->vector[2]; - break; - case OP_DIV_VF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_DIV_VF): { float temp = 1.0f / OPB->_float; OPC->vector[0] = temp * OPA->vector[0]; OPC->vector[1] = temp * OPA->vector[1]; OPC->vector[2] = temp * OPA->vector[2]; } - break; - case OP_DIV_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_DIV_I): OPC->_int = OPA->_int / OPB->_int; - break; - case OP_DIV_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_DIV_IF): OPC->_int = OPA->_int / (prvm_int_t) OPB->_float; - break; - case OP_DIV_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_DIV_FI): OPC->_float = OPA->_float / (prvm_vec_t) OPB->_int; - break; - case OP_CONV_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_CONV_IF): OPC->_float = OPA->_int; - break; - case OP_CONV_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_CONV_FI): OPC->_int = OPA->_float; - break; - case OP_BITAND_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITAND_I): OPC->_int = OPA->_int & OPB->_int; - break; - case OP_BITOR_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITOR_I): OPC->_int = OPA->_int | OPB->_int; - break; - case OP_BITAND_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITAND_IF): OPC->_int = OPA->_int & (prvm_int_t)OPB->_float; - break; - case OP_BITOR_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITOR_IF): OPC->_int = OPA->_int | (prvm_int_t)OPB->_float; - break; - case OP_BITAND_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITAND_FI): OPC->_float = (prvm_int_t)OPA->_float & OPB->_int; - break; - case OP_BITOR_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_BITOR_FI): OPC->_float = (prvm_int_t)OPA->_float | OPB->_int; - break; - case OP_GE_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GE_I): OPC->_float = OPA->_int >= OPB->_int; - break; - case OP_LE_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LE_I): OPC->_float = OPA->_int <= OPB->_int; - break; - case OP_GT_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GT_I): OPC->_float = OPA->_int > OPB->_int; - break; - case OP_LT_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LT_I): OPC->_float = OPA->_int < OPB->_int; - break; - case OP_AND_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_AND_I): OPC->_float = OPA->_int && OPB->_int; - break; - case OP_OR_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_OR_I): OPC->_float = OPA->_int || OPB->_int; - break; - case OP_GE_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GE_IF): OPC->_float = (prvm_vec_t)OPA->_int >= OPB->_float; - break; - case OP_LE_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LE_IF): OPC->_float = (prvm_vec_t)OPA->_int <= OPB->_float; - break; - case OP_GT_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GT_IF): OPC->_float = (prvm_vec_t)OPA->_int > OPB->_float; - break; - case OP_LT_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LT_IF): OPC->_float = (prvm_vec_t)OPA->_int < OPB->_float; - break; - case OP_AND_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_AND_IF): OPC->_float = (prvm_vec_t)OPA->_int && OPB->_float; - break; - case OP_OR_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_OR_IF): OPC->_float = (prvm_vec_t)OPA->_int || OPB->_float; - break; - case OP_GE_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GE_FI): OPC->_float = OPA->_float >= (prvm_vec_t)OPB->_int; - break; - case OP_LE_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LE_FI): OPC->_float = OPA->_float <= (prvm_vec_t)OPB->_int; - break; - case OP_GT_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GT_FI): OPC->_float = OPA->_float > (prvm_vec_t)OPB->_int; - break; - case OP_LT_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LT_FI): OPC->_float = OPA->_float < (prvm_vec_t)OPB->_int; - break; - case OP_AND_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_AND_FI): OPC->_float = OPA->_float && (prvm_vec_t)OPB->_int; - break; - case OP_OR_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_OR_FI): OPC->_float = OPA->_float || (prvm_vec_t)OPB->_int; - break; - case OP_NOT_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NOT_I): OPC->_float = !OPA->_int; - break; - case OP_EQ_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_I): OPC->_float = OPA->_int == OPB->_int; - break; - case OP_EQ_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_IF): OPC->_float = (prvm_vec_t)OPA->_int == OPB->_float; - break; - case OP_EQ_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_EQ_FI): OPC->_float = OPA->_float == (prvm_vec_t)OPB->_int; - break; - case OP_NE_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_I): OPC->_float = OPA->_int != OPB->_int; - break; - case OP_NE_IF: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_IF): OPC->_float = (prvm_vec_t)OPA->_int != OPB->_float; - break; - case OP_NE_FI: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_NE_FI): OPC->_float = OPA->_float != (prvm_vec_t)OPB->_int; - break; - case OP_STORE_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_STORE_I): OPB->_int = OPA->_int; - break; - case OP_STOREP_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_STOREP_I): #if PRBOUNDSCHECK if (OPB->_int < 0 || OPB->_int + 4 > pr_edictareasize) { @@ -615,8 +712,8 @@ #endif ptr = (prvm_eval_t *)(prog->edictsfields + OPB->_int); ptr->_int = OPA->_int; - break; - case OP_LOAD_I: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_LOAD_I): #if PRBOUNDSCHECK if (OPA->edict < 0 || OPA->edict >= prog->max_edicts) { @@ -633,14 +730,14 @@ #endif ed = PRVM_PROG_TO_EDICT(OPA->edict); OPC->_int = ((prvm_eval_t *)((int *)ed->v + OPB->_int))->_int; - break; - - case OP_GSTOREP_I: - case OP_GSTOREP_F: - case OP_GSTOREP_ENT: - case OP_GSTOREP_FLD: // integers - case OP_GSTOREP_S: - case OP_GSTOREP_FNC: // pointers + DISPATCH_OPCODE(); + + HANDLE_OPCODE(OP_GSTOREP_I): + HANDLE_OPCODE(OP_GSTOREP_F): + HANDLE_OPCODE(OP_GSTOREP_ENT): + HANDLE_OPCODE(OP_GSTOREP_FLD): // integers + HANDLE_OPCODE(OP_GSTOREP_S): + HANDLE_OPCODE(OP_GSTOREP_FNC): // pointers #if PRBOUNDSCHECK if (OPB->_int < 0 || OPB->_int >= pr_globaldefs) { @@ -650,8 +747,8 @@ } #endif pr_iglobals[OPB->_int] = OPA->_int; - break; - case OP_GSTOREP_V: + DISPATCH_OPCODE(); + HANDLE_OPCODE(OP_GSTOREP_V): #if PRBOUNDSCHECK if (OPB->_int < 0 || OPB->_int + 2 >= pr_globaldefs) { @@ -663,9 +760,9 @@ pr_iglobals[OPB->_int ] = OPA->ivector[0]; pr_iglobals[OPB->_int+1] = OPA->ivector[1]; pr_iglobals[OPB->_int+2] = OPA->ivector[2]; - break; + DISPATCH_OPCODE(); - case OP_GADDRESS: + HANDLE_OPCODE(OP_GADDRESS): i = OPA->_int + (prvm_int_t) OPB->_float; #if PRBOUNDSCHECK if (i < 0 || i >= pr_globaldefs) @@ -676,14 +773,14 @@ } #endif OPC->_int = pr_iglobals[i]; - break; - - case OP_GLOAD_I: - case OP_GLOAD_F: - case OP_GLOAD_FLD: - case OP_GLOAD_ENT: - case OP_GLOAD_S: - case OP_GLOAD_FNC: + DISPATCH_OPCODE(); + + HANDLE_OPCODE(OP_GLOAD_I): + HANDLE_OPCODE(OP_GLOAD_F): + HANDLE_OPCODE(OP_GLOAD_FLD): + HANDLE_OPCODE(OP_GLOAD_ENT): + HANDLE_OPCODE(OP_GLOAD_S): + HANDLE_OPCODE(OP_GLOAD_FNC): #if PRBOUNDSCHECK if (OPA->_int < 0 || OPA->_int >= pr_globaldefs) { @@ -693,9 +790,9 @@ } #endif OPC->_int = pr_iglobals[OPA->_int]; - break; + DISPATCH_OPCODE(); - case OP_GLOAD_V: + HANDLE_OPCODE(OP_GLOAD_V): #if PRBOUNDSCHECK if (OPA->_int < 0 || OPA->_int + 2 >= pr_globaldefs) { @@ -707,19 +804,20 @@ OPC->ivector[0] = pr_iglobals[OPA->_int ]; OPC->ivector[1] = pr_iglobals[OPA->_int+1]; OPC->ivector[2] = pr_iglobals[OPA->_int+2]; - break; + DISPATCH_OPCODE(); - case OP_BOUNDCHECK: + HANDLE_OPCODE(OP_BOUNDCHECK): if (OPA->_int < 0 || OPA->_int >= st->b) { PreError(); prog->error_cmd("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", prog->name, st->b, st->c); goto cleanup; } - break; + DISPATCH_OPCODE(); */ +#if !USE_COMPUTED_GOTOS default: PreError(); prog->error_cmd("Bad opcode %i in %s", st->op, prog->name); @@ -742,5 +840,11 @@ } #endif } +#endif // !USE_COMPUTED_GOTOS + +#undef DISPATCH_OPCODE +#undef HANDLE_OPCODE +#undef USE_COMPUTED_GOTOS + #undef PreError