📄 ljit_x86_inline.dash
字号:
case JIT_IH_TABLE_REMOVE: jit_assert(ii->nargs == 1); | lea TVALUE:eax, BASE[arg] | lea TVALUE:ecx, BASE[res] | call &jit_table_remove, L, TVALUE:eax, TVALUE:ecx if (ii->nresults == -1) { ii->xnresults = -1; | mov TOP, TVALUE:eax } break; case JIT_IH_TABLE_GETN: | mov TABLE:eax, BASE[arg].value | call &luaH_getn, TABLE:eax | mov TMP1, eax | fild dword TMP1 | fstp qword BASE[res].value | settt BASE[res], LUA_TNUMBER break; default: jit_assert(0); break; }}/* ------------------------------------------------------------------------ *//* This typedef must match the libm function signature. *//* Serves as a check against wrong lua_Number or wrong calling conventions. */typedef lua_Number (*mathfunc_11)(lua_Number);/* Partially inlined math functions. *//* CHECK: must match with jit_hints.h and jit.opt_lib. */static const mathfunc_11 jit_mathfuncs_11[JIT_IH_MATH_SIN] = { log, log10, exp, sinh, cosh, tanh, asin, acos, atan};/* FPU control words for ceil and floor (exceptions masked, full precision). */static const unsigned short jit_fpucw[2] = { 0x0b7f, 0x077f };static void jit_inline_math(jit_State *J, jit_InlineInfo *ii){ int arg = ii->func+1; int res = ii->res; int idx = JIT_IH_IDX(ii->hidx); if (idx < JIT_IH_MATH__21) { | isnumber arg; jne L_DEOPTIMIZE | fld qword BASE[arg].value } else { jit_assert(idx < JIT_IH_MATH__LAST); | isnumber2 arg, arg+1; jne L_DEOPTIMIZE } switch (idx) { /* We ignore sin/cos/tan range overflows (2^63 rad) just like -ffast-math. */ case JIT_IH_MATH_SIN: | fsin break; case JIT_IH_MATH_COS: | fcos break; case JIT_IH_MATH_TAN: | fptan; fpop break; case JIT_IH_MATH_CEIL: case JIT_IH_MATH_FLOOR: | fnstcw word TMP1 | fldcw word [(ptrdiff_t)&jit_fpucw[idx-JIT_IH_MATH_CEIL]] | frndint | fldcw word TMP1 break; case JIT_IH_MATH_ABS: | fabs break; case JIT_IH_MATH_SQRT: | fsqrt break; case JIT_IH_MATH_FMOD: | fld qword BASE[arg+1].value | fld qword BASE[arg].value |1: ; fprem; fnstsw ax; sahf; jp <1 | fstp st1 break; case JIT_IH_MATH_ATAN2: |// Inlining is easier than calling atan2(). | fld qword BASE[arg].value | fld qword BASE[arg+1].value | fpatan break; default: |// Partially inlined. Just call the libm function (__cdecl!). | fstp FPARG1 | call &jit_mathfuncs_11[idx] break; } | settt BASE[res], LUA_TNUMBER | fstp qword BASE[res].value}/* ------------------------------------------------------------------------ *//* Try to inline a CALL or TAILCALL instruction. */static int jit_inline_call(jit_State *J, int func, int nargs, int nresults){ const TValue *callable = hint_get(J, TYPE); /* TYPE hint = callable. */ int cltype = ttype(callable); const TValue *oidx; jit_InlineInfo ii; int idx; if (cltype != LUA_TFUNCTION) goto fail; if (J->flags & JIT_F_DEBUG) goto fail; /* DWIM. */ oidx = hint_get(J, INLINE); /* INLINE hint = library/function index. */ if (!ttisnumber(oidx)) goto fail; ii.hidx = (int)nvalue(oidx); idx = JIT_IH_IDX(ii.hidx); if (nresults == -2) { /* Tailcall. */ /* Tailcalls from vararg functions don't work with BASE[-1]. */ if (J->pt->is_vararg) goto fail; /* So forget about this rare case. */ ii.res = -1; /* Careful: 2nd result overlaps 1st stack slot. */ ii.nresults = -1; } else { ii.res = func; ii.nresults = nresults; } ii.func = func; ii.nargs = nargs; ii.xnargs = ii.xnresults = 1; /* Default: 1 arg, 1 result. */ /* Check for the currently supported cases. */ switch (JIT_IH_LIB(ii.hidx)) { case JIT_IHLIB_BASE: switch (idx) { case JIT_IH_BASE_PAIRS: case JIT_IH_BASE_IPAIRS: if (nresults == -2) goto fail; /* Not useful for tailcalls. */ ii.xnresults = 3; goto check; } break;#ifndef COCO_DISABLE case JIT_IHLIB_COROUTINE: switch (idx) { case JIT_IH_COROUTINE_YIELD: /* Only support common cases: no tailcalls, low number of results. */ if (nresults < 0 || nresults > EXTRA_STACK) goto fail; ii.xnargs = ii.xnresults = -1; goto ok; /* Anything else is ok. */ case JIT_IH_COROUTINE_RESUME: /* Only support common cases: no tailcalls, not with 0 args (error). */ if (nresults == -2 || nargs == 0) goto fail; ii.xnargs = ii.xnresults = -1; goto ok; /* Anything else is ok. */ } break;#endif case JIT_IHLIB_STRING: switch (idx) { case JIT_IH_STRING_LEN: goto check; case JIT_IH_STRING_SUB: if (nargs < 2) goto fail; /* No support for open calls, too. */ goto ok; /* 2 or more args are ok. */ case JIT_IH_STRING_CHAR: goto check; /* Only single arg supported. */ } break; case JIT_IHLIB_TABLE: switch (idx) { case JIT_IH_TABLE_INSERT: ii.xnargs = 2; goto check; /* Only push (append) supported. */ case JIT_IH_TABLE_REMOVE: goto check; /* Only pop supported. */ case JIT_IH_TABLE_GETN: goto check; } break; case JIT_IHLIB_MATH: if (idx >= JIT_IH_MATH__LAST) goto fail; if (idx >= JIT_IH_MATH__21) ii.xnargs = 2; goto check; }fail: return cltype; /* Call could not be inlined. Return type of callable. */check: if (nargs != ii.xnargs && nargs != -1) goto fail; /* The optimizer already checks the number of results (avoid setnil). */ok: /* Whew, all checks done. Go for it! */ /* Start with the common leadin for inlined calls. */ jit_deopt_target(J, nargs); |// Caveat: Must save TOP for open ops if jsub uses DEOPTIMIZE_CALLER. | isfunction func | jne L_DEOPTIMIZE // Not a function? Deoptimize. | cmp aword BASE[func].value, &clvalue(callable) | jne L_DEOPTIMIZE // Wrong closure? Deoptimize. if (nargs == -1 && ii.xnargs >= 0) { | lea eax, BASE[func+1+ii.xnargs] | cmp TOP, eax | jne L_DEOPTIMIZE // Wrong #args? Deoptimize. } /* Now inline the function itself. */ switch (JIT_IH_LIB(ii.hidx)) { case JIT_IHLIB_BASE: jit_inline_base(J, &ii); break;#ifndef COCO_DISABLE case JIT_IHLIB_COROUTINE: jit_inline_coroutine(J, &ii); break;#endif case JIT_IHLIB_STRING: jit_inline_string(J, &ii); break; case JIT_IHLIB_TABLE: jit_inline_table(J, &ii); break; case JIT_IHLIB_MATH: jit_inline_math(J, &ii); break; default: jit_assert(0); break; } /* And add the common leadout for inlined calls. */ if (ii.nresults == -1) { if (ii.xnresults >= 0) { | lea TOP, BASE[ii.res+ii.xnresults] } } else if (ii.nargs == -1) { /* Restore L->top only if needed. */ | lea TOP, BASE[J->pt->maxstacksize] | mov L->top, TOP } if (nresults == -2) { /* Results are in place. Add return for tailcalls. */ | add esp, FRAME_OFFSET | sub BASE, #BASE | sub aword L->ci, #CI | ret } return -1; /* Success, call has been inlined. */}/* ------------------------------------------------------------------------ *//* Helper function for inlined iterator code. Paraphrased from luaH_next. *//* TODO: GCC has trouble optimizing this. */static int jit_table_next(lua_State *L, TValue *ra){ Table *t = hvalue(&ra[TFOR_TAB]); int i = ra[TFOR_CTL].value.b; /* Hidden control variable. */ for (; i < t->sizearray; i++) { /* First the array part. */ if (!ttisnil(&t->array[i])) { setnvalue(&ra[TFOR_KEY], cast_num(i+1)); setobj2s(L, &ra[TFOR_VAL], &t->array[i]); ra[TFOR_CTL].value.b = i+1; return 1; } } for (i -= t->sizearray; i < sizenode(t); i++) { /* Then the hash part. */ if (!ttisnil(gval(gnode(t, i)))) { setobj2s(L, &ra[TFOR_KEY], key2tval(gnode(t, i))); setobj2s(L, &ra[TFOR_VAL], gval(gnode(t, i))); ra[TFOR_CTL].value.b = i+1+t->sizearray; return 1; } } return 0; /* End of iteration. */}/* Try to inline a TFORLOOP instruction. */static int jit_inline_tforloop(jit_State *J, int ra, int nresults, int target){ const TValue *oidx = hint_get(J, INLINE); /* INLINE hint = lib/func idx. */ int idx; if (!ttisnumber(oidx)) return 0; /* No hint: don't inline anything. */ idx = (int)nvalue(oidx); if (J->flags & JIT_F_DEBUG) return 0; /* DWIM. */ switch (idx) { case JIT_IH_MKIDX(JIT_IHLIB_BASE, JIT_IH_BASE_PAIRS): |// The type checks can be omitted -- see the iterator constructor. | lea TOP, BASE[ra] | call &jit_table_next, L, TOP | test eax, eax | jnz =>target return 1; /* Success, iterator has been inlined. */ case JIT_IH_MKIDX(JIT_IHLIB_BASE, JIT_IH_BASE_IPAIRS): |// The type checks can be omitted -- see the iterator constructor. | mov eax, BASE[ra+TFOR_CTL].value // Hidden control variable. | inc eax | mov TABLE:edx, BASE[ra+TFOR_TAB].value // Table object. | mov BASE[ra+TFOR_CTL].value, eax | call &luaH_getnum, TABLE:edx, eax | // This is really copyslot BASE[ra+TFOR_VAL], TVALUE:eax[0] plus compare. | mov ecx, TVALUE:eax->tt | test ecx, ecx // Assumes: LUA_TNIL == 0. | jz >9 // nil value stops iteration. | fild dword BASE[ra+TFOR_CTL].value // Set numeric key. | settt BASE[ra+TFOR_KEY], LUA_TNUMBER | fstp qword BASE[ra+TFOR_KEY].value | mov edx, TVALUE:eax->value | mov eax, TVALUE:eax->value.na[1] // Overwrites eax. | mov BASE[ra+TFOR_VAL].tt, ecx // Copy value from table slot. | mov BASE[ra+TFOR_VAL].value, edx | mov BASE[ra+TFOR_VAL].value.na[1], eax | jmp =>target |9: return 1; /* Success, iterator has been inlined. */ } return 0; /* No support for inlining any other iterators. */}/* ------------------------------------------------------------------------ */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -