FFI: Box all accessed or returned enums.

This commit is contained in:
Mike Pall 2012-07-17 22:20:03 +02:00
parent 2139c6791f
commit 4d9c29a78c
11 changed files with 121 additions and 60 deletions

View File

@ -250,19 +250,20 @@ constant values; retrieving return values from C calls:
<tr class="even separate"> <tr class="even separate">
<td class="convin"><tt>bool</tt></td><td class="convop">0 &rarr; <tt>false</tt>, otherwise <tt>true</tt></td><td class="convout">boolean</td></tr> <td class="convin"><tt>bool</tt></td><td class="convop">0 &rarr; <tt>false</tt>, otherwise <tt>true</tt></td><td class="convout">boolean</td></tr>
<tr class="odd separate"> <tr class="odd separate">
<td class="convin">Complex number</td><td class="convop">boxed value</td><td class="convout">complex cdata</td></tr> <td class="convin"><tt>enum</tt></td><td class="convop">boxed value</td><td class="convout">enum cdata</td></tr>
<tr class="even"> <tr class="even">
<td class="convin">Complex number</td><td class="convop">boxed value</td><td class="convout">complex cdata</td></tr>
<tr class="odd">
<td class="convin">Vector</td><td class="convop">boxed value</td><td class="convout">vector cdata</td></tr> <td class="convin">Vector</td><td class="convop">boxed value</td><td class="convout">vector cdata</td></tr>
<tr class="odd"> <tr class="even">
<td class="convin">Pointer</td><td class="convop">boxed value</td><td class="convout">pointer cdata</td></tr> <td class="convin">Pointer</td><td class="convop">boxed value</td><td class="convout">pointer cdata</td></tr>
<tr class="even separate"> <tr class="odd separate">
<td class="convin">Array</td><td class="convop">boxed reference</td><td class="convout">reference cdata</td></tr> <td class="convin">Array</td><td class="convop">boxed reference</td><td class="convout">reference cdata</td></tr>
<tr class="odd"> <tr class="even">
<td class="convin"><tt>struct</tt>/<tt>union</tt></td><td class="convop">boxed reference</td><td class="convout">reference cdata</td></tr> <td class="convin"><tt>struct</tt>/<tt>union</tt></td><td class="convop">boxed reference</td><td class="convout">reference cdata</td></tr>
</table> </table>
<p> <p>
Bitfields or <tt>enum</tt> types are treated like their underlying Bitfields are treated like their underlying type.
type.
</p> </p>
<p> <p>
Reference types are dereferenced <em>before</em> a conversion can take Reference types are dereferenced <em>before</em> a conversion can take
@ -715,6 +716,10 @@ is performed. Otherwise both sides are converted to an
<tt>int64_t</tt> and a signed arithmetic operation is performed. The <tt>int64_t</tt> and a signed arithmetic operation is performed. The
result is a boxed 64&nbsp;bit cdata object.<br> result is a boxed 64&nbsp;bit cdata object.<br>
If one of the operands is an <tt>enum</tt> and the other operand is a
string, the string is converted to the value of a matching <tt>enum</tt>
constant before the above conversion.<br>
These rules ensure that 64&nbsp;bit integers are "sticky". Any These rules ensure that 64&nbsp;bit integers are "sticky". Any
expression involving at least one 64&nbsp;bit integer operand results expression involving at least one 64&nbsp;bit integer operand results
in another one. The undefined cases for the division, modulo and power in another one. The undefined cases for the division, modulo and power
@ -740,7 +745,11 @@ cdata number and a Lua number can be compared with each other. If one
of them is an <tt>uint64_t</tt>, the other side is converted to an of them is an <tt>uint64_t</tt>, the other side is converted to an
<tt>uint64_t</tt> and an unsigned comparison is performed. Otherwise <tt>uint64_t</tt> and an unsigned comparison is performed. Otherwise
both sides are converted to an <tt>int64_t</tt> and a signed both sides are converted to an <tt>int64_t</tt> and a signed
comparison is performed.</li> comparison is performed.<br>
If one of the operands is an <tt>enum</tt> and the other operand is a
string, the string is converted to the value of a matching <tt>enum</tt>
constant before the above conversion.<br>
<li><b>Comparisons for equality/inequality</b> never raise an error. <li><b>Comparisons for equality/inequality</b> never raise an error.
Even incompatible pointers can be compared for equality by address. Any Even incompatible pointers can be compared for equality by address. Any

View File

@ -297,6 +297,9 @@ LJLIB_CF(ffi_meta___tostring)
goto checkgc; goto checkgc;
} else if (ctype_isfunc(ct->info)) { } else if (ctype_isfunc(ct->info)) {
p = *(void **)p; p = *(void **)p;
} else if (ctype_isenum(ct->info)) {
msg = "cdata<%s>: %d";
p = (void *)(uintptr_t)*(uint32_t **)p;
} else { } else {
if (ctype_isptr(ct->info)) { if (ctype_isptr(ct->info)) {
p = cdata_getptr(p, ct->size); p = cdata_getptr(p, ct->size);
@ -348,7 +351,6 @@ LJLIB_CF(ffi_clib___index) LJLIB_REC(clib_index 1)
CTypeID sid = ctype_cid(s->info); CTypeID sid = ctype_cid(s->info);
void *sp = *(void **)cdataptr(cd); void *sp = *(void **)cdataptr(cd);
CType *ct = ctype_raw(cts, sid); CType *ct = ctype_raw(cts, sid);
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp)) if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
lj_gc_check(L); lj_gc_check(L);
return 1; return 1;

View File

@ -1287,7 +1287,7 @@ static void asm_intcomp(ASMState *as, IRIns *ir)
Reg left; Reg left;
uint32_t m; uint32_t m;
int cmpprev0 = 0; int cmpprev0 = 0;
lua_assert(irt_isint(ir->t) || irt_isaddr(ir->t)); lua_assert(irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t));
if (asm_swapops(as, lref, rref)) { if (asm_swapops(as, lref, rref)) {
Reg tmp = lref; lref = rref; rref = tmp; Reg tmp = lref; lref = rref; rref = tmp;
if (cc >= CC_GE) cc ^= 7; /* LT <-> GT, LE <-> GE */ if (cc >= CC_GE) cc ^= 7; /* LT <-> GT, LE <-> GE */

View File

@ -337,7 +337,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
} }
} else if (ir->o == IR_FLOAD) { } else if (ir->o == IR_FLOAD) {
/* Generic fusion is only ok for 32 bit operand (but see asm_comp). */ /* Generic fusion is only ok for 32 bit operand (but see asm_comp). */
if ((irt_isint(ir->t) || irt_isaddr(ir->t)) && if ((irt_isint(ir->t) || irt_isu32(ir->t) || irt_isaddr(ir->t)) &&
noconflict(as, ref, IR_FSTORE, 0)) { noconflict(as, ref, IR_FSTORE, 0)) {
asm_fusefref(as, ir, xallow); asm_fusefref(as, ir, xallow);
return RID_MRM; return RID_MRM;
@ -2064,7 +2064,8 @@ static void asm_comp(ASMState *as, IRIns *ir, uint32_t cc)
IROp leftop = (IROp)(IR(lref)->o); IROp leftop = (IROp)(IR(lref)->o);
Reg r64 = REX_64IR(ir, 0); Reg r64 = REX_64IR(ir, 0);
int32_t imm = 0; int32_t imm = 0;
lua_assert(irt_is64(ir->t) || irt_isint(ir->t) || irt_isaddr(ir->t)); lua_assert(irt_is64(ir->t) || irt_isint(ir->t) ||
irt_isu32(ir->t) || irt_isaddr(ir->t));
/* Swap constants (only for ABC) and fusable loads to the right. */ /* Swap constants (only for ABC) and fusable loads to the right. */
if (irref_isk(lref) || (!irref_isk(rref) && opisfusableload(leftop))) { if (irref_isk(lref) || (!irref_isk(rref) && opisfusableload(leftop))) {
if ((cc & 0xc) == 0xc) cc ^= 0x53; /* L <-> G, LE <-> GE */ if ((cc & 0xc) == 0xc) cc ^= 0x53; /* L <-> G, LE <-> GE */

View File

@ -46,6 +46,7 @@ static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
ct = ctype_get(cts, ct = ctype_get(cts,
lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR));
} }
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
ca->ct[i] = ct; ca->ct[i] = ct;
ca->p[i] = p; ca->p[i] = p;
} else if (tvisint(o)) { } else if (tvisint(o)) {
@ -57,6 +58,25 @@ static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
} else if (tvisnil(o)) { } else if (tvisnil(o)) {
ca->ct[i] = ctype_get(cts, CTID_P_VOID); ca->ct[i] = ctype_get(cts, CTID_P_VOID);
ca->p[i] = (uint8_t *)0; ca->p[i] = (uint8_t *)0;
} else if (tvisstr(o)) {
TValue *o2 = i == 0 ? o+1 : o-1;
CType *ct = ctype_raw(cts, cdataV(o2)->ctypeid);
ca->ct[i] = NULL;
ca->p[i] = NULL;
ok = 0;
if (ctype_isenum(ct->info)) {
CTSize ofs;
CType *cct = lj_ctype_getfield(cts, ct, strV(o), &ofs);
if (cct && ctype_isconstval(cct->info)) {
ca->ct[i] = ctype_child(cts, cct);
ca->p[i] = (uint8_t *)&cct->size; /* Assumes ct does not grow. */
ok = 1;
} else {
ca->ct[1-i] = ct; /* Use enum to improve error message. */
ca->p[1-i] = NULL;
break;
}
}
} else { } else {
ca->ct[i] = NULL; ca->ct[i] = NULL;
ca->p[i] = NULL; ca->p[i] = NULL;
@ -204,17 +224,22 @@ static int lj_carith_meta(lua_State *L, CTState *cts, CDArith *ca, MMS mm)
tv = lj_ctype_meta(cts, cdataV(L->base+1)->ctypeid, mm); tv = lj_ctype_meta(cts, cdataV(L->base+1)->ctypeid, mm);
if (!tv) { if (!tv) {
const char *repr[2]; const char *repr[2];
int i; int i, isenum = -1, isstr = -1;
if (mm == MM_eq) { /* Equality checks never raise an error. */ if (mm == MM_eq) { /* Equality checks never raise an error. */
setboolV(L->top-1, 0); setboolV(L->top-1, 0);
return 1; return 1;
} }
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
if (ca->ct[i]) if (ca->ct[i]) {
if (ctype_isenum(ca->ct[i]->info)) isenum = i;
repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL)); repr[i] = strdata(lj_ctype_repr(L, ctype_typeid(cts, ca->ct[i]), NULL));
else } else {
if (tvisstr(&L->base[i])) isstr = i;
repr[i] = lj_typename(&L->base[i]); repr[i] = lj_typename(&L->base[i]);
}
} }
if ((isenum ^ isstr) == 1)
lj_err_callerv(L, LJ_ERR_FFI_BADCONV, repr[isstr], repr[isenum]);
lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN : lj_err_callerv(L, mm == MM_len ? LJ_ERR_FFI_BADLEN :
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT : mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH, mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,

View File

@ -684,7 +684,6 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
#endif #endif
/* No reference types end up here, so there's no need for the CTypeID. */ /* No reference types end up here, so there's no need for the CTypeID. */
lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info))); lua_assert(!(ctype_isrefarray(ctr->info) || ctype_isstruct(ctr->info)));
if (ctype_isenum(ctr->info)) ctr = ctype_child(cts, ctr);
return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp); return lj_cconv_tv_ct(cts, ctr, 0, L->top-1, sp);
} }

View File

@ -426,7 +426,6 @@ static void callback_conv_args(CTState *cts, lua_State *L)
MSize n; MSize n;
lua_assert(ctype_isfield(ctf->info)); lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf); cta = ctype_rawchild(cts, ctf);
if (ctype_isenum(cta->info)) cta = ctype_child(cts, cta);
isfp = ctype_isfp(cta->info); isfp = ctype_isfp(cta->info);
sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1); sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */ n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */

View File

@ -374,7 +374,6 @@ int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp) TValue *o, uint8_t *sp)
{ {
CTInfo sinfo = s->info; CTInfo sinfo = s->info;
lua_assert(!ctype_isenum(sinfo));
if (ctype_isnum(sinfo)) { if (ctype_isnum(sinfo)) {
if (!ctype_isbool(sinfo)) { if (!ctype_isbool(sinfo)) {
if (ctype_isinteger(sinfo) && s->size > 4) goto copyval; if (ctype_isinteger(sinfo) && s->size > 4) goto copyval;

View File

@ -231,8 +231,8 @@ int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
s = ctype_get(cts, sid); s = ctype_get(cts, sid);
} }
/* Skip attributes and enums. */ /* Skip attributes. */
while (ctype_isattrib(s->info) || ctype_isenum(s->info)) while (ctype_isattrib(s->info))
s = ctype_child(cts, s); s = ctype_child(cts, s);
return lj_cconv_tv_ct(cts, s, sid, o, sp); return lj_cconv_tv_ct(cts, s, sid, o, sp);

View File

@ -111,8 +111,9 @@ static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o)
*/ */
/* Convert CType to IRType. */ /* Convert CType to IRType. */
static IRType crec_ct2irt(CType *ct) static IRType crec_ct2irt(CTState *cts, CType *ct)
{ {
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (LJ_LIKELY(ctype_isnum(ct->info))) { if (LJ_LIKELY(ctype_isnum(ct->info))) {
if ((ct->info & CTF_FP)) { if ((ct->info & CTF_FP)) {
if (ct->size == sizeof(double)) if (ct->size == sizeof(double))
@ -162,10 +163,10 @@ static int crec_isnonzero(CType *s, void *p)
static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp, static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp,
void *svisnz) void *svisnz)
{ {
IRType dt = crec_ct2irt(ctype_ctsG(J2G(J)), d);
IRType st = crec_ct2irt(ctype_ctsG(J2G(J)), s);
CTSize dsize = d->size, ssize = s->size; CTSize dsize = d->size, ssize = s->size;
CTInfo dinfo = d->info, sinfo = s->info; CTInfo dinfo = d->info, sinfo = s->info;
IRType dt = crec_ct2irt(d);
IRType st = crec_ct2irt(s);
if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT)
goto err_conv; goto err_conv;
@ -317,10 +318,9 @@ static TRef crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp,
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)
{ {
CTState *cts = ctype_ctsG(J2G(J)); CTState *cts = ctype_ctsG(J2G(J));
IRType t = crec_ct2irt(cts, s);
CTInfo sinfo = s->info; CTInfo sinfo = s->info;
lua_assert(!ctype_isenum(sinfo));
if (ctype_isnum(sinfo)) { if (ctype_isnum(sinfo)) {
IRType t = crec_ct2irt(s);
TRef tr; TRef tr;
if (t == IRT_CDATA) if (t == IRT_CDATA)
goto err_nyi; /* NYI: copyval of >64 bit integers. */ goto err_nyi; /* NYI: copyval of >64 bit integers. */
@ -338,14 +338,12 @@ static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp)
} else { } else {
return tr; return tr;
} }
} else if (ctype_isptr(sinfo)) { } else if (ctype_isptr(sinfo) || ctype_isenum(sinfo)) {
IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32; sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Box pointers and enums. */
sp = emitir(IRT(IR_XLOAD, t), sp, 0);
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) { } else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
cts->L = J->L; cts->L = J->L;
sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */ sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */
} else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */ } else if (ctype_iscomplex(sinfo)) { /* Unbox/box complex. */
IRType t = s->size == 2*sizeof(double) ? IRT_NUM : IRT_FLOAT;
ptrdiff_t esz = (ptrdiff_t)(s->size >> 1); ptrdiff_t esz = (ptrdiff_t)(s->size >> 1);
TRef ptr, tr1, tr2, dp; TRef ptr, tr1, tr2, dp;
dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL); dp = emitir(IRTG(IR_CNEW, IRT_CDATA), lj_ir_kint(J, sid), TREF_NIL);
@ -362,7 +360,7 @@ static TRef crec_tv_ct(jit_State *J, CType *s, CTypeID sid, TRef sp)
err_nyi: err_nyi:
lj_trace_err(J, LJ_TRERR_NYICONV); lj_trace_err(J, LJ_TRERR_NYICONV);
} }
/* Box pointer, ref or 64 bit integer. */ /* Box pointer, ref, enum or 64 bit integer. */
return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, sid), sp); return emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, sid), sp);
} }
@ -403,8 +401,8 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
emitir(IRTG(IR_EQ, IRT_STR), sp, lj_ir_kstr(J, str)); emitir(IRTG(IR_EQ, IRT_STR), sp, lj_ir_kstr(J, str));
if (cct && ctype_isconstval(cct->info)) { if (cct && ctype_isconstval(cct->info)) {
lua_assert(ctype_child(cts, cct)->size == 4); lua_assert(ctype_child(cts, cct)->size == 4);
svisnz = (void *)(intptr_t)(cct->size != 0); svisnz = (void *)(intptr_t)(ofs != 0);
sp = lj_ir_kint(J, (int32_t)cct->size); sp = lj_ir_kint(J, (int32_t)ofs);
sid = ctype_cid(cct->info); sid = ctype_cid(cct->info);
} /* else: interpreter will throw. */ } /* else: interpreter will throw. */
} else if (ctype_isrefarray(d->info)) { /* Copy string to array. */ } else if (ctype_isrefarray(d->info)) { /* Copy string to array. */
@ -418,15 +416,13 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
sid = argv2cdata(J, sp, sval)->ctypeid; sid = argv2cdata(J, sp, sval)->ctypeid;
s = ctype_raw(cts, sid); s = ctype_raw(cts, sid);
svisnz = cdataptr(cdataV(sval)); svisnz = cdataptr(cdataV(sval));
if (ctype_isenum(s->info)) s = ctype_child(cts, s); t = crec_ct2irt(cts, s);
t = crec_ct2irt(s);
if (ctype_isptr(s->info)) { if (ctype_isptr(s->info)) {
sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_PTR); sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_PTR);
if (ctype_isref(s->info)) { if (ctype_isref(s->info)) {
svisnz = *(void **)svisnz; svisnz = *(void **)svisnz;
s = ctype_rawchild(cts, s); s = ctype_rawchild(cts, s);
if (ctype_isenum(s->info)) s = ctype_child(cts, s); t = crec_ct2irt(cts, s);
t = crec_ct2irt(s);
} else { } else {
goto doconv; goto doconv;
} }
@ -554,10 +550,8 @@ again:
} else if (tref_iscdata(idx)) { } else if (tref_iscdata(idx)) {
GCcdata *cdk = cdataV(&rd->argv[1]); GCcdata *cdk = cdataV(&rd->argv[1]);
CType *ctk = ctype_raw(cts, cdk->ctypeid); CType *ctk = ctype_raw(cts, cdk->ctypeid);
IRType t; IRType t = crec_ct2irt(cts, ctk);
if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk); if (ctype_ispointer(ct->info) && t >= IRT_I8 && t <= IRT_U64) {
if (ctype_ispointer(ct->info) &&
ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) {
if (ctk->size == 8) { if (ctk->size == 8) {
idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64); idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64);
} else if (ctk->size == 4) { } else if (ctk->size == 4) {
@ -637,7 +631,6 @@ again:
ct = ctype_child(cts, ct); /* Skip attributes. */ ct = ctype_child(cts, ct); /* Skip attributes. */
if (rd->data == 0) { /* __index metamethod. */ if (rd->data == 0) { /* __index metamethod. */
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); /* Skip enums. */
J->base[0] = crec_tv_ct(J, ct, sid, ptr); J->base[0] = crec_tv_ct(J, ct, sid, ptr);
} else { /* __newindex metamethod. */ } else { /* __newindex metamethod. */
rd->nres = 0; rd->nres = 0;
@ -888,7 +881,7 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
if (ctype_isfunc(ct->info)) { if (ctype_isfunc(ct->info)) {
TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR); TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR);
CType *ctr = ctype_rawchild(cts, ct); CType *ctr = ctype_rawchild(cts, ct);
IRType t = crec_ct2irt(ctr); IRType t = crec_ct2irt(cts, ctr);
TRef tr; TRef tr;
TValue tv; TValue tv;
/* Check for blacklisted C functions that might call a callback. */ /* Check for blacklisted C functions that might call a callback. */
@ -899,12 +892,10 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
if (ctype_isvoid(ctr->info)) { if (ctype_isvoid(ctr->info)) {
t = IRT_NIL; t = IRT_NIL;
rd->nres = 0; rd->nres = 0;
} else if (ctype_isenum(ctr->info)) { } else if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) ||
ctr = ctype_child(cts, ctr); ctype_isenum(ctr->info)) || t == IRT_CDATA) {
}
if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) ||
ctype_isvoid(ctr->info)) || t == IRT_CDATA)
lj_trace_err(J, LJ_TRERR_NYICALL); lj_trace_err(J, LJ_TRERR_NYICALL);
}
if ((ct->info & CTF_VARARG) if ((ct->info & CTF_VARARG)
#if LJ_TARGET_X86 #if LJ_TARGET_X86
|| ctype_cconv(ct->info) != CTCC_CDECL || ctype_cconv(ct->info) != CTCC_CDECL
@ -923,17 +914,17 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
J->postproc = LJ_POST_FIXGUARDSNAP; J->postproc = LJ_POST_FIXGUARDSNAP;
tr = TREF_TRUE; tr = TREF_TRUE;
} }
} else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) ||
t == IRT_I64 || t == IRT_U64 || ctype_isenum(ctr->info)) {
TRef trid = lj_ir_kint(J, ctype_cid(ct->info));
tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr);
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
} else if (t == IRT_FLOAT || t == IRT_U32) { } else if (t == IRT_FLOAT || t == IRT_U32) {
tr = emitconv(tr, IRT_NUM, t, 0); tr = emitconv(tr, IRT_NUM, t, 0);
} else if (t == IRT_I8 || t == IRT_I16) { } else if (t == IRT_I8 || t == IRT_I16) {
tr = emitconv(tr, IRT_INT, t, IRCONV_SEXT); tr = emitconv(tr, IRT_INT, t, IRCONV_SEXT);
} else if (t == IRT_U8 || t == IRT_U16) { } else if (t == IRT_U8 || t == IRT_U16) {
tr = emitconv(tr, IRT_INT, t, 0); tr = emitconv(tr, IRT_INT, t, 0);
} else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) ||
(t == IRT_I64 || t == IRT_U64)) {
TRef trid = lj_ir_kint(J, ctype_cid(ct->info));
tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr);
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
} }
J->base[0] = tr; J->base[0] = tr;
J->needsnap = 1; J->needsnap = 1;
@ -981,12 +972,25 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
CTypeID id; CTypeID id;
TRef tr; TRef tr;
MSize i; MSize i;
IROp op;
lj_needsplit(J); lj_needsplit(J);
if (((s[0]->info & CTF_UNSIGNED) && s[0]->size == 8) || if (((s[0]->info & CTF_UNSIGNED) && s[0]->size == 8) ||
((s[1]->info & CTF_UNSIGNED) && s[1]->size == 8)) { ((s[1]->info & CTF_UNSIGNED) && s[1]->size == 8)) {
dt = IRT_U64; id = CTID_UINT64; dt = IRT_U64; id = CTID_UINT64;
} else { } else {
dt = IRT_I64; id = CTID_INT64; dt = IRT_I64; id = CTID_INT64;
if (mm < MM_add &&
!((s[0]->info | s[1]->info) & CTF_FP) &&
s[0]->size == 4 && s[1]->size == 4) { /* Try to narrow comparison. */
if (!((s[0]->info ^ s[1]->info) & CTF_UNSIGNED) ||
(tref_isk(sp[1]) && IR(tref_ref(sp[1]))->i >= 0)) {
dt = (s[0]->info & CTF_UNSIGNED) ? IRT_U32 : IRT_INT;
goto comp;
} else if (tref_isk(sp[0]) && IR(tref_ref(sp[0]))->i >= 0) {
dt = (s[1]->info & CTF_UNSIGNED) ? IRT_U32 : IRT_INT;
goto comp;
}
}
} }
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
IRType st = tref_type(sp[i]); IRType st = tref_type(sp[i]);
@ -994,16 +998,16 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
sp[i] = emitconv(sp[i], dt, st, IRCONV_TRUNC|IRCONV_ANY); sp[i] = emitconv(sp[i], dt, st, IRCONV_TRUNC|IRCONV_ANY);
else if (!(st == IRT_I64 || st == IRT_U64)) else if (!(st == IRT_I64 || st == IRT_U64))
sp[i] = emitconv(sp[i], dt, IRT_INT, sp[i] = emitconv(sp[i], dt, IRT_INT,
((st - IRT_I8) & 1) ? 0 : IRCONV_SEXT); (s[i]->info & CTF_UNSIGNED) ? 0 : IRCONV_SEXT);
} }
if (mm < MM_add) { if (mm < MM_add) {
comp:
/* Assume true comparison. Fixup and emit pending guard later. */ /* Assume true comparison. Fixup and emit pending guard later. */
IROp op;
if (mm == MM_eq) { if (mm == MM_eq) {
op = IR_EQ; op = IR_EQ;
} else { } else {
op = mm == MM_lt ? IR_LT : IR_LE; op = mm == MM_lt ? IR_LT : IR_LE;
if (dt == IRT_U64) if (dt == IRT_U32 || dt == IRT_U64)
op += (IR_ULT-IR_LT); op += (IR_ULT-IR_LT);
} }
lj_ir_set(J, IRTG(op, dt), sp[0], sp[1]); lj_ir_set(J, IRTG(op, dt), sp[0], sp[1]);
@ -1116,26 +1120,33 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
goto trymeta; goto trymeta;
} else if (tref_iscdata(tr)) { } else if (tref_iscdata(tr)) {
CTypeID id = argv2cdata(J, tr, &rd->argv[i])->ctypeid; CTypeID id = argv2cdata(J, tr, &rd->argv[i])->ctypeid;
IRType t;
ct = ctype_raw(cts, id); ct = ctype_raw(cts, id);
t = crec_ct2irt(cts, ct);
if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */ if (ctype_isptr(ct->info)) { /* Resolve pointer or reference. */
IRType t = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32;
if (ctype_isref(ct->info)) ct = ctype_rawchild(cts, ct);
tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_PTR); tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_PTR);
} else if (ctype_isinteger(ct->info) && ct->size == 8) { if (ctype_isref(ct->info)) {
IRType t = (ct->info & CTF_UNSIGNED) ? IRT_U64 : IRT_I64; ct = ctype_rawchild(cts, ct);
t = crec_ct2irt(cts, ct);
}
} else if (t == IRT_I64 || t == IRT_U64) {
tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT64); tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT64);
lj_needsplit(J); lj_needsplit(J);
goto ok; goto ok;
} else if (t == IRT_INT || t == IRT_U32) {
tr = emitir(IRT(IR_FLOAD, t), tr, IRFL_CDATA_INT);
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
goto ok;
} else if (ctype_isfunc(ct->info)) { } else if (ctype_isfunc(ct->info)) {
tr = emitir(IRT(IR_FLOAD, IRT_PTR), tr, IRFL_CDATA_PTR); tr = emitir(IRT(IR_FLOAD, IRT_PTR), tr, IRFL_CDATA_PTR);
ct = ctype_get(cts, ct = ctype_get(cts,
lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR)); lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR));
goto ok;
} else { } else {
tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata))); tr = emitir(IRT(IR_ADD, IRT_PTR), tr, lj_ir_kintp(J, sizeof(GCcdata)));
} }
if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct); if (ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (ctype_isnum(ct->info)) { if (ctype_isnum(ct->info)) {
IRType t = crec_ct2irt(ct);
if (t == IRT_CDATA) goto trymeta; if (t == IRT_CDATA) goto trymeta;
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J); if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
tr = emitir(IRT(IR_XLOAD, t), tr, 0); tr = emitir(IRT(IR_XLOAD, t), tr, 0);
@ -1147,6 +1158,21 @@ void LJ_FASTCALL recff_cdata_arith(jit_State *J, RecordFFData *rd)
ct = ctype_get(cts, CTID_P_VOID); ct = ctype_get(cts, CTID_P_VOID);
} else if (tref_isinteger(tr)) { } else if (tref_isinteger(tr)) {
ct = ctype_get(cts, CTID_INT32); ct = ctype_get(cts, CTID_INT32);
} else if (tref_isstr(tr)) {
TRef tr2 = J->base[1-i];
CTypeID id = argv2cdata(J, tr2, &rd->argv[1-i])->ctypeid;
ct = ctype_raw(cts, id);
if (ctype_isenum(ct->info)) { /* Match string against enum constant. */
GCstr *str = strV(&rd->argv[i]);
CTSize ofs;
CType *cct = lj_ctype_getfield(cts, ct, str, &ofs);
if (cct && ctype_isconstval(cct->info)) {
/* Specialize to the name of the enum constant. */
emitir(IRTG(IR_EQ, IRT_STR), tr, lj_ir_kstr(J, str));
ct = ctype_child(cts, cct);
tr = lj_ir_kint(J, (int32_t)ofs);
} /* else: interpreter will throw. */
} /* else: interpreter will throw. */
} else if (!tref_isnum(tr)) { } else if (!tref_isnum(tr)) {
goto trymeta; goto trymeta;
} }
@ -1203,7 +1229,6 @@ void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd)
void *sp = *(void **)cdataptr(cdataV(tv)); void *sp = *(void **)cdataptr(cdataV(tv));
TRef ptr; TRef ptr;
ct = ctype_raw(cts, sid); ct = ctype_raw(cts, sid);
if (rd->data && ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (LJ_64 && !checkptr32(sp)) if (LJ_64 && !checkptr32(sp))
ptr = lj_ir_kintp(J, (uintptr_t)sp); ptr = lj_ir_kintp(J, (uintptr_t)sp);
else else

View File

@ -575,6 +575,8 @@ LJFOLDF(kfold_conv_kintu32_num)
LJFOLD(CONV KINT IRCONV_I64_INT) LJFOLD(CONV KINT IRCONV_I64_INT)
LJFOLD(CONV KINT IRCONV_U64_INT) LJFOLD(CONV KINT IRCONV_U64_INT)
LJFOLD(CONV KINT IRCONV_I64_U32)
LJFOLD(CONV KINT IRCONV_U64_U32)
LJFOLDF(kfold_conv_kint_i64) LJFOLDF(kfold_conv_kint_i64)
{ {
if ((fins->op2 & IRCONV_SEXT)) if ((fins->op2 & IRCONV_SEXT))