static void crec_ct_ct(jit_State *J, CType *d, CType *s, TRef dp, TRef sp, void *svisnz) { 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; /* ** Note: Unlike lj_cconv_ct_ct(), sp holds the _value_ of pointers and ** numbers up to 8 bytes. Otherwise sp holds a pointer. */ switch (cconv_idx2(dinfo, sinfo)) { /* Destination is a bool. */ case CCX(B, B): goto xstore; /* Source operand is already normalized. */ case CCX(B, I): case CCX(B, F): if (st != IRT_CDATA) { /* Specialize to the result of a comparison against 0. */ TRef zero = (st == IRT_NUM || st == IRT_FLOAT) ? lj_ir_knum(J, 0) : (st == IRT_I64 || st == IRT_U64) ? lj_ir_kint64(J, 0) : lj_ir_kint(J, 0); int isnz = crec_isnonzero(s, svisnz); emitir(IRTG(isnz ? IR_NE : IR_EQ, st), sp, zero); sp = lj_ir_kint(J, isnz); goto xstore; } goto err_nyi; /* Destination is an integer. */ case CCX(I, B): case CCX(I, I): conv_I_I: if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; #if LJ_64 /* Sign-extend 32 to 64 bit integer. */ if (dsize == 8 && ssize < 8 && !(sinfo & CTF_UNSIGNED)) sp = emitconv(sp, dt, IRT_INT, IRCONV_SEXT); /* All other conversions are no-ops on x64. */ #else if (dsize == 8 && ssize < 8) /* Extend to 64 bit integer. */ sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, (sinfo & CTF_UNSIGNED) ? 0 : IRCONV_SEXT); else if (dsize < 8 && ssize == 8) /* Truncate from 64 bit integer. */ sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, 0); #endif xstore: emitir(IRT(IR_XSTORE, dt), dp, sp); break; case CCX(I, C): sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ /* fallthrough */ case CCX(I, F): if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, st, IRCONV_TRUNC|IRCONV_ANY); goto xstore; case CCX(I, P): case CCX(I, A): sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); ssize = CTSIZE_PTR; st = IRT_UINTP; goto conv_I_I; /* Destination is a floating-point number. */ case CCX(F, B): case CCX(F, I): conv_F_I: if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; sp = emitconv(sp, dt, ssize < 4 ? IRT_INT : st, 0); goto xstore; case CCX(F, C): sp = emitir(IRT(IR_XLOAD, st), sp, 0); /* Load re. */ /* fallthrough */ case CCX(F, F): conv_F_F: if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; if (dt != st) sp = emitconv(sp, dt, st, 0); goto xstore; /* Destination is a complex number. */ case CCX(C, I): case CCX(C, F): { /* Clear im. */ TRef ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); emitir(IRT(IR_XSTORE, dt), ptr, lj_ir_knum(J, 0)); } /* Convert to re. */ if ((sinfo & CTF_FP)) goto conv_F_F; else goto conv_F_I; case CCX(C, C): if (dt == IRT_CDATA || st == IRT_CDATA) goto err_nyi; { TRef re, im, ptr; re = emitir(IRT(IR_XLOAD, st), sp, 0); ptr = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, (ssize >> 1))); im = emitir(IRT(IR_XLOAD, st), ptr, 0); if (dt != st) { re = emitconv(re, dt, st, 0); im = emitconv(im, dt, st, 0); } emitir(IRT(IR_XSTORE, dt), dp, re); ptr = emitir(IRT(IR_ADD, IRT_PTR), dp, lj_ir_kintp(J, (dsize >> 1))); emitir(IRT(IR_XSTORE, dt), ptr, im); } break; /* Destination is a vector. */ case CCX(V, I): case CCX(V, F): case CCX(V, C): case CCX(V, V): goto err_nyi; /* Destination is a pointer. */ case CCX(P, P): case CCX(P, A): case CCX(P, S): /* There are only 32 bit pointers/addresses on 32 bit machines. ** Also ok on x64, since all 32 bit ops clear the upper part of the reg. */ goto xstore; case CCX(P, I): if (st == IRT_CDATA) goto err_nyi; if (!LJ_64 && ssize == 8) /* Truncate from 64 bit integer. */ sp = emitconv(sp, IRT_U32, st, 0); goto xstore; case CCX(P, F): if (st == IRT_CDATA) goto err_nyi; /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ sp = emitconv(sp, (LJ_64 && dsize == 8) ? IRT_I64 : IRT_U32, st, IRCONV_TRUNC|IRCONV_ANY); goto xstore; /* Destination is an array. */ case CCX(A, A): goto err_nyi; /* Destination is a struct/union. */ case CCX(S, S): goto err_nyi; default: err_conv: err_nyi: lj_trace_err(J, LJ_TRERR_NYICONV); break; } }
/* Convert C type to C type. Caveat: expects to get the raw CType! ** ** Note: This is only used by the interpreter and not optimized at all. ** The JIT compiler will do a much better job specializing for each case. */ void lj_cconv_ct_ct(CTState *cts, CType *d, CType *s, uint8_t *dp, uint8_t *sp, CTInfo flags) { CTSize dsize = d->size, ssize = s->size; CTInfo dinfo = d->info, sinfo = s->info; void *tmpptr; lua_assert(!ctype_isenum(dinfo) && !ctype_isenum(sinfo)); lua_assert(!ctype_isattrib(dinfo) && !ctype_isattrib(sinfo)); if (ctype_type(dinfo) > CT_MAYCONVERT || ctype_type(sinfo) > CT_MAYCONVERT) goto err_conv; /* Some basic sanity checks. */ lua_assert(!ctype_isnum(dinfo) || dsize > 0); lua_assert(!ctype_isnum(sinfo) || ssize > 0); lua_assert(!ctype_isbool(dinfo) || dsize == 1 || dsize == 4); lua_assert(!ctype_isbool(sinfo) || ssize == 1 || ssize == 4); lua_assert(!ctype_isinteger(dinfo) || (1u<<lj_fls(dsize)) == dsize); lua_assert(!ctype_isinteger(sinfo) || (1u<<lj_fls(ssize)) == ssize); switch (cconv_idx2(dinfo, sinfo)) { /* Destination is a bool. */ case CCX(B, B): /* Source operand is already normalized. */ if (dsize == 1) *dp = *sp; else *(int *)dp = *sp; break; case CCX(B, I): { MSize i; uint8_t b = 0; for (i = 0; i < ssize; i++) b |= sp[i]; b = (b != 0); if (dsize == 1) *dp = b; else *(int *)dp = b; break; } case CCX(B, F): { uint8_t b; if (ssize == sizeof(double)) b = (*(double *)sp != 0); else if (ssize == sizeof(float)) b = (*(float *)sp != 0); else goto err_conv; /* NYI: long double. */ if (dsize == 1) *dp = b; else *(int *)dp = b; break; } /* Destination is an integer. */ case CCX(I, B): case CCX(I, I): conv_I_I: if (dsize > ssize) { /* Zero-extend or sign-extend LSB. */ #if LJ_LE uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[ssize-1]&0x80)) ? 0xff : 0; memcpy(dp, sp, ssize); memset(dp + ssize, fill, dsize-ssize); #else uint8_t fill = (!(sinfo & CTF_UNSIGNED) && (sp[0]&0x80)) ? 0xff : 0; memset(dp, fill, dsize-ssize); memcpy(dp + (dsize-ssize), sp, ssize); #endif } else { /* Copy LSB. */ #if LJ_LE memcpy(dp, sp, dsize); #else memcpy(dp, sp + (ssize-dsize), dsize); #endif } break; case CCX(I, F): { double n; /* Always convert via double. */ conv_I_F: /* Convert source to double. */ if (ssize == sizeof(double)) n = *(double *)sp; else if (ssize == sizeof(float)) n = (double)*(float *)sp; else goto err_conv; /* NYI: long double. */ /* Then convert double to integer. */ /* The conversion must exactly match the semantics of JIT-compiled code! */ if (dsize < 4 || (dsize == 4 && !(dinfo & CTF_UNSIGNED))) { int32_t i = (int32_t)n; if (dsize == 4) *(int32_t *)dp = i; else if (dsize == 2) *(int16_t *)dp = (int16_t)i; else *(int8_t *)dp = (int8_t)i; } else if (dsize == 4) { *(uint32_t *)dp = (uint32_t)n; } else if (dsize == 8) { if (!(dinfo & CTF_UNSIGNED)) *(int64_t *)dp = (int64_t)n; else *(uint64_t *)dp = lj_num2u64(n); } else { goto err_conv; /* NYI: conversion to >64 bit integers. */ } break; } case CCX(I, C): s = ctype_child(cts, s); sinfo = s->info; ssize = s->size; goto conv_I_F; /* Just convert re. */ case CCX(I, P): if (!(flags & CCF_CAST)) goto err_conv; sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); goto conv_I_I; case CCX(I, A): if (!(flags & CCF_CAST)) goto err_conv; sinfo = CTINFO(CT_NUM, CTF_UNSIGNED); ssize = CTSIZE_PTR; tmpptr = sp; sp = (uint8_t *)&tmpptr; goto conv_I_I; /* Destination is a floating-point number. */ case CCX(F, B): case CCX(F, I): { double n; /* Always convert via double. */ conv_F_I: /* First convert source to double. */ /* The conversion must exactly match the semantics of JIT-compiled code! */ if (ssize < 4 || (ssize == 4 && !(sinfo & CTF_UNSIGNED))) { int32_t i; if (ssize == 4) { i = *(int32_t *)sp; } else if (!(sinfo & CTF_UNSIGNED)) { if (ssize == 2) i = *(int16_t *)sp; else i = *(int8_t *)sp; } else { if (ssize == 2) i = *(uint16_t *)sp; else i = *(uint8_t *)sp; } n = (double)i; } else if (ssize == 4) { n = (double)*(uint32_t *)sp; } else if (ssize == 8) { if (!(sinfo & CTF_UNSIGNED)) n = (double)*(int64_t *)sp; else n = (double)*(uint64_t *)sp; } else { goto err_conv; /* NYI: conversion from >64 bit integers. */ } /* Convert double to destination. */ if (dsize == sizeof(double)) *(double *)dp = n; else if (dsize == sizeof(float)) *(float *)dp = (float)n; else goto err_conv; /* NYI: long double. */ break; } case CCX(F, F): { double n; /* Always convert via double. */ conv_F_F: if (ssize == dsize) goto copyval; /* Convert source to double. */ if (ssize == sizeof(double)) n = *(double *)sp; else if (ssize == sizeof(float)) n = (double)*(float *)sp; else goto err_conv; /* NYI: long double. */ /* Convert double to destination. */ if (dsize == sizeof(double)) *(double *)dp = n; else if (dsize == sizeof(float)) *(float *)dp = (float)n; else goto err_conv; /* NYI: long double. */ break; } case CCX(F, C): s = ctype_child(cts, s); sinfo = s->info; ssize = s->size; goto conv_F_F; /* Ignore im, and convert from re. */ /* Destination is a complex number. */ case CCX(C, I): d = ctype_child(cts, d); dinfo = d->info; dsize = d->size; memset(dp + dsize, 0, dsize); /* Clear im. */ goto conv_F_I; /* Convert to re. */ case CCX(C, F): d = ctype_child(cts, d); dinfo = d->info; dsize = d->size; memset(dp + dsize, 0, dsize); /* Clear im. */ goto conv_F_F; /* Convert to re. */ case CCX(C, C): if (dsize != ssize) { /* Different types: convert re/im separately. */ CType *dc = ctype_child(cts, d); CType *sc = ctype_child(cts, s); lj_cconv_ct_ct(cts, dc, sc, dp, sp, flags); lj_cconv_ct_ct(cts, dc, sc, dp + dc->size, sp + sc->size, flags); return; } goto copyval; /* Otherwise this is easy. */ /* Destination is a vector. */ case CCX(V, I): case CCX(V, F): case CCX(V, C): { CType *dc = ctype_child(cts, d); CTSize esize; /* First convert the scalar to the first element. */ lj_cconv_ct_ct(cts, dc, s, dp, sp, flags); /* Then replicate it to the other elements (splat). */ for (sp = dp, esize = dc->size; dsize > esize; dsize -= esize) { dp += esize; memcpy(dp, sp, esize); } break; } case CCX(V, V): /* Copy same-sized vectors, even for different lengths/element-types. */ if (dsize != ssize) goto err_conv; goto copyval; /* Destination is a pointer. */ case CCX(P, I): if (!(flags & CCF_CAST)) goto err_conv; dinfo = CTINFO(CT_NUM, CTF_UNSIGNED); goto conv_I_I; case CCX(P, F): if (!(flags & CCF_CAST) || !(flags & CCF_FROMTV)) goto err_conv; /* The signed conversion is cheaper. x64 really has 47 bit pointers. */ dinfo = CTINFO(CT_NUM, (LJ_64 && dsize == 8) ? 0 : CTF_UNSIGNED); goto conv_I_F; case CCX(P, P): if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; cdata_setptr(dp, dsize, cdata_getptr(sp, ssize)); break; case CCX(P, A): case CCX(P, S): if (!lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; cdata_setptr(dp, dsize, sp); break; /* Destination is an array. */ case CCX(A, A): if ((flags & CCF_CAST) || (d->info & CTF_VLA) || dsize != ssize || d->size == CTSIZE_INVALID || !lj_cconv_compatptr(cts, d, s, flags)) goto err_conv; goto copyval; /* Destination is a struct/union. */ case CCX(S, S): if ((flags & CCF_CAST) || (d->info & CTF_VLA) || d != s) goto err_conv; /* Must be exact same type. */ copyval: /* Copy value. */ lua_assert(dsize == ssize); memcpy(dp, sp, dsize); break; default: err_conv: cconv_err_conv(cts, d, s, flags); } }