FFI: Add 64 bit bitwise operations.

This commit is contained in:
Mike Pall
2013-03-13 22:44:01 +01:00
parent 3e8f5ac718
commit a98aede377
12 changed files with 496 additions and 61 deletions

View File

@@ -11,10 +11,12 @@
#include "lj_err.h"
#include "lj_tab.h"
#include "lj_meta.h"
#include "lj_ir.h"
#include "lj_ctype.h"
#include "lj_cconv.h"
#include "lj_cdata.h"
#include "lj_carith.h"
#include "lj_strscan.h"
/* -- C data arithmetic --------------------------------------------------- */
@@ -270,6 +272,80 @@ int lj_carith_op(lua_State *L, MMS mm)
return lj_carith_meta(L, cts, &ca, mm);
}
/* -- 64 bit bit operations helpers --------------------------------------- */
#if LJ_64
#define B64DEF(name) \
static LJ_AINLINE uint64_t lj_carith_##name(uint64_t x, int32_t sh)
#else
/* Not inlined on 32 bit archs, since some of these are quite lengthy. */
#define B64DEF(name) \
uint64_t LJ_NOINLINE lj_carith_##name(uint64_t x, int32_t sh)
#endif
B64DEF(shl64) { return x << (sh&63); }
B64DEF(shr64) { return x >> (sh&63); }
B64DEF(sar64) { return (uint64_t)((int64_t)x >> (sh&63)); }
B64DEF(rol64) { return lj_rol(x, (sh&63)); }
B64DEF(ror64) { return lj_ror(x, (sh&63)); }
#undef B64DEF
uint64_t lj_carith_shift64(uint64_t x, int32_t sh, int op)
{
switch (op) {
case IR_BSHL-IR_BSHL: x = lj_carith_shl64(x, sh); break;
case IR_BSHR-IR_BSHL: x = lj_carith_shr64(x, sh); break;
case IR_BSAR-IR_BSHL: x = lj_carith_sar64(x, sh); break;
case IR_BROL-IR_BSHL: x = lj_carith_rol64(x, sh); break;
case IR_BROR-IR_BSHL: x = lj_carith_ror64(x, sh); break;
default: lua_assert(0); break;
}
return x;
}
/* Equivalent to lj_lib_checkbit(), but handles cdata. */
uint64_t lj_carith_check64(lua_State *L, int narg, CTypeID *id)
{
TValue *o = L->base + narg-1;
if (o >= L->top) {
err:
lj_err_argt(L, narg, LUA_TNUMBER);
} else if (LJ_LIKELY(tvisnumber(o))) {
/* Handled below. */
} else if (tviscdata(o)) {
CTState *cts = ctype_cts(L);
uint8_t *sp = (uint8_t *)cdataptr(cdataV(o));
CTypeID sid = cdataV(o)->ctypeid;
CType *s = ctype_get(cts, sid);
uint64_t x;
if (ctype_isref(s->info)) {
sp = *(void **)sp;
sid = ctype_cid(s->info);
}
s = ctype_raw(cts, sid);
if (ctype_isenum(s->info)) s = ctype_child(cts, s);
if ((s->info & (CTMASK_NUM|CTF_BOOL|CTF_FP|CTF_UNSIGNED)) ==
CTINFO(CT_NUM, CTF_UNSIGNED) && s->size == 8)
*id = CTID_UINT64; /* Use uint64_t, since it has the highest rank. */
else if (!*id)
*id = CTID_INT64; /* Use int64_t, unless already set. */
lj_cconv_ct_ct(cts, ctype_get(cts, *id), s,
(uint8_t *)&x, sp, CCF_ARG(narg));
return x;
} else if (!(tvisstr(o) && lj_strscan_number(strV(o), o))) {
goto err;
}
if (LJ_LIKELY(tvisint(o))) {
return intV(o);
} else {
int32_t i = lj_num2bit(numV(o));
if (LJ_DUALNUM) setintV(o, i);
return i;
}
}
/* -- 64 bit integer arithmetic helpers ----------------------------------- */
#if LJ_32 && LJ_HASJIT