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

@@ -140,6 +140,7 @@ static IRRef split_call_l(jit_State *J, IRRef1 *hisubst, IRIns *oir,
ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, id);
return split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp);
}
#endif
/* Emit a CALLN with one split 64 bit argument and a 32 bit argument. */
static IRRef split_call_li(jit_State *J, IRRef1 *hisubst, IRIns *oir,
@@ -156,7 +157,6 @@ static IRRef split_call_li(jit_State *J, IRRef1 *hisubst, IRIns *oir,
ir->prev = tmp = split_emit(J, IRTI(IR_CALLN), tmp, id);
return split_emit(J, IRT(IR_HIOP, IRT_SOFTFP), tmp, tmp);
}
#endif
/* Emit a CALLN with two split 64 bit arguments. */
static IRRef split_call_ll(jit_State *J, IRRef1 *hisubst, IRIns *oir,
@@ -196,6 +196,118 @@ static IRRef split_ptr(jit_State *J, IRIns *oir, IRRef ref)
return split_emit(J, IRTI(IR_ADD), nref, lj_ir_kint(J, ofs));
}
#if LJ_HASFFI
static IRRef split_bitshift(jit_State *J, IRRef1 *hisubst,
IRIns *oir, IRIns *nir, IRIns *ir)
{
IROp op = ir->o;
IRRef kref = nir->op2;
if (irref_isk(kref)) { /* Optimize constant shifts. */
int32_t k = (IR(kref)->i & 63);
IRRef lo = nir->op1, hi = hisubst[ir->op1];
if (op == IR_BROL || op == IR_BROR) {
if (op == IR_BROR) k = (-k & 63);
if (k >= 32) { IRRef t = lo; lo = hi; hi = t; k -= 32; }
if (k == 0) {
passthrough:
J->cur.nins--;
ir->prev = lo;
return hi;
} else {
TRef k1, k2;
IRRef t1, t2, t3, t4;
J->cur.nins--;
k1 = lj_ir_kint(J, k);
k2 = lj_ir_kint(J, (-k & 31));
t1 = split_emit(J, IRTI(IR_BSHL), lo, k1);
t2 = split_emit(J, IRTI(IR_BSHL), hi, k1);
t3 = split_emit(J, IRTI(IR_BSHR), lo, k2);
t4 = split_emit(J, IRTI(IR_BSHR), hi, k2);
ir->prev = split_emit(J, IRTI(IR_BOR), t1, t4);
return split_emit(J, IRTI(IR_BOR), t2, t3);
}
} else if (k == 0) {
goto passthrough;
} else if (k < 32) {
if (op == IR_BSHL) {
IRRef t1 = split_emit(J, IRTI(IR_BSHL), hi, kref);
IRRef t2 = split_emit(J, IRTI(IR_BSHR), lo, lj_ir_kint(J, (-k&31)));
return split_emit(J, IRTI(IR_BOR), t1, t2);
} else {
IRRef t1 = ir->prev, t2;
lua_assert(op == IR_BSHR || op == IR_BSAR);
nir->o = IR_BSHR;
t2 = split_emit(J, IRTI(IR_BSHL), hi, lj_ir_kint(J, (-k&31)));
ir->prev = split_emit(J, IRTI(IR_BOR), t1, t2);
return split_emit(J, IRTI(op), hi, kref);
}
} else {
if (op == IR_BSHL) {
if (k == 32)
J->cur.nins--;
else
lo = ir->prev;
ir->prev = lj_ir_kint(J, 0);
return lo;
} else {
lua_assert(op == IR_BSHR || op == IR_BSAR);
if (k == 32) {
J->cur.nins--;
ir->prev = hi;
} else {
nir->op1 = hi;
}
if (op == IR_BSHR)
return lj_ir_kint(J, 0);
else
return split_emit(J, IRTI(IR_BSAR), hi, lj_ir_kint(J, 31));
}
}
}
return split_call_li(J, hisubst, oir, ir,
op - IR_BSHL + IRCALL_lj_carith_shl64);
}
static IRRef split_bitop(jit_State *J, IRRef1 *hisubst,
IRIns *nir, IRIns *ir)
{
IROp op = ir->o;
IRRef hi, kref = nir->op2;
if (irref_isk(kref)) { /* Optimize bit operations with lo constant. */
int32_t k = IR(kref)->i;
if (k == 0 || k == -1) {
if (op == IR_BAND) k = ~k;
if (k == 0) {
J->cur.nins--;
ir->prev = nir->op1;
} else if (op == IR_BXOR) {
nir->o = IR_BNOT;
nir->op2 = 0;
} else {
J->cur.nins--;
ir->prev = kref;
}
}
}
hi = hisubst[ir->op1];
kref = hisubst[ir->op2];
if (irref_isk(kref)) { /* Optimize bit operations with hi constant. */
int32_t k = IR(kref)->i;
if (k == 0 || k == -1) {
if (op == IR_BAND) k = ~k;
if (k == 0) {
return hi;
} else if (op == IR_BXOR) {
return split_emit(J, IRTI(IR_BNOT), hi, 0);
} else {
return kref;
}
}
}
return split_emit(J, IRTI(op), hi, kref);
}
#endif
/* Transform the old IR to the new IR. */
static void split_ir(jit_State *J)
{
@@ -417,6 +529,19 @@ static void split_ir(jit_State *J)
irt_isi64(ir->t) ? IRCALL_lj_carith_powi64 :
IRCALL_lj_carith_powu64);
break;
case IR_BNOT:
hi = split_emit(J, IRTI(IR_BNOT), hiref, 0);
break;
case IR_BSWAP:
ir->prev = split_emit(J, IRTI(IR_BSWAP), hiref, 0);
hi = nref;
break;
case IR_BAND: case IR_BOR: case IR_BXOR:
hi = split_bitop(J, hisubst, nir, ir);
break;
case IR_BSHL: case IR_BSHR: case IR_BSAR: case IR_BROL: case IR_BROR:
hi = split_bitshift(J, hisubst, oir, nir, ir);
break;
case IR_FLOAD:
lua_assert(ir->op2 == IRFL_CDATA_INT64);
hi = split_emit(J, IRTI(IR_FLOAD), nir->op1, IRFL_CDATA_INT64_4);