From 4d1f954efb78c760f614034726888d6bd3915d9e Mon Sep 17 00:00:00 2001 From: Laurence Tratt Date: Tue, 24 Mar 2026 15:24:45 +0000 Subject: [PATCH] Promote big constants. This commit promotes "big" constants i.e. those in the constant pool. This is possible thanks to 60c3e599, but still requires some work: in particular, we have to create different codepaths to ensure that whenever we load something out of the constant pool we do so via an idempotent function. Fortunately, by introducing "K" variants of some macros, we can do this in a way that doesn't cause much code corruption. Speeds up cd/json/storage by ~2%. --- src/lvm.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/src/lvm.c b/src/lvm.c index a1b491f..0c9c324 100644 --- a/src/lvm.c +++ b/src/lvm.c @@ -959,7 +959,7 @@ void luaV_finishOp (lua_State *L) { StkId ra = RA(i); \ TValue *v1 = vRB(i); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ - op_arithf_aux(L, v1, v2, fop); } + op_arithfK_aux(L, v1, v2, fop); } /* @@ -973,6 +973,69 @@ void luaV_finishOp (lua_State *L) { } \ else op_arithf_aux(L, v1, v2, fop); } +#ifdef USE_YK +#define NOOPT_VAL(X) asm volatile("" : "+r,m"(X) : : "memory"); + +#define ttisfloatK(o) (load_tag(o) == LUA_VNUMFLT) +#define ttisintegerK(o) (load_tag(o) == LUA_VNUMINT) +#define ivalueK(o) load_int(o) +// FIXME: We currently have to use memcpy to bitcast from uint64_t to lua_Number +#define fltvalueK(o) ({ uint64_t x = load_flt(o); lua_Number y; memcpy(&y, &x, sizeof(lua_Number)); y; }) +#define tointegernsK(o,i) \ + (l_likely(ttisintegerK(o)) ? (*(i) = ivalueK(o), 1) \ + : luaV_tointegerns(o,i,LUA_FLOORN2I)) +#define tonumbernsK(o,n) \ + (ttisfloatK(o) ? ((n) = fltvalueK(o), 1) : \ + (ttisintegerK(o) ? ((n) = cast_num(ivalueK(o)), 1) : 0)) + +# define op_arithK_aux(L,v1,v2,iop,fop) { \ + StkId ra = RA(i); \ + if (ttisinteger(v1) && ttisintegerK(v2)) { \ + lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalueK(v2); \ + pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ + } \ + else op_arithfK_aux(L, v1, v2, fop); } + +# define op_arithfK_aux(L,v1,v2,fop) { \ + lua_Number n1; lua_Number n2; \ + if (tonumberns(v1, n1) && tonumbernsK(v2, n2)) { \ + pc++; setfltvalue(s2v(ra), fop(L, n1, n2)); \ + }} + +// Returns the type tag for `o`. +__attribute__((yk_idempotent)) +lu_byte load_tag(const TValue *o) { + NOOPT_VAL(o); + return o->tt_; +} + +// Returns the `lua_Number` floating point number stored in `o`. The caller is +// responsible for checking that this `TValue` really contains a `lua_Number`. +__attribute__((yk_idempotent)) +uint64_t load_flt(const TValue *o) { + NOOPT_VAL(o); + uint64_t x; + // FIXME: We currently have to use memcpy to bitcast from lua_Number to uint64_t + memcpy(&x, &o->value_.n, sizeof(lua_Number)); + return x; +} + +// Returns the `lua_Integer` integer stored in `o`. The caller is responsible +// for checking that this `TValue` really contains a `lua_Integer`. +__attribute__((yk_idempotent)) +lua_Integer load_int(const TValue *o) { + NOOPT_VAL(o); + return o->value_.i; +} +#else +#define ttisfloatK(o) ttisfloat(o) +#define ttisintegerK(o) ttisinteger(o) +#define ivalueK(o) ivalue(o) +# define op_arithK_aux(L,v1,v2,iop,fop) (op_arith_aux(L,v1,v2,iop,fop)) +# define op_arithfK_aux(L,v1,v2,fop) (op_arithf_aux(L,v1,v2,fop)) +# define tointegernsK(o,i) tointegerns(o,i) +#endif + /* ** Arithmetic operations with register operands. @@ -989,7 +1052,7 @@ void luaV_finishOp (lua_State *L) { #define op_arithK(L,iop,fop) { \ TValue *v1 = vRB(i); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ - op_arith_aux(L, v1, v2, iop, fop); } + op_arithK_aux(L, v1, v2, iop, fop); } /* @@ -1000,8 +1063,8 @@ void luaV_finishOp (lua_State *L) { TValue *v1 = vRB(i); \ TValue *v2 = KC(i); \ lua_Integer i1; \ - lua_Integer i2 = ivalue(v2); \ - if (tointegerns(v1, &i1)) { \ + lua_Integer i2 = ivalueK(v2); \ + if (tointegernsK(v1, &i1)) { \ pc++; setivalue(s2v(ra), op(i1, i2)); \ }} @@ -1175,7 +1238,6 @@ void luaV_finishOp (lua_State *L) { /* fetch an instruction and prepare its execution */ #ifdef USE_YK -#define NOOPT_VAL(X) asm volatile("" : "+r,m"(X) : : "memory"); // Elide instruction lookup. __attribute__((yk_idempotent)) Instruction load_inst(uint64_t pv, const Instruction *pc) {