JIT-compile bitfield stores

This commit implements compilation of bitfield stores.  The
generated IR is not good – in fact, it’s downright terrible – but
it is certainly a big improvement over these operations being
banished to the interpreter.
This commit is contained in:
Demi Obenour 2017-04-01 12:04:13 -04:00
parent bc01981736
commit bbec2d4760

View File

@ -401,8 +401,20 @@ static int crec_isnonzero(CType *s, void *p)
} }
} }
static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp, /* Load a C type from a bitfield ------------------------------------------ */
void *svisnz) static TRef crec_bitfield_load(jit_State *J, CTypeID sid, TRef tr) {
uint32_t pos = ctype_bitpos(sid);
uint32_t bsz = ctype_bitbsz(sid);
CTSize shift = 32 - bsz;
lua_assert(ctype_isbitfield(sid));
lua_assert(bsz > 0 && "Zero sized bitfield is invalid");
tr = emitir(IRT(IR_BSHL, IRT_INT), tr, lj_ir_kint(J, shift - pos));
return emitir(IRT(IR_BSHR, IRT_INT), tr, lj_ir_kint(J, shift));
/* if crosses container boundary: interpreter will throw */
}
static TRef crec_ct_ct(jit_State *J, CType *d, CTypeID bitfield_val,
CType *s, TRef dp, TRef sp, void *svisnz)
{ {
IRType dt = crec_ct2irt(ctype_ctsG(J2G(J)), d); IRType dt = crec_ct2irt(ctype_ctsG(J2G(J)), d);
IRType st = crec_ct2irt(ctype_ctsG(J2G(J)), s); IRType st = crec_ct2irt(ctype_ctsG(J2G(J)), s);
@ -449,6 +461,23 @@ static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp,
else if (st == IRT_INT) else if (st == IRT_INT)
sp = lj_opt_narrow_toint(J, sp); sp = lj_opt_narrow_toint(J, sp);
xstore: xstore:
if (bitfield_val) {
CTSize bsz, pos;
TRef target;
CTSize shift;
TRef k, loaded;
lua_assert(ctype_isbitfield(bitfield_val));
bsz = ctype_bitbsz(bitfield_val);
pos = ctype_bitpos(bitfield_val);
k = lj_ir_kint(J, 8*pos);
target = emitir(IRT(IR_XLOAD, IRT_INT), dp, k);
shift = ~(((uint32_t)-1 >> (32 - bsz)) << pos);
lua_assert(bsz && "Zero sized bitfield is invalid!");
loaded = emitir(IRT(IR_BAND, IRT_INT), target, lj_ir_kint(J, shift));
sp = emitir(IRT(IR_BSHL, IRT_INT), sp, lj_ir_kint(J, pos));
sp = emitir(IRT(IR_BAND, IRT_INT), sp, lj_ir_kint(J, ~shift));
sp = emitir(IRT(IR_BOR, IRT_INT), sp, loaded);
}
if (dt == IRT_I64 || dt == IRT_U64) lj_needsplit(J); if (dt == IRT_I64 || dt == IRT_U64) lj_needsplit(J);
if (dp == 0) return sp; if (dp == 0) return sp;
emitir(IRT(IR_XSTORE, dt), dp, sp); emitir(IRT(IR_XSTORE, dt), dp, sp);
@ -558,22 +587,6 @@ static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp,
return 0; return 0;
} }
/* Load a C type from a bitfield ------------------------------------------ */
static TRef crec_bitfield_load(jit_State *J, CTypeID sid, TRef tr) {
uint32_t pos = ctype_bitpos(sid);
uint32_t bsz = ctype_bitbsz(sid);
lua_assert(ctype_isbitfield(sid));
lua_assert(bsz > 0 && "Zero sized bitfield is invalid");
if (!(sid & CTF_BOOL)) {
CTSize shift = 32 - bsz;
tr = emitir(IRT(IR_BSHL, IRT_INT), tr, lj_ir_kint(J, shift - pos));
return emitir(IRT(IR_BSHR, IRT_INT), tr, lj_ir_kint(J, shift));
/* if crosses container boundary: interpreter will throw */
} else {
lj_trace_err(J, LJ_TRERR_NYICONV);
}
}
/* -- Convert C type to TValue (load) ------------------------------------- */ /* -- Convert C type to TValue (load) ------------------------------------- */
static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp) static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp)
@ -633,8 +646,8 @@ boolfield:
} }
/* -- Convert TValue to C type (store) ------------------------------------ */ /* -- Convert TValue to C type (store) ------------------------------------ */
static TRef crec_ct_tv_(jit_State *J, CType *d, CTypeID bitfield_val, TRef dp,
static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) TRef sp, cTValue *sval)
{ {
CTState *cts = ctype_ctsG(J2G(J)); CTState *cts = ctype_ctsG(J2G(J));
CTypeID sid = CTID_P_VOID; CTypeID sid = CTID_P_VOID;
@ -725,7 +738,11 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
s = ctype_get(cts, sid); s = ctype_get(cts, sid);
doconv: doconv:
if (ctype_isenum(d->info)) d = ctype_child(cts, d); if (ctype_isenum(d->info)) d = ctype_child(cts, d);
return crec_ct_ct(J, d, s, dp, sp, svisnz); return crec_ct_ct(J, d, bitfield_val, s, dp, sp, svisnz);
}
static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval) {
return crec_ct_tv_(J, d, 0, dp, sp, sval);
} }
/* -- C data metamethods -------------------------------------------------- */ /* -- C data metamethods -------------------------------------------------- */
@ -876,8 +893,6 @@ again:
J->base[0] = lj_ir_kint(J, (int32_t)fct->size); J->base[0] = lj_ir_kint(J, (int32_t)fct->size);
return; /* Interpreter will throw for newindex. */ return; /* Interpreter will throw for newindex. */
} else if (ctype_isbitfield(fct->info)) { } else if (ctype_isbitfield(fct->info)) {
if (rd->data != 0)
lj_trace_err(J, LJ_TRERR_NYICONV);
isbitfield = 1; isbitfield = 1;
bitfield_val = fct->info; bitfield_val = fct->info;
sid = ctype_underlying_type(bitfield_val); sid = ctype_underlying_type(bitfield_val);
@ -930,7 +945,7 @@ again:
} else { /* __newindex metamethod. */ } else { /* __newindex metamethod. */
rd->nres = 0; rd->nres = 0;
J->needsnap = 1; J->needsnap = 1;
crec_ct_tv(J, ct, ptr, J->base[2], &rd->argv[2]); crec_ct_tv_(J, ct, bitfield_val, ptr, J->base[2], &rd->argv[2]);
} }
} }