diff --git a/doc/ext_ffi_semantics.html b/doc/ext_ffi_semantics.html
index ed32d23f..afe7e613 100644
--- a/doc/ext_ffi_semantics.html
+++ b/doc/ext_ffi_semantics.html
@@ -250,19 +250,20 @@ constant values; retrieving return values from C calls:
bool | 0 → false, otherwise true | boolean |
-Complex number | boxed value | complex cdata |
+enum | boxed value | enum cdata |
+Complex number | boxed value | complex cdata |
+
Vector | boxed value | vector cdata |
-
+
Pointer | boxed value | pointer cdata |
-
+
Array | boxed reference | reference cdata |
-
+
struct/union | boxed reference | reference cdata |
-Bitfields or enum types are treated like their underlying
-type.
+Bitfields are treated like their underlying type.
Reference types are dereferenced before a conversion can take
@@ -715,6 +716,10 @@ is performed. Otherwise both sides are converted to an
int64_t and a signed arithmetic operation is performed. The
result is a boxed 64 bit cdata object.
+If one of the operands is an enum and the other operand is a
+string, the string is converted to the value of a matching enum
+constant before the above conversion.
+
These rules ensure that 64 bit integers are "sticky". Any
expression involving at least one 64 bit integer operand results
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 uint64_t, the other side is converted to an
uint64_t and an unsigned comparison is performed. Otherwise
both sides are converted to an int64_t and a signed
-comparison is performed.
+comparison is performed.
+
+If one of the operands is an enum and the other operand is a
+string, the string is converted to the value of a matching enum
+constant before the above conversion.
Comparisons for equality/inequality never raise an error.
Even incompatible pointers can be compared for equality by address. Any
diff --git a/src/lib_ffi.c b/src/lib_ffi.c
index c74b497a..5cb9086e 100644
--- a/src/lib_ffi.c
+++ b/src/lib_ffi.c
@@ -297,6 +297,9 @@ LJLIB_CF(ffi_meta___tostring)
goto checkgc;
} else if (ctype_isfunc(ct->info)) {
p = *(void **)p;
+ } else if (ctype_isenum(ct->info)) {
+ msg = "cdata<%s>: %d";
+ p = (void *)(uintptr_t)*(uint32_t **)p;
} else {
if (ctype_isptr(ct->info)) {
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);
void *sp = *(void **)cdataptr(cd);
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))
lj_gc_check(L);
return 1;
diff --git a/src/lj_asm_arm.h b/src/lj_asm_arm.h
index 9ef785c3..6a44e5ef 100644
--- a/src/lj_asm_arm.h
+++ b/src/lj_asm_arm.h
@@ -1287,7 +1287,7 @@ static void asm_intcomp(ASMState *as, IRIns *ir)
Reg left;
uint32_t m;
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)) {
Reg tmp = lref; lref = rref; rref = tmp;
if (cc >= CC_GE) cc ^= 7; /* LT <-> GT, LE <-> GE */
diff --git a/src/lj_asm_x86.h b/src/lj_asm_x86.h
index c68768b4..ceeefbee 100644
--- a/src/lj_asm_x86.h
+++ b/src/lj_asm_x86.h
@@ -337,7 +337,7 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
}
} else if (ir->o == IR_FLOAD) {
/* 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)) {
asm_fusefref(as, ir, xallow);
return RID_MRM;
@@ -2064,7 +2064,8 @@ static void asm_comp(ASMState *as, IRIns *ir, uint32_t cc)
IROp leftop = (IROp)(IR(lref)->o);
Reg r64 = REX_64IR(ir, 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. */
if (irref_isk(lref) || (!irref_isk(rref) && opisfusableload(leftop))) {
if ((cc & 0xc) == 0xc) cc ^= 0x53; /* L <-> G, LE <-> GE */
diff --git a/src/lj_carith.c b/src/lj_carith.c
index c5275f70..8c76abe9 100644
--- a/src/lj_carith.c
+++ b/src/lj_carith.c
@@ -46,6 +46,7 @@ static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
ct = ctype_get(cts,
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->p[i] = p;
} else if (tvisint(o)) {
@@ -57,6 +58,25 @@ static int carith_checkarg(lua_State *L, CTState *cts, CDArith *ca)
} else if (tvisnil(o)) {
ca->ct[i] = ctype_get(cts, CTID_P_VOID);
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 {
ca->ct[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);
if (!tv) {
const char *repr[2];
- int i;
+ int i, isenum = -1, isstr = -1;
if (mm == MM_eq) { /* Equality checks never raise an error. */
setboolV(L->top-1, 0);
return 1;
}
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));
- else
+ } else {
+ if (tvisstr(&L->base[i])) isstr = 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 :
mm == MM_concat ? LJ_ERR_FFI_BADCONCAT :
mm < MM_add ? LJ_ERR_FFI_BADCOMP : LJ_ERR_FFI_BADARITH,
diff --git a/src/lj_ccall.c b/src/lj_ccall.c
index 22171778..c3eb25f6 100644
--- a/src/lj_ccall.c
+++ b/src/lj_ccall.c
@@ -684,7 +684,6 @@ static int ccall_get_results(lua_State *L, CTState *cts, CType *ct,
#endif
/* No reference types end up here, so there's no need for the CTypeID. */
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);
}
diff --git a/src/lj_ccallback.c b/src/lj_ccallback.c
index c3f37f2d..a9567bc5 100644
--- a/src/lj_ccallback.c
+++ b/src/lj_ccallback.c
@@ -426,7 +426,6 @@ static void callback_conv_args(CTState *cts, lua_State *L)
MSize n;
lua_assert(ctype_isfield(ctf->info));
cta = ctype_rawchild(cts, ctf);
- if (ctype_isenum(cta->info)) cta = ctype_child(cts, cta);
isfp = ctype_isfp(cta->info);
sz = (cta->size + CTSIZE_PTR-1) & ~(CTSIZE_PTR-1);
n = sz / CTSIZE_PTR; /* Number of GPRs or stack slots needed. */
diff --git a/src/lj_cconv.c b/src/lj_cconv.c
index 9964f8a4..f33ed56d 100644
--- a/src/lj_cconv.c
+++ b/src/lj_cconv.c
@@ -374,7 +374,6 @@ int lj_cconv_tv_ct(CTState *cts, CType *s, CTypeID sid,
TValue *o, uint8_t *sp)
{
CTInfo sinfo = s->info;
- lua_assert(!ctype_isenum(sinfo));
if (ctype_isnum(sinfo)) {
if (!ctype_isbool(sinfo)) {
if (ctype_isinteger(sinfo) && s->size > 4) goto copyval;
diff --git a/src/lj_cdata.c b/src/lj_cdata.c
index 461b55a2..2f10113b 100644
--- a/src/lj_cdata.c
+++ b/src/lj_cdata.c
@@ -231,8 +231,8 @@ int lj_cdata_get(CTState *cts, CType *s, TValue *o, uint8_t *sp)
s = ctype_get(cts, sid);
}
- /* Skip attributes and enums. */
- while (ctype_isattrib(s->info) || ctype_isenum(s->info))
+ /* Skip attributes. */
+ while (ctype_isattrib(s->info))
s = ctype_child(cts, s);
return lj_cconv_tv_ct(cts, s, sid, o, sp);
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index 6cb565c3..49b2341a 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -111,8 +111,9 @@ static CTypeID argv2ctype(jit_State *J, TRef tr, cTValue *o)
*/
/* 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 ((ct->info & CTF_FP)) {
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,
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;
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)
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)
{
CTState *cts = ctype_ctsG(J2G(J));
+ IRType t = crec_ct2irt(cts, s);
CTInfo sinfo = s->info;
- lua_assert(!ctype_isenum(sinfo));
if (ctype_isnum(sinfo)) {
- IRType t = crec_ct2irt(s);
TRef tr;
if (t == IRT_CDATA)
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 {
return tr;
}
- } else if (ctype_isptr(sinfo)) {
- IRType t = (LJ_64 && s->size == 8) ? IRT_P64 : IRT_P32;
- sp = emitir(IRT(IR_XLOAD, t), sp, 0);
+ } else if (ctype_isptr(sinfo) || ctype_isenum(sinfo)) {
+ sp = emitir(IRT(IR_XLOAD, t), sp, 0); /* Box pointers and enums. */
} else if (ctype_isrefarray(sinfo) || ctype_isstruct(sinfo)) {
cts->L = J->L;
sid = lj_ctype_intern(cts, CTINFO_REF(sid), CTSIZE_PTR); /* Create ref. */
} 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);
TRef ptr, tr1, tr2, dp;
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:
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);
}
@@ -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));
if (cct && ctype_isconstval(cct->info)) {
lua_assert(ctype_child(cts, cct)->size == 4);
- svisnz = (void *)(intptr_t)(cct->size != 0);
- sp = lj_ir_kint(J, (int32_t)cct->size);
+ svisnz = (void *)(intptr_t)(ofs != 0);
+ sp = lj_ir_kint(J, (int32_t)ofs);
sid = ctype_cid(cct->info);
} /* else: interpreter will throw. */
} 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;
s = ctype_raw(cts, sid);
svisnz = cdataptr(cdataV(sval));
- if (ctype_isenum(s->info)) s = ctype_child(cts, s);
- t = crec_ct2irt(s);
+ t = crec_ct2irt(cts, s);
if (ctype_isptr(s->info)) {
sp = emitir(IRT(IR_FLOAD, t), sp, IRFL_CDATA_PTR);
if (ctype_isref(s->info)) {
svisnz = *(void **)svisnz;
s = ctype_rawchild(cts, s);
- if (ctype_isenum(s->info)) s = ctype_child(cts, s);
- t = crec_ct2irt(s);
+ t = crec_ct2irt(cts, s);
} else {
goto doconv;
}
@@ -554,10 +550,8 @@ again:
} else if (tref_iscdata(idx)) {
GCcdata *cdk = cdataV(&rd->argv[1]);
CType *ctk = ctype_raw(cts, cdk->ctypeid);
- IRType t;
- if (ctype_isenum(ctk->info)) ctk = ctype_child(cts, ctk);
- if (ctype_ispointer(ct->info) &&
- ctype_isinteger(ctk->info) && (t = crec_ct2irt(ctk)) != IRT_CDATA) {
+ IRType t = crec_ct2irt(cts, ctk);
+ if (ctype_ispointer(ct->info) && t >= IRT_I8 && t <= IRT_U64) {
if (ctk->size == 8) {
idx = emitir(IRT(IR_FLOAD, t), idx, IRFL_CDATA_INT64);
} else if (ctk->size == 4) {
@@ -637,7 +631,6 @@ again:
ct = ctype_child(cts, ct); /* Skip attributes. */
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);
} else { /* __newindex metamethod. */
rd->nres = 0;
@@ -888,7 +881,7 @@ static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
if (ctype_isfunc(ct->info)) {
TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR);
CType *ctr = ctype_rawchild(cts, ct);
- IRType t = crec_ct2irt(ctr);
+ IRType t = crec_ct2irt(cts, ctr);
TRef tr;
TValue tv;
/* 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)) {
t = IRT_NIL;
rd->nres = 0;
- } else if (ctype_isenum(ctr->info)) {
- ctr = ctype_child(cts, ctr);
- }
- if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) ||
- ctype_isvoid(ctr->info)) || t == IRT_CDATA)
+ } else if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info) ||
+ ctype_isenum(ctr->info)) || t == IRT_CDATA) {
lj_trace_err(J, LJ_TRERR_NYICALL);
+ }
if ((ct->info & CTF_VARARG)
#if LJ_TARGET_X86
|| 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;
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) {
tr = emitconv(tr, IRT_NUM, t, 0);
} else if (t == IRT_I8 || t == IRT_I16) {
tr = emitconv(tr, IRT_INT, t, IRCONV_SEXT);
} else if (t == IRT_U8 || t == IRT_U16) {
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->needsnap = 1;
@@ -981,12 +972,25 @@ static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
CTypeID id;
TRef tr;
MSize i;
+ IROp op;
lj_needsplit(J);
if (((s[0]->info & CTF_UNSIGNED) && s[0]->size == 8) ||
((s[1]->info & CTF_UNSIGNED) && s[1]->size == 8)) {
dt = IRT_U64; id = CTID_UINT64;
} else {
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++) {
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);
else if (!(st == IRT_I64 || st == IRT_U64))
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) {
+ comp:
/* Assume true comparison. Fixup and emit pending guard later. */
- IROp op;
if (mm == MM_eq) {
op = IR_EQ;
} else {
op = mm == MM_lt ? IR_LT : IR_LE;
- if (dt == IRT_U64)
+ if (dt == IRT_U32 || dt == IRT_U64)
op += (IR_ULT-IR_LT);
}
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;
} else if (tref_iscdata(tr)) {
CTypeID id = argv2cdata(J, tr, &rd->argv[i])->ctypeid;
+ IRType t;
ct = ctype_raw(cts, id);
+ t = crec_ct2irt(cts, ct);
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);
- } else if (ctype_isinteger(ct->info) && ct->size == 8) {
- IRType t = (ct->info & CTF_UNSIGNED) ? IRT_U64 : IRT_I64;
+ if (ctype_isref(ct->info)) {
+ 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);
lj_needsplit(J);
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)) {
tr = emitir(IRT(IR_FLOAD, IRT_PTR), tr, IRFL_CDATA_PTR);
ct = ctype_get(cts,
lj_ctype_intern(cts, CTINFO(CT_PTR, CTALIGN_PTR|id), CTSIZE_PTR));
+ goto ok;
} else {
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_isnum(ct->info)) {
- IRType t = crec_ct2irt(ct);
if (t == IRT_CDATA) goto trymeta;
if (t == IRT_I64 || t == IRT_U64) lj_needsplit(J);
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);
} else if (tref_isinteger(tr)) {
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)) {
goto trymeta;
}
@@ -1203,7 +1229,6 @@ void LJ_FASTCALL recff_clib_index(jit_State *J, RecordFFData *rd)
void *sp = *(void **)cdataptr(cdataV(tv));
TRef ptr;
ct = ctype_raw(cts, sid);
- if (rd->data && ctype_isenum(ct->info)) ct = ctype_child(cts, ct);
if (LJ_64 && !checkptr32(sp))
ptr = lj_ir_kintp(J, (uintptr_t)sp);
else
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c
index 156db426..f4aadb8d 100644
--- a/src/lj_opt_fold.c
+++ b/src/lj_opt_fold.c
@@ -575,6 +575,8 @@ LJFOLDF(kfold_conv_kintu32_num)
LJFOLD(CONV KINT IRCONV_I64_INT)
LJFOLD(CONV KINT IRCONV_U64_INT)
+LJFOLD(CONV KINT IRCONV_I64_U32)
+LJFOLD(CONV KINT IRCONV_U64_U32)
LJFOLDF(kfold_conv_kint_i64)
{
if ((fins->op2 & IRCONV_SEXT))