diff --git a/src/lj_carith.c b/src/lj_carith.c index a7d92983..46f07be7 100644 --- a/src/lj_carith.c +++ b/src/lj_carith.c @@ -184,7 +184,12 @@ static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) else *up = u0 % u1; break; - case MM_pow: *up = lj_carith_powi64(u0, u1, (id == CTID_UINT64)); break; + case MM_pow: + if (id == CTID_INT64) + *up = (uint64_t)lj_carith_powi64((int64_t)u0, (int64_t)u1); + else + *up = lj_carith_powu64(u0, u1); + break; case MM_unm: *up = (uint64_t)-(int64_t)u0; break; default: lua_assert(0); break; } @@ -225,24 +230,12 @@ int lj_carith_op(lua_State *L, MMS mm) /* -- 64 bit integer arithmetic helpers ----------------------------------- */ -/* 64 bit integer x^k. */ -uint64_t lj_carith_powi64(uint64_t x, uint64_t k, int isunsigned) +/* Unsigned 64 bit x^k. */ +uint64_t lj_carith_powu64(uint64_t x, uint64_t k) { - uint64_t y = 0; + uint64_t y; if (k == 0) return 1; - if (!isunsigned) { - if ((int64_t)k < 0) { - if (x == 0) - return U64x(7fffffff,ffffffff); - else if (x == 1) - return 1; - else if ((int64_t)x == -1) - return (k & 1) ? -1 : 1; - else - return 0; - } - } for (; (k & 1) == 0; k >>= 1) x *= x; y = x; if ((k >>= 1) != 0) { @@ -257,4 +250,22 @@ uint64_t lj_carith_powi64(uint64_t x, uint64_t k, int isunsigned) return y; } +/* Signed 64 bit x^k. */ +int64_t lj_carith_powi64(int64_t x, int64_t k) +{ + if (k == 0) + return 1; + if (k < 0) { + if (x == 0) + return U64x(7fffffff,ffffffff); + else if (x == 1) + return 1; + else if (x == -1) + return (k & 1) ? -1 : 1; + else + return 0; + } + return (int64_t)lj_carith_powu64((uint64_t)x, (uint64_t)k); +} + #endif diff --git a/src/lj_carith.h b/src/lj_carith.h index acb095db..6870172b 100644 --- a/src/lj_carith.h +++ b/src/lj_carith.h @@ -12,7 +12,8 @@ LJ_FUNC int lj_carith_op(lua_State *L, MMS mm); -LJ_FUNC uint64_t lj_carith_powi64(uint64_t x, uint64_t k, int isunsigned); +LJ_FUNC uint64_t lj_carith_powu64(uint64_t x, uint64_t k); +LJ_FUNC int64_t lj_carith_powi64(int64_t x, int64_t k); #endif diff --git a/src/lj_crecord.c b/src/lj_crecord.c index 647c464a..86e95679 100644 --- a/src/lj_crecord.c +++ b/src/lj_crecord.c @@ -689,8 +689,8 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) J->postproc = LJ_POST_FIXGUARD; return TREF_TRUE; } else if (mm == MM_pow) { - tr = lj_ir_call(J, IRCALL_lj_carith_powi64, sp[0], sp[1], - lj_ir_kint(J, (int)dt-(int)IRT_I64)); + tr = lj_ir_call(J, dt == IRT_I64 ? IRCALL_lj_carith_powi64 : + IRCALL_lj_carith_powu64, sp[0], sp[1]); } else { if (mm == MM_div || mm == MM_mod) return 0; /* NYI: integer div, mod. */ diff --git a/src/lj_ir.h b/src/lj_ir.h index 6dee36c6..1cb3566e 100644 --- a/src/lj_ir.h +++ b/src/lj_ir.h @@ -251,11 +251,13 @@ typedef struct CCallInfo { #define CCI_CASTU64 0x0200 /* Cast u64 result to number. */ #define CCI_NOFPRCLOBBER 0x0400 /* Does not clobber any FPRs. */ #define CCI_FASTCALL 0x0800 /* Fastcall convention. */ +#define CCI_STACK64 0x1000 /* Needs 64 bits per argument. */ /* Function definitions for CALL* instructions. */ #if LJ_HASFFI #define IRCALLDEF_FFI(_) \ - _(lj_carith_powi64, 3, N, U64, CCI_NOFPRCLOBBER) + _(lj_carith_powi64, 2, N, I64, CCI_STACK64|CCI_NOFPRCLOBBER) \ + _(lj_carith_powu64, 2, N, U64, CCI_STACK64|CCI_NOFPRCLOBBER) #else #define IRCALLDEF_FFI(_) #endif