improve lua opcode dispatch performance by using computed goto instead of switch/case - improves performance by about 10% in a simple loop test
SVN-Revision: 12378
This commit is contained in:
		
							
								
								
									
										363
									
								
								package/lua/patches/300-opcode_performance.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										363
									
								
								package/lua/patches/300-opcode_performance.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,363 @@ | ||||
| --- a/src/lvm.c | ||||
| +++ b/src/lvm.c | ||||
| @@ -31,6 +31,9 @@ | ||||
|  /* limit for table tag-method chains (to avoid loops) */ | ||||
|  #define MAXTAGLOOP	100 | ||||
|   | ||||
| +#ifdef __GNUC__ | ||||
| +#define COMPUTED_GOTO 1 | ||||
| +#endif | ||||
|   | ||||
|  /* | ||||
|   * If 'obj' is a string, it is tried to be interpreted as a number. | ||||
| @@ -562,12 +565,65 @@ | ||||
|      ARITH_OP1_END | ||||
|  #endif | ||||
|   | ||||
| +#ifdef COMPUTED_GOTO | ||||
| +#define OPCODE_TARGET(op) DO_OP_##op: | ||||
| +#define CALL_OPCODE(op) \ | ||||
| +	if ((op < sizeof(opcodes) / sizeof(opcodes[0])) && opcodes[op]) \ | ||||
| +		goto *opcodes[op]; | ||||
| +#define OPCODE_PTR(op) [OP_##op] = &&DO_OP_##op | ||||
| +#else | ||||
| +#define OPCODE_TARGET(op) case OP_##op: | ||||
| +#define CALL_OPCODE(op) switch (op) | ||||
| +#endif | ||||
| + | ||||
|   | ||||
|  void luaV_execute (lua_State *L, int nexeccalls) { | ||||
|    LClosure *cl; | ||||
|    StkId base; | ||||
|    TValue *k; | ||||
|    const Instruction *pc; | ||||
| +#ifdef COMPUTED_GOTO | ||||
| +  static const void *opcodes[] = { | ||||
| +   OPCODE_PTR(MOVE), | ||||
| +   OPCODE_PTR(LOADK), | ||||
| +   OPCODE_PTR(LOADBOOL), | ||||
| +   OPCODE_PTR(LOADNIL), | ||||
| +   OPCODE_PTR(GETUPVAL), | ||||
| +   OPCODE_PTR(GETGLOBAL), | ||||
| +   OPCODE_PTR(GETTABLE), | ||||
| +   OPCODE_PTR(SETGLOBAL), | ||||
| +   OPCODE_PTR(SETUPVAL), | ||||
| +   OPCODE_PTR(SETTABLE), | ||||
| +   OPCODE_PTR(NEWTABLE), | ||||
| +   OPCODE_PTR(SELF), | ||||
| +   OPCODE_PTR(ADD), | ||||
| +   OPCODE_PTR(SUB), | ||||
| +   OPCODE_PTR(MUL), | ||||
| +   OPCODE_PTR(DIV), | ||||
| +   OPCODE_PTR(MOD), | ||||
| +   OPCODE_PTR(POW), | ||||
| +   OPCODE_PTR(UNM), | ||||
| +   OPCODE_PTR(NOT), | ||||
| +   OPCODE_PTR(LEN), | ||||
| +   OPCODE_PTR(CONCAT), | ||||
| +   OPCODE_PTR(JMP), | ||||
| +   OPCODE_PTR(EQ), | ||||
| +   OPCODE_PTR(LT), | ||||
| +   OPCODE_PTR(LE), | ||||
| +   OPCODE_PTR(TEST), | ||||
| +   OPCODE_PTR(TESTSET), | ||||
| +   OPCODE_PTR(CALL), | ||||
| +   OPCODE_PTR(TAILCALL), | ||||
| +   OPCODE_PTR(RETURN), | ||||
| +   OPCODE_PTR(FORLOOP), | ||||
| +   OPCODE_PTR(FORPREP), | ||||
| +   OPCODE_PTR(TFORLOOP), | ||||
| +   OPCODE_PTR(SETLIST), | ||||
| +   OPCODE_PTR(CLOSE), | ||||
| +   OPCODE_PTR(CLOSURE), | ||||
| +   OPCODE_PTR(VARARG) | ||||
| +  }; | ||||
| +#endif | ||||
|   reentry:  /* entry point */ | ||||
|    lua_assert(isLua(L->ci)); | ||||
|    pc = L->savedpc; | ||||
| @@ -593,32 +649,32 @@ | ||||
|      lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); | ||||
|      lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); | ||||
|      switch (GET_OPCODE(i)) { | ||||
| -      case OP_MOVE: { | ||||
| +      OPCODE_TARGET(MOVE) { | ||||
|          setobjs2s(L, ra, RB(i)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LOADK: { | ||||
| +      OPCODE_TARGET(LOADK) { | ||||
|          setobj2s(L, ra, KBx(i)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LOADBOOL: { | ||||
| +      OPCODE_TARGET(LOADBOOL) { | ||||
|          setbvalue(ra, GETARG_B(i)); | ||||
|          if (GETARG_C(i)) pc++;  /* skip next instruction (if C) */ | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LOADNIL: { | ||||
| +      OPCODE_TARGET(LOADNIL) { | ||||
|          TValue *rb = RB(i); | ||||
|          do { | ||||
|            setnilvalue(rb--); | ||||
|          } while (rb >= ra); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_GETUPVAL: { | ||||
| +      OPCODE_TARGET(GETUPVAL) { | ||||
|          int b = GETARG_B(i); | ||||
|          setobj2s(L, ra, cl->upvals[b]->v); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_GETGLOBAL: { | ||||
| +      OPCODE_TARGET(GETGLOBAL) { | ||||
|          TValue g; | ||||
|          TValue *rb = KBx(i); | ||||
|          sethvalue(L, &g, cl->env); | ||||
| @@ -626,88 +682,88 @@ | ||||
|          Protect(luaV_gettable(L, &g, rb, ra)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_GETTABLE: { | ||||
| +      OPCODE_TARGET(GETTABLE) { | ||||
|          Protect(luaV_gettable(L, RB(i), RKC(i), ra)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SETGLOBAL: { | ||||
| +      OPCODE_TARGET(SETGLOBAL) { | ||||
|          TValue g; | ||||
|          sethvalue(L, &g, cl->env); | ||||
|          lua_assert(ttisstring(KBx(i))); | ||||
|          Protect(luaV_settable(L, &g, KBx(i), ra)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SETUPVAL: { | ||||
| +      OPCODE_TARGET(SETUPVAL) { | ||||
|          UpVal *uv = cl->upvals[GETARG_B(i)]; | ||||
|          setobj(L, uv->v, ra); | ||||
|          luaC_barrier(L, uv, ra); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SETTABLE: { | ||||
| +      OPCODE_TARGET(SETTABLE) { | ||||
|          Protect(luaV_settable(L, ra, RKB(i), RKC(i))); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_NEWTABLE: { | ||||
| +      OPCODE_TARGET(NEWTABLE) { | ||||
|          int b = GETARG_B(i); | ||||
|          int c = GETARG_C(i); | ||||
|          sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); | ||||
|          Protect(luaC_checkGC(L)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SELF: { | ||||
| +      OPCODE_TARGET(SELF) { | ||||
|          StkId rb = RB(i); | ||||
|          setobjs2s(L, ra+1, rb); | ||||
|          Protect(luaV_gettable(L, rb, RKC(i), ra)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_ADD: { | ||||
| +      OPCODE_TARGET(ADD) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue( luai_numadd, try_addint, luai_vectadd ); | ||||
|          Protect(Arith(L, ra, rb, rc, TM_ADD)); \ | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SUB: { | ||||
| +      OPCODE_TARGET(SUB) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue( luai_numsub, try_subint, luai_vectsub ); | ||||
|          Protect(Arith(L, ra, rb, rc, TM_SUB)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_MUL: { | ||||
| +      OPCODE_TARGET(MUL) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue(luai_nummul, try_mulint, luai_vectmul); | ||||
|          Protect(Arith(L, ra, rb, rc, TM_MUL)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_DIV: { | ||||
| +      OPCODE_TARGET(DIV) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue(luai_numdiv, try_divint, luai_vectdiv); | ||||
|          Protect(Arith(L, ra, rb, rc, TM_DIV)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_MOD: { | ||||
| +      OPCODE_TARGET(MOD) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue_scalar(luai_nummod, try_modint);  /* scalars only */ | ||||
|          Protect(Arith(L, ra, rb, rc, TM_MOD)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_POW: { | ||||
| +      OPCODE_TARGET(POW) { | ||||
|          TValue *rb = RKB(i), *rc= RKC(i); | ||||
|          arith_op_continue(luai_numpow, try_powint, luai_vectpow); | ||||
|          Protect(Arith(L, ra, rb, rc, TM_POW)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_UNM: { | ||||
| +      OPCODE_TARGET(UNM) { | ||||
|          TValue *rb = RB(i); | ||||
|          arith_op1_continue(luai_numunm, try_unmint, luai_vectunm); | ||||
|          Protect(Arith(L, ra, rb, rb, TM_UNM)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_NOT: { | ||||
| +      OPCODE_TARGET(NOT) { | ||||
|          int res = l_isfalse(RB(i));  /* next assignment may change this value */ | ||||
|          setbvalue(ra, res); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LEN: { | ||||
| +      OPCODE_TARGET(LEN) { | ||||
|          const TValue *rb = RB(i); | ||||
|          switch (ttype(rb)) { | ||||
|            case LUA_TTABLE: { | ||||
| @@ -727,18 +783,18 @@ | ||||
|          } | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_CONCAT: { | ||||
| +      OPCODE_TARGET(CONCAT) { | ||||
|          int b = GETARG_B(i); | ||||
|          int c = GETARG_C(i); | ||||
|          Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); | ||||
|          setobjs2s(L, RA(i), base+b); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_JMP: { | ||||
| +      OPCODE_TARGET(JMP) { | ||||
|          dojump(L, pc, GETARG_sBx(i)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_EQ: { | ||||
| +      OPCODE_TARGET(EQ) { | ||||
|          TValue *rb = RKB(i); | ||||
|          TValue *rc = RKC(i); | ||||
|          Protect( | ||||
| @@ -748,7 +804,7 @@ | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LT: { | ||||
| +      OPCODE_TARGET(LT) { | ||||
|          Protect( | ||||
|            if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) | ||||
|              dojump(L, pc, GETARG_sBx(*pc)); | ||||
| @@ -756,7 +812,7 @@ | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_LE: { | ||||
| +      OPCODE_TARGET(LE) { | ||||
|          Protect( | ||||
|            if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) | ||||
|              dojump(L, pc, GETARG_sBx(*pc)); | ||||
| @@ -764,13 +820,13 @@ | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_TEST: { | ||||
| +      OPCODE_TARGET(TEST) { | ||||
|          if (l_isfalse(ra) != GETARG_C(i)) | ||||
|            dojump(L, pc, GETARG_sBx(*pc)); | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_TESTSET: { | ||||
| +      OPCODE_TARGET(TESTSET) { | ||||
|          TValue *rb = RB(i); | ||||
|          if (l_isfalse(rb) != GETARG_C(i)) { | ||||
|            setobjs2s(L, ra, rb); | ||||
| @@ -779,7 +835,7 @@ | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_CALL: { | ||||
| +      OPCODE_TARGET(CALL) { | ||||
|          int b = GETARG_B(i); | ||||
|          int nresults = GETARG_C(i) - 1; | ||||
|          if (b != 0) L->top = ra+b;  /* else previous instruction set top */ | ||||
| @@ -800,7 +856,7 @@ | ||||
|            } | ||||
|          } | ||||
|        } | ||||
| -      case OP_TAILCALL: { | ||||
| +      OPCODE_TARGET(TAILCALL) { | ||||
|          int b = GETARG_B(i); | ||||
|          if (b != 0) L->top = ra+b;  /* else previous instruction set top */ | ||||
|          L->savedpc = pc; | ||||
| @@ -832,7 +888,7 @@ | ||||
|            } | ||||
|          } | ||||
|        } | ||||
| -      case OP_RETURN: { | ||||
| +      OPCODE_TARGET(RETURN) { | ||||
|          int b = GETARG_B(i); | ||||
|          if (b != 0) L->top = ra+b-1; | ||||
|          if (L->openupval) luaF_close(L, base); | ||||
| @@ -847,7 +903,7 @@ | ||||
|            goto reentry; | ||||
|          } | ||||
|        } | ||||
| -      case OP_FORLOOP: { | ||||
| +      OPCODE_TARGET(FORLOOP) { | ||||
|          /* If start,step and limit are all integers, we don't need to check | ||||
|           * against overflow in the looping. | ||||
|           */ | ||||
| @@ -875,7 +931,7 @@ | ||||
|          } | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_FORPREP: { | ||||
| +      OPCODE_TARGET(FORPREP) { | ||||
|          const TValue *init = ra; | ||||
|          const TValue *plimit = ra+1; | ||||
|          const TValue *pstep = ra+2; | ||||
| @@ -898,7 +954,7 @@ | ||||
|          dojump(L, pc, GETARG_sBx(i)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_TFORLOOP: { | ||||
| +      OPCODE_TARGET(TFORLOOP) { | ||||
|          StkId cb = ra + 3;  /* call base */ | ||||
|          setobjs2s(L, cb+2, ra+2); | ||||
|          setobjs2s(L, cb+1, ra+1); | ||||
| @@ -914,7 +970,7 @@ | ||||
|          pc++; | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_SETLIST: { | ||||
| +      OPCODE_TARGET(SETLIST) { | ||||
|          int n = GETARG_B(i); | ||||
|          int c = GETARG_C(i); | ||||
|          int last; | ||||
| @@ -936,11 +992,11 @@ | ||||
|          } | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_CLOSE: { | ||||
| +      OPCODE_TARGET(CLOSE) { | ||||
|          luaF_close(L, ra); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_CLOSURE: { | ||||
| +      OPCODE_TARGET(CLOSURE) { | ||||
|          Proto *p; | ||||
|          Closure *ncl; | ||||
|          int nup, j; | ||||
| @@ -960,7 +1016,7 @@ | ||||
|          Protect(luaC_checkGC(L)); | ||||
|          continue; | ||||
|        } | ||||
| -      case OP_VARARG: { | ||||
| +      OPCODE_TARGET(VARARG) { | ||||
|          int b = GETARG_B(i) - 1; | ||||
|          int j; | ||||
|          CallInfo *ci = L->ci; | ||||
		Reference in New Issue
	
	Block a user
	 Felix Fietkau
					Felix Fietkau