<tr class="odd">
<td class="convin">Integer</td><td class="convop">→<sup>round</sup></td><td class="convout"><tt>double</tt>, <tt>float</tt></td></tr>
<tr class="even">
-<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>trunc</sup> <tt>int32_t</tt> →<sup>narrow</sup></td><td class="convout"><tt>(u)int8_t</tt>, <tt>(u)int16_t</tt></td></tr>
+<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>trunc</sup> <tt>int64_t</tt> →<sup>narrow</sup> <sup>*</sup></td><td class="convout"><tt>(u)int8_t</tt>, <tt>(u)int16_t</tt>, <tt>(u)int32_t</tt></td></tr>
<tr class="odd">
-<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>trunc</sup></td><td class="convout"><tt>(u)int32_t</tt>, <tt>(u)int64_t</tt></td></tr>
+<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>trunc</sup></td><td class="convout"><tt>int64_t</tt></td></tr>
<tr class="even">
+<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>trunc</sup> uint64_t ∪ int64_t →<sup>reinterpret</sup> <sup>*</sup></td><td class="convout"><tt>uint64_t</tt></td></tr>
+<tr class="odd">
<td class="convin"><tt>double</tt>, <tt>float</tt></td><td class="convop">→<sup>round</sup></td><td class="convout"><tt>float</tt>, <tt>double</tt></td></tr>
-<tr class="odd separate">
+<tr class="even separate">
<td class="convin">Number</td><td class="convop">n == 0 → 0, otherwise 1</td><td class="convout"><tt>bool</tt></td></tr>
-<tr class="even">
+<tr class="odd">
<td class="convin"><tt>bool</tt></td><td class="convop"><tt>false</tt> → 0, <tt>true</tt> → 1</td><td class="convout">Number</td></tr>
-<tr class="odd separate">
+<tr class="even separate">
<td class="convin">Complex number</td><td class="convop">convert real part</td><td class="convout">Number</td></tr>
-<tr class="even">
-<td class="convin">Number</td><td class="convop">convert real part, imag = 0</td><td class="convout">Complex number</td></tr>
<tr class="odd">
+<td class="convin">Number</td><td class="convop">convert real part, imag = 0</td><td class="convout">Complex number</td></tr>
+<tr class="even">
<td class="convin">Complex number</td><td class="convop">convert real and imag part</td><td class="convout">Complex number</td></tr>
-<tr class="even separate">
+<tr class="odd separate">
<td class="convin">Number</td><td class="convop">convert scalar and replicate</td><td class="convout">Vector</td></tr>
-<tr class="odd">
+<tr class="even">
<td class="convin">Vector</td><td class="convop">copy (same size)</td><td class="convout">Vector</td></tr>
-<tr class="even separate">
+<tr class="odd separate">
<td class="convin"><tt>struct</tt>/<tt>union</tt></td><td class="convop">take base address (compat)</td><td class="convout">Pointer</td></tr>
-<tr class="odd">
-<td class="convin">Array</td><td class="convop">take base address (compat)</td><td class="convout">Pointer</td></tr>
<tr class="even">
+<td class="convin">Array</td><td class="convop">take base address (compat)</td><td class="convout">Pointer</td></tr>
+<tr class="odd">
<td class="convin">Function</td><td class="convop">take function address</td><td class="convout">Function pointer</td></tr>
-<tr class="odd separate">
+<tr class="even separate">
<td class="convin">Number</td><td class="convop">convert via <tt>uintptr_t</tt> (cast)</td><td class="convout">Pointer</td></tr>
-<tr class="even">
-<td class="convin">Pointer</td><td class="convop">convert address (compat/cast)</td><td class="convout">Pointer</td></tr>
<tr class="odd">
-<td class="convin">Pointer</td><td class="convop">convert address (cast)</td><td class="convout">Integer</td></tr>
+<td class="convin">Pointer</td><td class="convop">convert address (compat/cast)</td><td class="convout">Pointer</td></tr>
<tr class="even">
+<td class="convin">Pointer</td><td class="convop">convert address (cast)</td><td class="convout">Integer</td></tr>
+<tr class="odd">
<td class="convin">Array</td><td class="convop">convert base address (cast)</td><td class="convout">Integer</td></tr>
-<tr class="odd separate">
+<tr class="even separate">
<td class="convin">Array</td><td class="convop">copy (compat)</td><td class="convout">Array</td></tr>
-<tr class="even">
+<tr class="odd">
<td class="convin"><tt>struct</tt>/<tt>union</tt></td><td class="convop">copy (identical type)</td><td class="convout"><tt>struct</tt>/<tt>union</tt></td></tr>
</table>
<p>
Conversions not listed above will raise an error. E.g. it's not
possible to convert a pointer to a complex number or vice versa.
</p>
+<p>
+* Some conversions from <tt>double</tt> have a larger defined range to
+allow for mixed-signedness conversions, which are common in C code.
+E.g. initializing an <tt>int32_t</tt> field with <tt>0xffffffff</tt>
+or initializing an <tt>uint32_t</tt> or <tt>uint64_t</tt> field with
+<tt>-1</tt>. Under strict conversion rules, these assignments would
+give undefined results, since Lua numbers are doubles. The extended
+ranges make these conversions defined. Lua numbers that are even
+outside that range give an architecture-specific result.
+</p>
+<p>
+Please note that doubles do not have the precision to represent the
+whole signed or unsigned 64 bit integer range. Beware of large hex
+constants in particular: e.g. <tt>0xffffffffffffffff</tt> is a double
+rounded up to <tt>0x1p64</tt> during parsing. This will <em>not</em>
+convert to a defined 64 bit integer value. Use the 64 bit literal
+syntax instead, i.e. <tt>0xffffffffffffffffULL</tt>.
+</p>
<h3 id="convert_vararg">Conversions for vararg C function arguments</h3>
<p>
lua_Number d;
if (fscanf(fp, LUA_NUMBER_SCAN, &d) == 1) {
if (LJ_DUALNUM) {
- int32_t i = lj_num2int(d);
- if (d == (lua_Number)i && !tvismzero((cTValue *)&d)) {
+ int64_t i64;
+ int32_t i;
+ if (lj_num2int_check(d, i64, i) && !tvismzero((cTValue *)&d)) {
setintV(L->top++, i);
return 1;
}
if (tvisint(o))
ofs = (int64_t)intV(o);
else if (tvisnum(o))
- ofs = (int64_t)numV(o);
+ ofs = lj_num2i64(numV(o));
else if (!tvisnil(o))
lj_err_argt(L, 3, LUA_TNUMBER);
}
LJLIB_CF(os_date)
{
const char *s = luaL_optstring(L, 1, "%c");
- time_t t = luaL_opt(L, (time_t)luaL_checknumber, 2, time(NULL));
+ time_t t = lua_isnoneornil(L, 2) ? time(NULL) :
+ lj_num2int_type(luaL_checknumber(L, 2), time_t);
struct tm *stm;
#if LJ_TARGET_POSIX
struct tm rtm;
LJLIB_CF(os_difftime)
{
- lua_pushnumber(L, difftime((time_t)(luaL_checknumber(L, 1)),
- (time_t)(luaL_optnumber(L, 2, (lua_Number)0))));
+ lua_pushnumber(L,
+ difftime(lj_num2int_type(luaL_checknumber(L, 1), time_t),
+ lj_num2int_type(luaL_optnumber(L, 2, (lua_Number)0), time_t)));
return 1;
}
return intV(&tmp);
n = numV(&tmp);
}
-#if LJ_64
- return (lua_Integer)n;
-#else
- return lj_num2int(n);
-#endif
+ return lj_num2int_type(n, lua_Integer);
}
LUA_API lua_Integer lua_tointegerx(lua_State *L, int idx, int *ok)
n = numV(&tmp);
}
if (ok) *ok = 1;
-#if LJ_64
- return (lua_Integer)n;
-#else
- return lj_num2int(n);
-#endif
+ return lj_num2int_type(n, lua_Integer);
}
LUALIB_API lua_Integer luaL_checkinteger(lua_State *L, int idx)
return (lua_Integer)intV(&tmp);
n = numV(&tmp);
}
-#if LJ_64
- return (lua_Integer)n;
-#else
- return lj_num2int(n);
-#endif
+ return lj_num2int_type(n, lua_Integer);
}
LUALIB_API lua_Integer luaL_optinteger(lua_State *L, int idx, lua_Integer def)
return (lua_Integer)intV(&tmp);
n = numV(&tmp);
}
-#if LJ_64
- return (lua_Integer)n;
-#else
- return lj_num2int(n);
-#endif
+ return lj_num2int_type(n, lua_Integer);
}
LUA_API int lua_toboolean(lua_State *L, int idx)
IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK);
IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH);
IRCallID id;
+ const CCallInfo *ci;
+#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
+ CCallInfo cim;
+#endif
IRRef args[2];
lj_assertA((ir-1)->o == IR_CONV && ir->o == IR_HIOP,
"not a CONV/HIOP pair at IR %04d", (int)(ir - as->ir) - REF_BIAS);
args[LJ_BE] = (ir-1)->op1;
args[LJ_LE] = ir->op1;
- if (st == IRT_NUM || st == IRT_FLOAT) {
- id = IRCALL_fp64_d2l + ((st == IRT_FLOAT) ? 2 : 0) + (dt - IRT_I64);
+ lj_assertA(st != IRT_FLOAT, "bad CONV *64.float emitted");
+ if (st == IRT_NUM) {
+ id = IRCALL_lj_vm_num2u64;
ir--;
+ ci = &lj_ir_callinfo[id];
} else {
id = IRCALL_fp64_l2d + ((dt == IRT_FLOAT) ? 2 : 0) + (st - IRT_I64);
- }
- {
#if LJ_TARGET_ARM && !LJ_ABI_SOFTFP
- CCallInfo cim = lj_ir_callinfo[id], *ci = &cim;
+ cim = lj_ir_callinfo[id];
cim.flags |= CCI_VARARG; /* These calls don't use the hard-float ABI! */
+ ci = &cim;
#else
- const CCallInfo *ci = &lj_ir_callinfo[id];
+ ci = &lj_ir_callinfo[id];
#endif
- asm_setupresult(as, ir, ci);
- asm_gencall(as, ci, args);
}
+ asm_setupresult(as, ir, ci);
+ asm_gencall(as, ci, args);
}
#endif
Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left));
Reg dest = ra_dest(as, ir, RSET_GPR);
ARMIns ai;
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
emit_dn(as, ARMI_VMOV_R_S, dest, (tmp & 15));
- ai = irt_isint(ir->t) ?
- (st == IRT_NUM ? ARMI_VCVT_S32_F64 : ARMI_VCVT_S32_F32) :
- (st == IRT_NUM ? ARMI_VCVT_U32_F64 : ARMI_VCVT_U32_F32);
+ ai = st == IRT_NUM ? ARMI_VCVT_S32_F64 : ARMI_VCVT_S32_F32;
emit_dm(as, ai, (tmp & 15), (left & 15));
}
} else
} else {
Reg left = ra_alloc1(as, lref, RSET_FPR);
Reg dest = ra_dest(as, ir, RSET_GPR);
- A64Ins ai = irt_is64(ir->t) ?
- (st == IRT_NUM ?
- (irt_isi64(ir->t) ? A64I_FCVT_S64_F64 : A64I_FCVT_U64_F64) :
- (irt_isi64(ir->t) ? A64I_FCVT_S64_F32 : A64I_FCVT_U64_F32)) :
- (st == IRT_NUM ?
- (irt_isint(ir->t) ? A64I_FCVT_S32_F64 : A64I_FCVT_U32_F64) :
- (irt_isint(ir->t) ? A64I_FCVT_S32_F32 : A64I_FCVT_U32_F32));
- emit_dn(as, ai, dest, (left & 31));
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
+ if (irt_isu64(ir->t)) {
+ emit_dnm(as, A64I_CSELx | A64F_CC(CC_VC), dest, dest, RID_TMP);
+ emit_n(as, (A64I_CMNx^A64I_K12) | A64F_U12(1), dest);
+ emit_dn(as, st == IRT_NUM ? A64I_FCVT_U64_F64 : A64I_FCVT_U64_F32, RID_TMP, (left & 31));
+ emit_dn(as, st == IRT_NUM ? A64I_FCVT_S64_F64 : A64I_FCVT_S64_F32, dest, (left & 31));
+ } else {
+ A64Ins ai = irt_is64(ir->t) ?
+ (st == IRT_NUM ? A64I_FCVT_S64_F64 : A64I_FCVT_S64_F32) :
+ (st == IRT_NUM ? A64I_FCVT_S32_F64 : A64I_FCVT_S32_F32);
+ emit_dn(as, ai, dest, (left & 31));
+ }
}
} else if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */
Reg dest = ra_dest(as, ir, RSET_GPR);
Reg dest = ra_dest(as, ir, RSET_GPR);
Reg left = ra_alloc1(as, lref, RSET_FPR);
Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left));
- if (irt_isu32(ir->t)) { /* FP to U32 conversion. */
- /* y = (int)floor(x - 2147483648.0) ^ 0x80000000 */
- emit_dst(as, MIPSI_XOR, dest, dest, RID_TMP);
- emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000);
- emit_tg(as, MIPSI_MFC1, dest, tmp);
- emit_fg(as, st == IRT_FLOAT ? MIPSI_FLOOR_W_S : MIPSI_FLOOR_W_D,
- tmp, tmp);
- emit_fgh(as, st == IRT_FLOAT ? MIPSI_SUB_S : MIPSI_SUB_D,
- tmp, left, tmp);
- if (st == IRT_FLOAT)
- emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
- (void *)&as->J->k32[LJ_K32_2P31], RSET_GPR);
- else
- emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
- (void *)&as->J->k64[LJ_K64_2P31], RSET_GPR);
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
#if LJ_64
- } else if (irt_isu64(ir->t)) { /* FP to U64 conversion. */
- MCLabel l_end;
+ if (irt_isu64(ir->t)) { /* FP to U64 conversion. */
+ MCLabel l_end = emit_label(as);
emit_tg(as, MIPSI_DMFC1, dest, tmp);
- l_end = emit_label(as);
- /* For inputs >= 2^63 add -2^64 and convert again. */
+ /* For result == INT64_MAX add -2^64 and convert again. */
if (st == IRT_NUM) {
emit_fg(as, MIPSI_TRUNC_L_D, tmp, tmp);
emit_fgh(as, MIPSI_ADD_D, tmp, left, tmp);
emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
(void *)&as->J->k64[LJ_K64_M2P64],
- rset_exclude(RSET_GPR, dest));
- emit_fg(as, MIPSI_TRUNC_L_D, tmp, left); /* Delay slot. */
-#if !LJ_TARGET_MIPSR6
- emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
- emit_fgh(as, MIPSI_C_OLT_D, 0, left, tmp);
-#else
- emit_branch(as, MIPSI_BC1NEZ, 0, (tmp&31), l_end);
- emit_fgh(as, MIPSI_CMP_LT_D, tmp, left, tmp);
-#endif
- emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
- (void *)&as->J->k64[LJ_K64_2P63],
- rset_exclude(RSET_GPR, dest));
+ rset_exclude(RSET_GPR, dest)); /* Delay slot. */
+ emit_branch(as, MIPSI_BNE, RID_TMP, dest, l_end); /* != INT64_MAX? */
+ emit_dta(as, MIPSI_DSRL, RID_TMP, RID_TMP, 1);
+ emit_ti(as, MIPSI_LI, RID_TMP, -1);
+ emit_tg(as, MIPSI_DMFC1, dest, tmp);
+ emit_fg(as, MIPSI_TRUNC_L_D, tmp, left);
} else {
emit_fg(as, MIPSI_TRUNC_L_S, tmp, tmp);
emit_fgh(as, MIPSI_ADD_S, tmp, left, tmp);
emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
(void *)&as->J->k32[LJ_K32_M2P64],
- rset_exclude(RSET_GPR, dest));
- emit_fg(as, MIPSI_TRUNC_L_S, tmp, left); /* Delay slot. */
-#if !LJ_TARGET_MIPSR6
- emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
- emit_fgh(as, MIPSI_C_OLT_S, 0, left, tmp);
-#else
- emit_branch(as, MIPSI_BC1NEZ, 0, (tmp&31), l_end);
- emit_fgh(as, MIPSI_CMP_LT_S, tmp, left, tmp);
-#endif
- emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
- (void *)&as->J->k32[LJ_K32_2P63],
- rset_exclude(RSET_GPR, dest));
+ rset_exclude(RSET_GPR, dest)); /* Delay slot. */
+ emit_branch(as, MIPSI_BNE, RID_TMP, dest, l_end); /* != INT64_MAX? */
+ emit_dta(as, MIPSI_DSRL, RID_TMP, RID_TMP, 1);
+ emit_ti(as, MIPSI_LI, RID_TMP, -1);
+ emit_tg(as, MIPSI_DMFC1, dest, tmp);
+ emit_fg(as, MIPSI_TRUNC_L_S, tmp, left);
}
+ } else
#endif
- } else {
+ {
#if LJ_32
emit_tg(as, MIPSI_MFC1, dest, tmp);
emit_fg(as, st == IRT_FLOAT ? MIPSI_TRUNC_W_S : MIPSI_TRUNC_W_D,
"bad type for checked CONV");
asm_tointg(as, ir, RID_NONE);
} else {
- IRCallID cid = irt_is64(ir->t) ?
- ((st == IRT_NUM) ?
- (irt_isi64(ir->t) ? IRCALL_fp64_d2l : IRCALL_fp64_d2ul) :
- (irt_isi64(ir->t) ? IRCALL_fp64_f2l : IRCALL_fp64_f2ul)) :
- ((st == IRT_NUM) ?
- (irt_isint(ir->t) ? IRCALL_softfp_d2i : IRCALL_softfp_d2ui) :
- (irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui));
+ IRCallID cid;
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
+ lj_assertA(!(irt_is64(ir->t) && st != IRT_NUM), "bad CONV *64.float emitted");
+ cid = irt_is64(ir->t) ? IRCALL_lj_vm_num2u64 :
+ (st == IRT_NUM ? IRCALL_softfp_d2i : IRCALL_softfp_f2i);
asm_callid(as, ir, cid);
}
} else
}
}
} else {
- if (st64 && !(ir->op2 & IRCONV_NONE)) {
+ if (!irt_isu32(ir->t)) { /* Implicit sign extension. */
+ Reg left = ra_alloc1(as, lref, RSET_GPR);
+ emit_dta(as, MIPSI_SLL, dest, left, 0);
+ } else if (st64 && !(ir->op2 & IRCONV_NONE)) {
/* This is either a 32 bit reg/reg mov which zeroes the hiword
** or a load of the loword from a 64 bit address.
*/
Reg dest = ra_dest(as, ir, RSET_GPR);
Reg left = ra_alloc1(as, lref, RSET_FPR);
Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left));
- if (irt_isu32(ir->t)) {
- /* Convert both x and x-2^31 to int and merge results. */
- Reg tmpi = ra_scratch(as, rset_exclude(RSET_GPR, dest));
- emit_asb(as, PPCI_OR, dest, dest, tmpi); /* Select with mask idiom. */
- emit_asb(as, PPCI_AND, tmpi, tmpi, RID_TMP);
- emit_asb(as, PPCI_ANDC, dest, dest, RID_TMP);
- emit_tai(as, PPCI_LWZ, tmpi, RID_SP, SPOFS_TMPLO); /* tmp = (int)(x) */
- emit_tai(as, PPCI_ADDIS, dest, dest, 0x8000); /* dest += 2^31 */
- emit_asb(as, PPCI_SRAWI, RID_TMP, dest, 31); /* mask = -(dest < 0) */
- emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP);
- emit_tai(as, PPCI_LWZ, dest,
- RID_SP, SPOFS_TMPLO); /* dest = (int)(x-2^31) */
- emit_fb(as, PPCI_FCTIWZ, tmp, left);
- emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP);
- emit_fb(as, PPCI_FCTIWZ, tmp, tmp);
- emit_fab(as, PPCI_FSUB, tmp, left, tmp);
- emit_lsptr(as, PPCI_LFS, (tmp & 31),
- (void *)&as->J->k32[LJ_K32_2P31], RSET_GPR);
- } else {
- emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO);
- emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP);
- emit_fb(as, PPCI_FCTIWZ, tmp, left);
- }
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
+ emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO);
+ emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP);
+ emit_fb(as, PPCI_FCTIWZ, tmp, left);
}
} else
#endif
} else {
Reg dest = ra_dest(as, ir, RSET_GPR);
x86Op op = st == IRT_NUM ? XO_CVTTSD2SI : XO_CVTTSS2SI;
- if (LJ_64 ? irt_isu64(ir->t) : irt_isu32(ir->t)) {
- /* LJ_64: For inputs >= 2^63 add -2^64, convert again. */
- /* LJ_32: For inputs >= 2^31 add -2^31, convert again and add 2^31. */
+ lj_assertA(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
+#if LJ_64
+ if (irt_isu64(ir->t)) {
+ /* For the indefinite result -2^63, add -2^64 and convert again. */
Reg tmp = ra_noreg(IR(lref)->r) ? ra_alloc1(as, lref, RSET_FPR) :
ra_scratch(as, RSET_FPR);
MCLabel l_end = emit_label(as);
- if (LJ_32)
- emit_gri(as, XG_ARITHi(XOg_ADD), dest, (int32_t)0x80000000);
emit_rr(as, op, dest|REX_64, tmp);
if (st == IRT_NUM)
- emit_rma(as, XO_ADDSD, tmp, &as->J->k64[LJ_K64_M2P64_31]);
+ emit_rma(as, XO_ADDSD, tmp, &as->J->k64[LJ_K64_M2P64]);
else
- emit_rma(as, XO_ADDSS, tmp, &as->J->k32[LJ_K32_M2P64_31]);
- emit_sjcc(as, CC_NS, l_end);
- emit_rr(as, XO_TEST, dest|REX_64, dest); /* Check if dest negative. */
+ emit_rma(as, XO_ADDSS, tmp, &as->J->k32[LJ_K32_M2P64]);
+ emit_sjcc(as, CC_NO, l_end);
+ emit_gmrmi(as, XG_ARITHi(XOg_CMP), dest|REX_64, 1);
emit_rr(as, op, dest|REX_64, tmp);
ra_left(as, tmp, lref);
- } else {
- if (LJ_64 && irt_isu32(ir->t))
- emit_rr(as, XO_MOV, dest, dest); /* Zero hiword. */
+
+ } else
+#endif
+ {
emit_mrm(as, op,
- dest|((LJ_64 &&
- (irt_is64(ir->t) || irt_isu32(ir->t))) ? REX_64 : 0),
+ dest|((LJ_64 && irt_is64(ir->t)) ? REX_64 : 0),
asm_fuseload(as, lref, RSET_FPR));
}
}
IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK);
IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH);
Reg lo, hi;
+ int usehi = ra_used(ir);
lj_assertA(st == IRT_NUM || st == IRT_FLOAT, "bad type for CONV");
lj_assertA(dt == IRT_I64 || dt == IRT_U64, "bad type for CONV");
hi = ra_dest(as, ir, RSET_GPR);
emit_gri(as, XG_ARITHi(XOg_AND), lo, 0xf3ff);
}
if (dt == IRT_U64) {
- /* For inputs in [2^63,2^64-1] add -2^64 and convert again. */
+ /* For the indefinite result -2^63, add -2^64 and convert again. */
MCLabel l_pop, l_end = emit_label(as);
emit_x87op(as, XI_FPOP);
l_pop = emit_label(as);
emit_sjmp(as, l_end);
- emit_rmro(as, XO_MOV, hi, RID_ESP, 4);
+ if (usehi) emit_rmro(as, XO_MOV, hi, RID_ESP, 4);
if ((as->flags & JIT_F_SSE3))
emit_rmro(as, XO_FISTTPq, XOg_FISTTPq, RID_ESP, 0);
else
emit_rmro(as, XO_FISTPq, XOg_FISTPq, RID_ESP, 0);
- emit_rma(as, XO_FADDq, XOg_FADDq, &as->J->k64[LJ_K64_M2P64]);
- emit_sjcc(as, CC_NS, l_pop);
- emit_rr(as, XO_TEST, hi, hi); /* Check if out-of-range (2^63). */
- }
- emit_rmro(as, XO_MOV, hi, RID_ESP, 4);
+ emit_rma(as, XO_FADDd, XOg_FADDd, &as->J->k32[LJ_K32_M2P64]);
+ emit_sjcc(as, CC_NE, l_pop);
+ emit_gmroi(as, XG_ARITHi(XOg_CMP), RID_ESP, 0, 0);
+ emit_sjcc(as, CC_NO, l_pop);
+ emit_gmrmi(as, XG_ARITHi(XOg_CMP), hi, 1);
+ usehi = 1;
+ }
+ if (usehi) emit_rmro(as, XO_MOV, hi, RID_ESP, 4);
if ((as->flags & JIT_F_SSE3)) { /* Truncation is easy with SSE3. */
emit_rmro(as, XO_FISTTPq, XOg_FISTTPq, RID_ESP, 0);
} else { /* Otherwise set FPU rounding mode to truncate before the store. */
p = lj_strfmt_wuleb128(p, intV(o));
} else if (tvisnum(o)) {
if (!LJ_DUALNUM && narrow) { /* Narrow number constants to integers. */
- lua_Number num = numV(o);
- int32_t k = lj_num2int(num);
- if (num == (lua_Number)k) { /* -0 is never a constant. */
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(numV(o), i64, k)) { /* -0 is never a constant. */
*p++ = BCDUMP_KTAB_INT;
p = lj_strfmt_wuleb128(p, k);
ctx->sb.w = p;
/* Write a 33 bit ULEB128 for the int (lsb=0) or loword (lsb=1). */
if (!LJ_DUALNUM && o->u32.hi != LJ_KEYINDEX) {
/* Narrow number constants to integers. */
- lua_Number num = numV(o);
- k = lj_num2int(num);
- if (num == (lua_Number)k) { /* -0 is never a constant. */
+ int64_t i64;
+ if (lj_num2int_check(numV(o), i64, k)) { /* -0 is never a constant. */
save_int:
p = lj_strfmt_wuleb128(p, 2*(uint32_t)k | ((uint32_t)k&0x80000000u));
if (k < 0)
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 < 8) {
+ int64_t i = lj_num2i64(n); /* Always convert via int64_t. */
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
+ if ((dinfo & CTF_UNSIGNED))
*(uint64_t *)dp = lj_num2u64(n);
+ else
+ *(int64_t *)dp = lj_num2i64(n);
} else {
goto err_conv; /* NYI: conversion to >64 bit integers. */
}
idx = (ptrdiff_t)intV(key);
goto integer_key;
} else if (tvisnum(key)) { /* Numeric key. */
-#ifdef _MSC_VER
- /* Workaround for MSVC bug. */
- volatile
-#endif
- lua_Number n = numV(key);
- idx = LJ_64 ? (ptrdiff_t)n : (ptrdiff_t)lj_num2int(n);
+ idx = lj_num2int_type(numV(key), ptrdiff_t);
integer_key:
if (ctype_ispointer(ct->info)) {
CTSize sz = lj_ctype_size(cts, ctype_cid(ct->info)); /* Element size. */
/* 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_ANY);
+ conv_I_F:
+#if LJ_SOFTFP || LJ_32
+ if (st == IRT_FLOAT) { /* Uncommon. Simplify split backends. */
+ sp = emitconv(sp, IRT_NUM, IRT_FLOAT, 0);
+ st = IRT_NUM;
+ }
+#endif
+ if (dsize < 8) {
+ lj_needsplit(J);
+ sp = emitconv(sp, IRT_I64, st, IRCONV_ANY);
+ sp = emitconv(sp, dsize < 4 ? IRT_INT : dt, IRT_I64, 0);
+ } else {
+ sp = emitconv(sp, dt, st, IRCONV_ANY);
+ }
goto xstore;
case CCX(I, P):
case CCX(I, A):
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_ANY);
- goto xstore;
+ /* The signed 64 bit conversion is cheaper. */
+ dt = (LJ_64 && dsize == 8) ? IRT_I64 : IRT_U32;
+ goto conv_I_F;
/* Destination is an array. */
case CCX(A, A):
if (J->base[0] && tref_iscdata(J->base[1])) {
tsh = crec_bit64_arg(J, ctype_get(cts, CTID_INT64),
J->base[1], &rd->argv[1]);
- if (!tref_isinteger(tsh))
+ if (LJ_32 && !tref_isinteger(tsh))
tsh = emitconv(tsh, IRT_INT, tref_type(tsh), 0);
J->base[1] = tsh;
}
if (id) {
TRef tr = crec_bit64_arg(J, ctype_get(cts, id), J->base[0], &rd->argv[0]);
uint32_t op = rd->data;
+ IRType t;
if (!tsh) tsh = lj_opt_narrow_tobit(J, J->base[1]);
+ t = tref_isinteger(tsh) ? IRT_INT : tref_type(tsh);
if (!(op < IR_BROL ? LJ_TARGET_MASKSHIFT : LJ_TARGET_MASKROT) &&
!tref_isk(tsh))
- tsh = emitir(IRTI(IR_BAND), tsh, lj_ir_kint(J, 63));
+ tsh = emitir(IRT(IR_BAND, t), tsh, lj_ir_kint(J, 63));
#ifdef LJ_TARGET_UNIFYROT
- if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
- op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
- tsh = emitir(IRTI(IR_NEG), tsh, tsh);
- }
+ if (op == (LJ_TARGET_UNIFYROT == 1 ? IR_BROR : IR_BROL)) {
+ op = LJ_TARGET_UNIFYROT == 1 ? IR_BROL : IR_BROR;
+ tsh = emitir(IRT(IR_NEG, t), tsh, tsh);
+ }
#endif
tr = emitir(IRT(op, id-CTID_INT64+IRT_I64), tr, tsh);
J->base[0] = emitir(IRTG(IR_CNEWI, IRT_CDATA), lj_ir_kint(J, id), tr);
#define LJ_INLINE inline
#define LJ_AINLINE inline __attribute__((always_inline))
#define LJ_NOINLINE __attribute__((noinline))
+#define LJ_CONSTF __attribute__((nothrow,const))
#if defined(__ELF__) || defined(__MACH__) || defined(__psp2__)
#if !((defined(__sun__) && defined(__svr4__)) || defined(__CELLOS_LV2__))
#define LJ_INLINE __inline
#define LJ_AINLINE __forceinline
#define LJ_NOINLINE __declspec(noinline)
+#define LJ_CONSTF __declspec(nothrow noalias)
#if defined(_M_IX86)
#define LJ_FASTCALL __fastcall
#endif
{
if (!lj_strscan_numberobj(o))
lj_trace_err(J, LJ_TRERR_BADTYPE);
- return tvisint(o) ? intV(o) : lj_num2int(numV(o));
+ return numberVint(o);
}
/* Get runtime value of string argument. */
/* Result is integral (or NaN/Inf), but may not fit an int32_t. */
if (LJ_DUALNUM) { /* Try to narrow using a guarded conversion to int. */
lua_Number n = lj_vm_foldfpm(numberVnum(&rd->argv[0]), rd->data);
- if (n == (lua_Number)lj_num2int(n))
+ if (lj_num2int_ok(n))
tr = emitir(IRTGI(IR_CONV), tr, IRCONV_INT_NUM|IRCONV_CHECK);
}
J->base[0] = tr;
return lj_ir_k64(J, IR_KINT64, u64);
}
-/* Check whether a number is int and return it. -0 is NOT considered an int. */
-static int numistrueint(lua_Number n, int32_t *kp)
-{
- int32_t k = lj_num2int(n);
- if (n == (lua_Number)k) {
- if (kp) *kp = k;
- if (k == 0) { /* Special check for -0. */
- TValue tv;
- setnumV(&tv, n);
- if (tv.u32.hi != 0)
- return 0;
- }
- return 1;
- }
- return 0;
-}
-
/* Intern number as int32_t constant if possible, otherwise as FP constant. */
TRef lj_ir_knumint(jit_State *J, lua_Number n)
{
+ int64_t i64;
int32_t k;
- if (numistrueint(n, &k))
+ TValue tv;
+ setnumV(&tv, n);
+ /* -0 is NOT considered an int. */
+ if (lj_num2int_check(n, i64, k) && !tvismzero(&tv))
return lj_ir_kint(J, k);
else
return lj_ir_knum(J, n);
_(SOFTFP_MIPS64, lj_vm_tointg, 1, N, INT, 0) \
_(SOFTFP_FFI, softfp_ui2d, 1, N, NUM, 0) \
_(SOFTFP_FFI, softfp_f2d, 1, N, NUM, 0) \
- _(SOFTFP_FFI, softfp_d2ui, 1, N, INT, XA_FP32) \
_(SOFTFP_FFI, softfp_d2f, 1, N, FLOAT, XA_FP32) \
_(SOFTFP_FFI, softfp_i2f, 1, N, FLOAT, 0) \
_(SOFTFP_FFI, softfp_ui2f, 1, N, FLOAT, 0) \
_(SOFTFP_FFI, softfp_f2i, 1, N, INT, 0) \
- _(SOFTFP_FFI, softfp_f2ui, 1, N, INT, 0) \
_(FP64_FFI, fp64_l2d, 1, N, NUM, XA_64) \
_(FP64_FFI, fp64_ul2d, 1, N, NUM, XA_64) \
_(FP64_FFI, fp64_l2f, 1, N, FLOAT, XA_64) \
_(FP64_FFI, fp64_ul2f, 1, N, FLOAT, XA_64) \
- _(FP64_FFI, fp64_d2l, 1, N, I64, XA_FP) \
- _(FP64_FFI, fp64_d2ul, 1, N, U64, XA_FP) \
- _(FP64_FFI, fp64_f2l, 1, N, I64, 0) \
- _(FP64_FFI, fp64_f2ul, 1, N, U64, 0) \
+ _(FP64_FFI, lj_vm_num2u64, 1, N, U64, XA_FP) \
_(FFI, lj_carith_divi64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_divu64, 2, N, U64, XA2_64|CCI_NOFPRCLOBBER) \
_(FFI, lj_carith_modi64, 2, N, I64, XA2_64|CCI_NOFPRCLOBBER) \
#define softfp_d2i __aeabi_d2iz
#define softfp_ui2d __aeabi_ui2d
#define softfp_f2d __aeabi_f2d
-#define softfp_d2ui __aeabi_d2uiz
#define softfp_d2f __aeabi_d2f
#define softfp_i2f __aeabi_i2f
#define softfp_ui2f __aeabi_ui2f
#define softfp_f2i __aeabi_f2iz
-#define softfp_f2ui __aeabi_f2uiz
#define fp64_l2d __aeabi_l2d
#define fp64_ul2d __aeabi_ul2d
#define fp64_l2f __aeabi_l2f
#define fp64_ul2f __aeabi_ul2f
-#if LJ_TARGET_IOS
-#define fp64_d2l __fixdfdi
-#define fp64_d2ul __fixunsdfdi
-#define fp64_f2l __fixsfdi
-#define fp64_f2ul __fixunssfdi
-#else
-#define fp64_d2l __aeabi_d2lz
-#define fp64_d2ul __aeabi_d2ulz
-#define fp64_f2l __aeabi_f2lz
-#define fp64_f2ul __aeabi_f2ulz
-#endif
#elif LJ_TARGET_MIPS || LJ_TARGET_PPC
#define softfp_add __adddf3
#define softfp_sub __subdf3
#define softfp_d2i __fixdfsi
#define softfp_ui2d __floatunsidf
#define softfp_f2d __extendsfdf2
-#define softfp_d2ui __fixunsdfsi
#define softfp_d2f __truncdfsf2
#define softfp_i2f __floatsisf
#define softfp_ui2f __floatunsisf
#define softfp_f2i __fixsfsi
-#define softfp_f2ui __fixunssfsi
#else
#error "Missing soft-float definitions for target architecture"
#endif
#if LJ_HASFFI
extern double softfp_ui2d(uint32_t a);
extern double softfp_f2d(float a);
-extern uint32_t softfp_d2ui(double a);
extern float softfp_d2f(double a);
extern float softfp_i2f(int32_t a);
extern float softfp_ui2f(uint32_t a);
extern int32_t softfp_f2i(float a);
-extern uint32_t softfp_f2ui(float a);
#endif
#if LJ_TARGET_MIPS
extern double lj_vm_sfmin(double a, double b);
#define fp64_ul2d __floatundidf
#define fp64_l2f __floatdisf
#define fp64_ul2f __floatundisf
-#define fp64_d2l __fixdfdi
-#define fp64_d2ul __fixunsdfdi
-#define fp64_f2l __fixsfdi
-#define fp64_f2ul __fixunssfdi
#else
#error "Missing fp64 helper definitions for this compiler"
#endif
extern double fp64_ul2d(uint64_t a);
extern float fp64_l2f(int64_t a);
extern float fp64_ul2f(uint64_t a);
-extern int64_t fp64_d2l(double a);
-extern uint64_t fp64_d2ul(double a);
-extern int64_t fp64_f2l(float a);
-extern uint64_t fp64_f2ul(float a);
#endif
#endif
};
enum {
+#if LJ_TARGET_X64 || LJ_TARGET_MIPS64
+ LJ_K64_M2P64, /* -2^64 */
+#endif
#if LJ_TARGET_X86ORX64
LJ_K64_TOBIT, /* 2^52 + 2^51 */
LJ_K64_2P64, /* 2^64 */
- LJ_K64_M2P64, /* -2^64 */
-#if LJ_32
- LJ_K64_M2P64_31, /* -2^64 or -2^31 */
-#else
- LJ_K64_M2P64_31 = LJ_K64_M2P64,
#endif
+#if LJ_TARGET_MIPS64
+ LJ_K64_2P63, /* 2^63 */
#endif
#if LJ_TARGET_MIPS
LJ_K64_2P31, /* 2^31 */
-#if LJ_64
- LJ_K64_2P63, /* 2^63 */
- LJ_K64_M2P64, /* -2^64 */
-#endif
#endif
#if LJ_TARGET_ARM64 || LJ_TARGET_MIPS64
LJ_K64_VM_EXIT_HANDLER,
#define LJ_K64__USED (LJ_TARGET_X86ORX64 || LJ_TARGET_ARM64 || LJ_TARGET_MIPS)
enum {
-#if LJ_TARGET_X86ORX64
- LJ_K32_M2P64_31, /* -2^64 or -2^31 */
+#if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS64
+ LJ_K32_M2P64, /* -2^64 */
+#endif
+#if LJ_TARGET_MIPS64
+ LJ_K32_2P63, /* 2^63 */
#endif
#if LJ_TARGET_PPC
LJ_K32_2P52_2P31, /* 2^52 + 2^31 */
LJ_K32_2P52, /* 2^52 */
#endif
-#if LJ_TARGET_PPC || LJ_TARGET_MIPS
+#if LJ_TARGET_PPC
LJ_K32_2P31, /* 2^31 */
#endif
-#if LJ_TARGET_MIPS64
- LJ_K32_2P63, /* 2^63 */
- LJ_K32_M2P64, /* -2^64 */
-#endif
#if LJ_TARGET_PPC || LJ_TARGET_MIPS32
LJ_K32_VM_EXIT_HANDLER,
LJ_K32_VM_EXIT_INTERP,
** integer overflow. Overflow detection still works, since all FPUs
** return either MININT or MAXINT, which is then out of range.
*/
- int32_t i = (int32_t)numV(o);
+ int32_t i = lj_num2int(numV(o));
if (i >= a && i <= b) return i;
#if LJ_HASFFI
} else if (tviscdata(o)) {
if (tvisint(o+i)) {
k[i] = intV(o+i); nint++;
} else {
- k[i] = lj_num2int(numV(o+i)); nint += ((lua_Number)k[i] == numV(o+i));
+ int64_t i64;
+ if (lj_num2int_check(numV(o+i), i64, k[i])) nint++;
}
}
if (nint == 3) { /* Narrow to integers. */
/* -- Number to integer conversion ---------------------------------------- */
-#if LJ_SOFTFP
-LJ_ASMF int32_t lj_vm_tobit(double x);
-#if LJ_TARGET_MIPS64
-LJ_ASMF int32_t lj_vm_tointg(double x);
-#endif
-#endif
+/*
+** The C standard leaves many aspects of FP to integer conversions as
+** undefined behavior. Portability is a mess, hardware support varies,
+** and modern C compilers are like a box of chocolates -- you never know
+** what you're gonna get.
+**
+** However, we need 100% matching behavior between the interpreter (asm + C),
+** optimizations (C) and the code generated by the JIT compiler (asm).
+** Mixing Lua numbers with FFI numbers creates some extra requirements.
+**
+** These conversions have been moved to assembler code, even if they seem
+** trivial, to foil unanticipated C compiler 'optimizations' with the
+** surrounding code. Only the unchecked double to int32_t conversion
+** is still in C, because it ought to be pretty safe -- we'll see.
+**
+** These macros also serve to document all places where FP to integer
+** conversions happen.
+*/
-static LJ_AINLINE int32_t lj_num2bit(lua_Number n)
-{
-#if LJ_SOFTFP
- return lj_vm_tobit(n);
-#else
- TValue o;
- o.n = n + 6755399441055744.0; /* 2^52 + 2^51 */
- return (int32_t)o.u32.lo;
-#endif
-}
+/* Unchecked double to int32_t conversion. */
+#define lj_num2int(n) ((int32_t)(n))
-#define lj_num2int(n) ((int32_t)(n))
+/* Unchecked double to arch/os-dependent signed integer type conversion.
+** This assumes the 32/64-bit signed conversions are NOT range-extended.
+*/
+#define lj_num2int_type(n, tp) ((tp)(n))
-/*
-** This must match the JIT backend behavior. In particular for archs
-** that don't have a common hardware instruction for this conversion.
-** Note that signed FP to unsigned int conversions have an undefined
-** result and should never be relied upon in portable FFI code.
-** See also: C99 or C11 standard, 6.3.1.4, footnote of (1).
+/* Convert a double to int32_t and check for exact conversion.
+** Returns the zero-extended int32_t on success. -0 is OK, too.
+** Returns 0x8000000080000000LL on failure (simplifies range checks).
*/
-static LJ_AINLINE uint64_t lj_num2u64(lua_Number n)
-{
-#if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS
- int64_t i = (int64_t)n;
- if (i < 0) i = (int64_t)(n - 18446744073709551616.0);
- return (uint64_t)i;
-#else
- return (uint64_t)n;
-#endif
-}
+LJ_ASMF LJ_CONSTF int64_t lj_vm_num2int_check(double x);
+
+/* Check for exact conversion only, without storing the result. */
+#define lj_num2int_ok(x) (lj_vm_num2int_check((x)) >= 0)
+
+/* Check for exact conversion and conditionally store result.
+** Note: conditions that fail for 0x80000000 may check only the lower
+** 32 bits. This generates good code for both 32 and 64 bit archs.
+*/
+#define lj_num2int_cond(x, i64, i, cond) \
+ (i64 = lj_vm_num2int_check((x)), cond ? (i = (int32_t)i64, 1) : 0)
+
+/* This is the generic check for a full-range int32_t result. */
+#define lj_num2int_check(x, i64, i) \
+ lj_num2int_cond((x), i64, i, i64 >= 0)
+
+/* Predictable conversion from double to int64_t or uint64_t.
+** Truncates towards zero. Out-of-range values, NaN and +-Inf return
+** an arch-dependent result, but do not cause C undefined behavior.
+** The uint64_t conversion accepts the union of the unsigned + signed range.
+*/
+LJ_ASMF LJ_CONSTF int64_t lj_vm_num2i64(double x);
+LJ_ASMF LJ_CONSTF int64_t lj_vm_num2u64(double x);
+
+#define lj_num2i64(x) (lj_vm_num2i64((x)))
+#define lj_num2u64(x) (lj_vm_num2u64((x)))
+
+/* Lua BitOp conversion semantics use the 2^52 + 2^51 trick. */
+LJ_ASMF LJ_CONSTF int32_t lj_vm_tobit(double x);
+
+#define lj_num2bit(x) lj_vm_tobit((x))
static LJ_AINLINE int32_t numberVint(cTValue *o)
{
return INTFOLD(kfold_intop(fleft->i, fright->i, (IROp)fins->o));
}
+/* Forward declaration. */
+static uint64_t kfold_int64arith(jit_State *J, uint64_t k1, uint64_t k2,
+ IROp op);
+
LJFOLD(ADDOV KINT KINT)
LJFOLD(SUBOV KINT KINT)
LJFOLD(MULOV KINT KINT)
LJFOLDF(kfold_intovarith)
{
- lua_Number n = lj_vm_foldarith((lua_Number)fleft->i, (lua_Number)fright->i,
- fins->o - IR_ADDOV);
- int32_t k = lj_num2int(n);
- if (n != (lua_Number)k)
- return FAILFOLD;
- return INTFOLD(k);
+ int64_t k = kfold_int64arith(J, (int64_t)fleft->i, (int64_t)fright->i,
+ (IROp)((int)fins->o - (int)IR_ADDOV + (int)IR_ADD));
+ return checki32(k) ? INTFOLD(k) : FAILFOLD;
}
LJFOLD(BNOT KINT)
IROp op)
{
UNUSED(J);
-#if LJ_HASFFI
switch (op) {
case IR_ADD: k1 += k2; break;
case IR_SUB: k1 -= k2; break;
case IR_MUL: k1 *= k2; break;
+#if LJ_HASFFI
case IR_BAND: k1 &= k2; break;
case IR_BOR: k1 |= k2; break;
case IR_BXOR: k1 ^= k2; break;
case IR_BROL: k1 = lj_rol(k1, (k2 & 63)); break;
case IR_BROR: k1 = lj_ror(k1, (k2 & 63)); break;
default: lj_assertJ(0, "bad IR op %d", op); break;
- }
-#else
- UNUSED(k2); UNUSED(op);
- lj_assertJ(0, "FFI IR op without FFI");
#endif
+ }
return k1;
}
LJFOLDF(kfold_conv_knum_int_num)
{
lua_Number n = knumleft;
- int32_t k = lj_num2int(n);
- if (irt_isguard(fins->t) && n != (lua_Number)k) {
+ if (irt_isguard(fins->t)) {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(n, i64, k))
+ return INTFOLD(k);
/* We're about to create a guard which always fails, like CONV +1.5.
** Some pathological loops cause this during LICM, e.g.:
** local x,k,t = 0,1.5,{1,[1.5]=2}
** assert(x == 300)
*/
return FAILFOLD;
+ } else {
+ return INTFOLD(lj_num2int(n));
}
- return INTFOLD(k);
-}
-
-LJFOLD(CONV KNUM IRCONV_U32_NUM)
-LJFOLDF(kfold_conv_knum_u32_num)
-{
-#ifdef _MSC_VER
- { /* Workaround for MSVC bug. */
- volatile uint32_t u = (uint32_t)knumleft;
- return INTFOLD((int32_t)u);
- }
-#else
- return INTFOLD((int32_t)(uint32_t)knumleft);
-#endif
}
LJFOLD(CONV KNUM IRCONV_I64_NUM)
LJFOLDF(kfold_conv_knum_i64_num)
{
- return INT64FOLD((uint64_t)(int64_t)knumleft);
+ return INT64FOLD((uint64_t)lj_num2i64(knumleft));
}
LJFOLD(CONV KNUM IRCONV_U64_NUM)
}
LJFOLD(CONV CONV IRCONV_INT_NUM) /* _INT */
-LJFOLD(CONV CONV IRCONV_U32_NUM) /* _U32 */
LJFOLDF(simplify_conv_int_num)
{
/* Fold even across PHI to avoid expensive num->int conversions in loop. */
return lj_opt_narrow_convert(J);
}
+LJFOLD(XSTORE any CONV)
+LJFOLDF(xstore_conv)
+{
+#if LJ_64
+ PHIBARRIER(fright);
+ if (!irt_is64(fins->t) &&
+ irt_type(fins->t) == (IRType)((fright->op2&IRCONV_DSTMASK)>>IRCONV_DSH) &&
+ ((fright->op2&IRCONV_SRCMASK) == IRT_I64 ||
+ (fright->op2&IRCONV_SRCMASK) == IRT_U64)) {
+ fins->op2 = fright->op1;
+ return RETRYFOLD;
+ }
+#else
+ UNUSED(J);
+#endif
+ return NEXTFOLD;
+}
+
/* -- Integer algebraic simplifications ----------------------------------- */
LJFOLD(ADD any KINT)
return 0;
} else if (ir->o == IR_KNUM) { /* Narrow FP constant. */
lua_Number n = ir_knum(ir)->n;
+ int64_t i64;
+ int32_t k;
if ((nc->mode & IRCONV_CONVMASK) == IRCONV_TOBIT) {
- /* Allows a wider range of constants. */
- int64_t k64 = (int64_t)n;
- if (n == (lua_Number)k64) { /* Only if const doesn't lose precision. */
- *nc->sp++ = NARROWINS(NARROW_INT, 0);
- *nc->sp++ = (NarrowIns)k64; /* But always truncate to 32 bits. */
- return 0;
- }
- } else {
- int32_t k = lj_num2int(n);
- /* Only if constant is a small integer. */
- if (checki16(k) && n == (lua_Number)k) {
+ /* Allows a wider range of constants, if const doesn't lose precision. */
+ if (lj_num2int_check(n, i64, k)) {
*nc->sp++ = NARROWINS(NARROW_INT, 0);
*nc->sp++ = (NarrowIns)k;
return 0;
}
+ } else if (lj_num2int_cond(n, i64, k, checki16((int32_t)i64))) {
+ /* Only if constant is a small integer. */
+ *nc->sp++ = NARROWINS(NARROW_INT, 0);
+ *nc->sp++ = (NarrowIns)k;
+ return 0;
}
return 10; /* Never narrow other FP constants (this is rare). */
}
/* -- Narrowing of arithmetic operators ----------------------------------- */
-/* Check whether a number fits into an int32_t (-0 is ok, too). */
-static int numisint(lua_Number n)
-{
- return (n == (lua_Number)lj_num2int(n));
-}
-
/* Convert string to number. Error out for non-numeric string values. */
static TRef conv_str_tonum(jit_State *J, TRef tr, TValue *o)
{
/* Must not narrow MUL in non-DUALNUM variant, because it loses -0. */
if ((op >= IR_ADD && op <= (LJ_DUALNUM ? IR_MUL : IR_SUB)) &&
tref_isinteger(rb) && tref_isinteger(rc) &&
- numisint(lj_vm_foldarith(numberVnum(vb), numberVnum(vc),
- (int)op - (int)IR_ADD)))
+ lj_num2int_ok(lj_vm_foldarith(numberVnum(vb), numberVnum(vc),
+ (int)op - (int)IR_ADD)))
return emitir(IRTGI((int)op - (int)IR_ADD + (int)IR_ADDOV), rb, rc);
if (!tref_isnum(rb)) rb = emitir(IRTN(IR_CONV), rb, IRCONV_NUM_INT);
if (!tref_isnum(rc)) rc = emitir(IRTN(IR_CONV), rc, IRCONV_NUM_INT);
static int narrow_forl(jit_State *J, cTValue *o)
{
if (tvisint(o)) return 1;
- if (LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) return numisint(numV(o));
+ if (LJ_DUALNUM || (J->flags & JIT_F_OPT_NARROW)) return lj_num2int_ok(numV(o));
return 0;
}
case IR_CONV: { /* Conversion to 64 bit integer. Others handled below. */
IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK);
#if LJ_SOFTFP
+ lj_assertJ(st != IRT_FLOAT, "bad CONV *64.float emitted");
if (st == IRT_NUM) { /* NUM to 64 bit int conv. */
- hi = split_call_l(J, hisubst, oir, ir,
- irt_isi64(ir->t) ? IRCALL_fp64_d2l : IRCALL_fp64_d2ul);
- } else if (st == IRT_FLOAT) { /* FLOAT to 64 bit int conv. */
- nir->o = IR_CALLN;
- nir->op2 = irt_isi64(ir->t) ? IRCALL_fp64_f2l : IRCALL_fp64_f2ul;
- hi = split_emit(J, IRTI(IR_HIOP), nref, nref);
+ hi = split_call_l(J, hisubst, oir, ir, IRCALL_lj_vm_num2u64);
}
#else
if (st == IRT_NUM || st == IRT_FLOAT) { /* FP to 64 bit int conv. */
nir->op2 = st == IRT_INT ? IRCALL_softfp_i2f : IRCALL_softfp_ui2f;
}
} else if (st == IRT_FLOAT) {
+ lj_assertJ(!irt_isu32(ir->t), "bad CONV u32.fp emitted");
nir->o = IR_CALLN;
- nir->op2 = irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui;
+ nir->op2 = IRCALL_softfp_f2i;
} else
#endif
#if LJ_SOFTFP
} else {
split_call_l(J, hisubst, oir, ir,
#if LJ_32 && LJ_HASFFI
- st == IRT_NUM ?
- (irt_isint(ir->t) ? IRCALL_softfp_d2i : IRCALL_softfp_d2ui) :
- (irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui)
+ st == IRT_NUM ? IRCALL_softfp_d2i : IRCALL_softfp_f2i
#else
IRCALL_softfp_d2i
#endif
ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)intV(tv));
else
#else
- lua_Number n = expr_numberV(e);
- int32_t k = lj_num2int(n);
- if (checki16(k) && n == (lua_Number)k)
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_cond(expr_numberV(e), i64, k, checki16((int32_t)i64)))
ins = BCINS_AD(BC_KSHORT, reg, (BCReg)(uint16_t)k);
else
#endif
setnumV(&o, n);
if (tvisnan(&o) || tvismzero(&o)) return 0; /* Avoid NaN and -0 as consts. */
if (LJ_DUALNUM) {
- int32_t k = lj_num2int(n);
- if ((lua_Number)k == n) {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(n, i64, k)) {
setintV(&e1->u.nval, k);
return 1;
}
if (tvisnum(&n->key)) {
TValue *tv = &((TValue *)kptr)[kidx];
if (LJ_DUALNUM) {
- lua_Number nn = numV(&n->key);
- int32_t k = lj_num2int(nn);
+ int64_t i64;
+ int32_t k;
lj_assertFS(!tvismzero(&n->key), "unexpected -0 key");
- if ((lua_Number)k == nn)
+ if (lj_num2int_check(numV(&n->key), i64, k))
setintV(tv, k);
else
*tv = n->key;
}
}
#else
- lua_Number n = expr_numberV(e);
- int32_t k = lj_num2int(n);
- if (checku8(k) && n == (lua_Number)k) {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_cond(expr_numberV(e), i64, k, checku8((int32_t)i64))) {
t->u.s.aux = BCMAX_C+1+(uint32_t)k; /* 256..511: const byte key */
return;
}
} else {
cTValue *tv = proto_knumtv(J->pt, bc_d(ins));
if (t == IRT_INT) {
- int32_t k = numberVint(tv);
- if (tvisint(tv) || numV(tv) == (lua_Number)k) /* -0 is ok here. */
- return lj_ir_kint(J, k);
+ if (tvisint(tv)) {
+ return lj_ir_kint(J, intV(tv));
+ } else {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(numV(tv), i64, k)) /* -0 is ok here. */
+ return lj_ir_kint(J, k);
+ }
return 0; /* Type mismatch. */
} else {
return lj_ir_knum(J, numberVnum(tv));
/* Integer keys are looked up in the array part first. */
key = ix->key;
if (tref_isnumber(key)) {
- int32_t k = numberVint(&ix->keyv);
- if (!tvisint(&ix->keyv) && numV(&ix->keyv) != (lua_Number)k)
- k = LJ_MAX_ASIZE;
+ int32_t k;
+ if (tvisint(&ix->keyv)) {
+ k = intV(&ix->keyv);
+ } else {
+ int64_t i64;
+ if (!lj_num2int_check(numV(&ix->keyv), i64, k)) k = LJ_MAX_ASIZE;
+ }
if ((MSize)k < LJ_MAX_ASIZE) { /* Potential array key? */
TRef ikey = lj_opt_narrow_index(J, key);
TRef asizeref = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_ASIZE);
/* Add number formatted as signed integer to buffer. */
SBuf *lj_strfmt_putfnum_int(SBuf *sb, SFormat sf, lua_Number n)
{
- int64_t k = (int64_t)n;
+ int64_t k = lj_num2i64(n);
if (checki32(k) && sf == STRFMT_INT)
return lj_strfmt_putint(sb, (int32_t)k); /* Shortcut for plain %d. */
else
/* Add number formatted as unsigned integer to buffer. */
SBuf *lj_strfmt_putfnum_uint(SBuf *sb, SFormat sf, lua_Number n)
{
- int64_t k;
- if (n >= 9223372036854775808.0)
- k = (int64_t)(n - 18446744073709551616.0);
- else
- k = (int64_t)n;
- return lj_strfmt_putfxint(sb, sf, (uint64_t)k);
+ return lj_strfmt_putfxint(sb, sf, lj_num2u64(n));
}
/* Format stack arguments to buffer. */
fmt = strscan_dec(sp, o, fmt, opt, ex, neg, dig);
/* Try to convert number to integer, if requested. */
- if (fmt == STRSCAN_NUM && (opt & STRSCAN_OPT_TOINT) && !tvismzero(o)) {
- double n = o->n;
- int32_t i = lj_num2int(n);
- if (n == (lua_Number)i) { o->i = i; return STRSCAN_INT; }
+ if (fmt == STRSCAN_NUM && (opt & STRSCAN_OPT_TOINT)) {
+ int64_t tmp;
+ if (lj_num2int_check(o->n, tmp, o->i) && !tvismzero(o))
+ return STRSCAN_INT;
}
return fmt;
}
{
lj_assertX(!tvisint(key), "bad integer key");
if (tvisnum(key)) {
- lua_Number nk = numV(key);
- int32_t k = lj_num2int(nk);
- if ((uint32_t)k < LJ_MAX_ASIZE && nk == (lua_Number)k) {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_cond(numV(key), i64, k, (uint32_t)i64 < LJ_MAX_ASIZE)) {
bins[(k > 2 ? lj_fls((uint32_t)(k-1)) : 0)]++;
return 1;
}
if (tv)
return tv;
} else if (tvisnum(key)) {
- lua_Number nk = numV(key);
- int32_t k = lj_num2int(nk);
- if (nk == (lua_Number)k) {
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(numV(key), i64, k)) {
cTValue *tv = lj_tab_getint(t, k);
if (tv)
return tv;
} else if (tvisint(key)) {
return lj_tab_setint(L, t, intV(key));
} else if (tvisnum(key)) {
- lua_Number nk = numV(key);
- int32_t k = lj_num2int(nk);
- if (nk == (lua_Number)k)
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_check(numV(key), i64, k))
return lj_tab_setint(L, t, k);
if (tvisnan(key))
lj_err_msg(L, LJ_ERR_NANIDX);
setnumV(&tmp, (lua_Number)k);
key = &tmp;
} else if (tvisnum(key)) {
- lua_Number nk = numV(key);
- int32_t k = lj_num2int(nk);
- if ((uint32_t)k < t->asize && nk == (lua_Number)k)
+ int64_t i64;
+ int32_t k;
+ if (lj_num2int_cond(numV(key), i64, k, (uint32_t)i64 < t->asize))
return (uint32_t)k + 1;
}
if (!tvisnil(key)) {
XO_FSTPq = XO_(dd), XOg_FSTPq = 3,
XO_FISTPq = XO_(df), XOg_FISTPq = 7,
XO_FISTTPq = XO_(dd), XOg_FISTTPq = 1,
+ XO_FADDd = XO_(d8), XOg_FADDd = 0,
XO_FADDq = XO_(dc), XOg_FADDq = 0,
XO_FLDCW = XO_(d9), XOg_FLDCW = 5,
XO_FNSTCW = XO_(d9), XOg_FNSTCW = 7
tv[1].u64 = U64x(80000000,00000000);
/* Initialize 32/64 bit constants. */
+#if LJ_TARGET_X64 || LJ_TARGET_MIPS64
+ J->k64[LJ_K64_M2P64].u64 = U64x(c3f00000,00000000);
+#endif
#if LJ_TARGET_X86ORX64
J->k64[LJ_K64_TOBIT].u64 = U64x(43380000,00000000);
-#if LJ_32
- J->k64[LJ_K64_M2P64_31].u64 = U64x(c1e00000,00000000);
-#endif
J->k64[LJ_K64_2P64].u64 = U64x(43f00000,00000000);
- J->k32[LJ_K32_M2P64_31] = LJ_64 ? 0xdf800000 : 0xcf000000;
#endif
+#if LJ_TARGET_MIPS64
+ J->k64[LJ_K64_2P63].u64 = U64x(43e00000,00000000);
+#endif
+#if LJ_TARGET_MIPS
+ J->k64[LJ_K64_2P31].u64 = U64x(41e00000,00000000);
+#endif
+
#if LJ_TARGET_X86ORX64 || LJ_TARGET_MIPS64
- J->k64[LJ_K64_M2P64].u64 = U64x(c3f00000,00000000);
+ J->k32[LJ_K32_M2P64] = 0xdf800000;
+#endif
+#if LJ_TARGET_MIPS64
+ J->k32[LJ_K32_2P63] = 0x5f000000;
#endif
#if LJ_TARGET_PPC
J->k32[LJ_K32_2P52_2P31] = 0x59800004;
J->k32[LJ_K32_2P52] = 0x59800000;
#endif
-#if LJ_TARGET_PPC || LJ_TARGET_MIPS
+#if LJ_TARGET_PPC
J->k32[LJ_K32_2P31] = 0x4f000000;
#endif
-#if LJ_TARGET_MIPS
- J->k64[LJ_K64_2P31].u64 = U64x(41e00000,00000000);
-#if LJ_64
- J->k64[LJ_K64_2P63].u64 = U64x(43e00000,00000000);
- J->k32[LJ_K32_2P63] = 0x5f000000;
- J->k32[LJ_K32_M2P64] = 0xdf800000;
-#endif
-#endif
+
#if LJ_TARGET_PPC || LJ_TARGET_MIPS32
J->k32[LJ_K32_VM_EXIT_HANDLER] = (uintptr_t)(void *)lj_vm_exit_handler;
J->k32[LJ_K32_VM_EXIT_INTERP] = (uintptr_t)(void *)lj_vm_exit_interp;
#if LJ_TARGET_PPC
void lj_vm_cachesync(void *start, void *end);
#endif
-LJ_ASMF double lj_vm_foldarith(double x, double y, int op);
+LJ_ASMF LJ_CONSTF double lj_vm_foldarith(double x, double y, int op);
#if LJ_HASJIT
-LJ_ASMF double lj_vm_foldfpm(double x, int op);
+LJ_ASMF LJ_CONSTF double lj_vm_foldfpm(double x, int op);
#endif
-#if !LJ_ARCH_HASFPU
-/* Declared in lj_obj.h: LJ_ASMF int32_t lj_vm_tobit(double x); */
+#if LJ_SOFTFP && LJ_TARGET_MIPS64
+LJ_ASMF LJ_CONSTF int32_t lj_vm_tointg(double x);
#endif
+/* Declared in lj_obj.h:
+** LJ_ASMF LJ_CONSTF int64_t lj_vm_num2int_check(double x);
+** LJ_ASMF LJ_CONSTF int64_t lj_vm_num2i64(double x);
+** LJ_ASMF LJ_CONSTF uint64_t lj_vm_num2u64(double x);
+** LJ_ASMF LJ_CONSTF int32_t lj_vm_tobit(double x);
+*/
/* Dispatch targets for recording and hooks. */
LJ_ASMF void lj_vm_record(void);
#define lj_vm_floor floor
#define lj_vm_ceil ceil
#else
-LJ_ASMF double lj_vm_floor(double);
-LJ_ASMF double lj_vm_ceil(double);
+LJ_ASMF LJ_CONSTF double lj_vm_floor(double);
+LJ_ASMF LJ_CONSTF double lj_vm_ceil(double);
#if LJ_TARGET_ARM
-LJ_ASMF double lj_vm_floor_sf(double);
-LJ_ASMF double lj_vm_ceil_sf(double);
+LJ_ASMF LJ_CONSTF double lj_vm_floor_sf(double);
+LJ_ASMF LJ_CONSTF double lj_vm_ceil_sf(double);
#endif
#endif
#ifdef LUAJIT_NO_LOG2
-LJ_ASMF double lj_vm_log2(double);
+LJ_ASMF LJ_CONSTF double lj_vm_log2(double);
#else
#define lj_vm_log2 log2
#endif
#if LJ_HASJIT
#if LJ_TARGET_X86ORX64
-LJ_ASMF void lj_vm_floor_sse(void);
-LJ_ASMF void lj_vm_ceil_sse(void);
-LJ_ASMF void lj_vm_trunc_sse(void);
+LJ_ASMF LJ_CONSTF void lj_vm_floor_sse(void);
+LJ_ASMF LJ_CONSTF void lj_vm_ceil_sse(void);
+LJ_ASMF LJ_CONSTF void lj_vm_trunc_sse(void);
#endif
#if LJ_TARGET_PPC || LJ_TARGET_ARM64
#define lj_vm_trunc trunc
#else
-LJ_ASMF double lj_vm_trunc(double);
+LJ_ASMF LJ_CONSTF double lj_vm_trunc(double);
#if LJ_TARGET_ARM
-LJ_ASMF double lj_vm_trunc_sf(double);
+LJ_ASMF LJ_CONSTF double lj_vm_trunc_sf(double);
#endif
#endif
#if LJ_HASFFI
case IR_NEG - IR_ADD: return -x; break;
case IR_ABS - IR_ADD: return fabs(x); break;
#if LJ_HASJIT
- case IR_LDEXP - IR_ADD: return ldexp(x, (int)y); break;
+ case IR_LDEXP - IR_ADD: return ldexp(x, lj_num2int(y)); break;
case IR_MIN - IR_ADD: return x < y ? x : y; break;
case IR_MAX - IR_ADD: return x > y ? x : y; break;
#endif
| bx lr
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ |.if FPU
+ |.if not HFABI
+ | vmov d0, CARG1, CARG2
+ |.endif
+ | vcvt.s32.f64 s4, d0
+ | vcvt.f64.s32 d1, s4
+ | vcmp.f64 d0, d1
+ | vmrs
+ | bne >1
+ | vmov CRET1, s4
+ | mov CRET2, #0
+ | bx lr
+ |
+ |.else
+ |
+ | asr CARG4, CARG2, #31 // sign = 0 or -1.
+ | lsl CARG2, CARG2, #1
+ | orrs RB, CARG2, CARG1
+ | bxeq lr // Return 0 for +-0.
+ | mov RB, #1024
+ | add RB, RB, #30
+ | sub RB, RB, CARG2, lsr #21
+ | cmp RB, #32
+ | bhs >1 // Fail if |x| < 0x1p0 || |x| >= 0x1p32.
+ | lsr CARG3, CARG1, #21
+ | orr CARG2, CARG3, CARG2, lsl #10 // Left-aligned mantissa.
+ | rsb CARG3, RB, #32
+ | lsl CARG3, CARG2, CARG3
+ | orr CARG2, CARG2, #0x80000000 // Merge leading 1.
+ | orrs CARG3, CARG3, CARG1, lsl #11
+ | lsr CARG1, CARG2, RB // lo = right-aligned absolute value.
+ | bne >1 // Fail if fractional part != 0.
+ | adds CRET1, CARG1, CARG4
+ | bmi >1 // Fail if lo+sign >= 0x80000000.
+ | eor CRET1, CRET1, CARG4 // lo = sign?-lo:lo = (lo+sign)^sign.
+ | mov CRET2, #0
+ | bx lr
+ |.endif
+ |1:
+ | mov CRET1, #0x80000000
+ | mov CRET2, #0x80000000
+ | bx lr
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ |// fallthrough, same as lj_vm_num2u64.
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ |.if HFABI
+ | vmov CARG1, CARG2, d0
+ |.endif
+ | lsl RB, CARG2, #1
+ | lsr RB, RB, #21
+ | sub RB, RB, #1020
+ | sub RB, RB, #3
+ | cmp RB, #116
+ | bhs >3 // Exponent out of range.
+ | asr CARG4, CARG2, #31 // sign = 0 or -1.
+ | lsl CARG2, CARG2, #12
+ | lsr CARG2, CARG2, #12
+ | rsbs RB, RB, #52
+ | orr CARG2, CARG2, #0x00100000
+ | bmi >2 // Shift mantissa left or right?
+ | lsr CARG1, CARG1, RB // 64 bit right shift.
+ | lsr CARG3, CARG2, RB
+ | rsb RB, RB, #32
+ | orr CARG1, CARG1, CARG2, lsl RB
+ | rsb RB, RB, #0
+ | orr CARG1, CARG1, CARG2, lsr RB
+ | adds CRET1, CARG1, CARG4 // m = sign?-m:m = (m+sign)^sign.
+ | adc CRET2, CARG3, CARG4
+ |1:
+ | eor CRET1, CRET1, CARG4
+ | eor CRET2, CRET2, CARG4
+ | bx lr
+ |2:
+ | rsb RB, RB, #0
+ | lsl CARG2, CARG2, RB // 64 bit left shift.
+ | lsl CARG3, CARG1, RB
+ | sub RB, RB, #32
+ | orr CARG2, CARG2, CARG1, lsl RB
+ | rsb RB, RB, #0
+ | orr CARG2, CARG2, CARG1, lsr RB
+ | adds CRET1, CARG3, CARG4
+ | adc CRET2, CARG2, CARG4
+ | b <1
+ |3:
+ | mov CRET1, #0
+ | mov CRET2, #0
+ | bx lr
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |.if FPU
+ |->vm_tobit:
+ | vldr d1, >9
+ |.if not HFABI
+ | vmov d0, CARG1, CARG2
+ |.endif
+ | vadd.f64 d0, d0, d1
+ | vmov CARG1, s0
+ | bx lr
+ |9:
+ | .long 0, 0x43380000 // (double)(2^52 + 2^51).
+ |.endif
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
| ldr TRACE:CARG1, [CARG1, CARG2, lsl #2]
| // Subsumes ins_next1 and ins_next2.
| ldr INS, TRACE:CARG1->startins
- | bfi INS, OP, #0, #8
+ | bic INS, INS, #0xff
+ | orr INS, INS, OP
| str INS, [PC], #4
| b <1
|.endif
| ret
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ | fcvtzs CRET1w, FARG1
+ | scvtf FARG2, CRET1w
+ | fcmp FARG2, FARG1
+ | bne >1
+ | ret
+ |1:
+ | mov CRET1, #0x8000000080000000
+ | ret
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ | fcvtzs CRET1, FARG1
+ | ret
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ | fcvtzs CRET1, FARG1
+ | fcvtzu CARG2, FARG1
+ | cmn CRET1, #1 // Set overflow if CRET1 == INT64_MAX.
+ | csel CRET1, CRET1, CARG2, vc // No overflow ? i64 : u64.
+ | ret
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |->vm_tobit:
+ | movz CRET1, #0x4338, lsl #48 // 2^52 + 2^51.
+ | fmov FARG2, CRET1
+ | fadd FARG1, FARG1, FARG2
+ | fmov CRET1w, s0
+ | ret
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
|
|.if FPU
|.define FARG1, f12
+|.define FARG1HI, f13
|.define FARG2, f14
|
|.define FRET1, f0
| mtc1 r0, f4
| mtc1 TMP0, f5
| abs.d FRET2, FARG1 // |x|
- | mfc1 AT, f13
+ | mfc1 AT, FARG1HI
| c.olt.d 0, FRET2, f4
| add.d FRET1, FRET2, f4 // (|x| + 2^52) - 2^52
| bc1f 0, >1 // Truncate only if |x| < 2^52.
| sfmin_max max, vm_sfcmpogt
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ |.if FPU
+ | trunc.w.d FARG2, FARG1
+ | mfc1 SFRETLO, FARG2
+ | cvt.d.w FARG2, FARG2
+ | c.eq.d FARG1, FARG2
+ | bc1f 0, >2
+ |. nop
+ | jr ra
+ |. move SFRETHI, r0
+ |
+ |.else
+ |
+ | sll SFRETLO, SFARG1HI, 1
+ | or SFRETHI, SFRETLO, SFARG1LO
+ | beqz SFRETHI, >1 // Return 0 for +-0.
+ |. li TMP0, 1054
+ | srl AT, SFRETLO, 21
+ | subu TMP0, TMP0, AT
+ | sltiu AT, TMP0, 32
+ | beqz AT, >2 // Fail if |x| < 0x1p0 || |x| >= 0x1p32.
+ |. sll SFRETLO, SFARG1HI, 11
+ | srl SFRETHI, SFARG1LO, 21
+ | negu TMP1, TMP0
+ | or SFRETLO, SFRETLO, SFRETHI // Left-aligned mantissa.
+ | sllv TMP2, SFRETLO, TMP1
+ | lui AT, 0x8000
+ | sll SFRETHI, SFARG1LO, 11
+ | or SFRETLO, SFRETLO, AT // Merge leading 1.
+ | or TMP2, TMP2, SFRETHI
+ | srlv SFRETLO, SFRETLO, TMP0 // lo = right-aligned absolute value.
+ | bnez TMP2, >2 // Fail if fractional part != 0.
+ |. sra SFARG1HI, SFARG1HI, 31 // sign = 0 or -1.
+ | addu SFRETLO, SFRETLO, SFARG1HI
+ | bltz SFRETLO, >2 // Fail if lo+sign >= 0x80000000.
+ |. xor SFRETLO, SFRETLO, SFARG1HI // lo = sign?-lo:lo = (lo+sign)^sign.
+ |1:
+ | jr ra
+ |. move SFRETHI, r0
+ |.endif
+ |2: // Not an integer, return 0x8000000080000000LL.
+ | lui SFRETHI, 0x8000
+ | jr ra
+ |. lui SFRETLO, 0x8000
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ |// fallthrough, same as lj_vm_num2u64.
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ |.if FPU
+ | mfc1 SFARG1HI, FARG1HI
+ | mfc1 SFARG1LO, FARG1
+ |.endif
+ | srl TMP0, SFARG1HI, 20
+ | andi TMP0, TMP0, 0x7ff
+ | addiu SFRETLO, TMP0, -1023
+ | sltiu SFRETLO, SFRETLO, 116
+ | beqz SFRETLO, >3 // Exponent out of range.
+ |. sll SFRETHI, SFARG1HI, 12
+ | lui AT, 0x0010
+ | srl SFRETHI, SFRETHI, 12
+ | addiu TMP0, TMP0, -1075
+ | sra SFARG1HI, SFARG1HI, 31 // sign = 0 or -1.
+ | bgez TMP0, >2 // Shift mantissa left or right?
+ |. or SFRETHI, SFRETHI, AT // Merge leading 1 into masked mantissa.
+ | subu TMP1, r0, TMP0
+ | sll AT, SFRETHI, 1
+ | nor TMP0, r0, TMP1
+ | srlv SFRETHI, SFRETHI, TMP1 // Shift hi mantissa right for low exp.
+ | sllv AT, AT, TMP0 // Shifted-out hi mantissa.
+ | srlv SFRETLO, SFARG1LO, TMP1 // Shift lo mantissa right for low exp.
+ | andi TMP1, TMP1, 0x20 // Conditional right shift by 32.
+ | or AT, AT, SFRETLO // Merge into lo mantissa.
+ | movn AT, SFRETHI, TMP1
+ | movn SFRETHI, r0, TMP1
+ |1:
+ | addu SFRETLO, AT, SFARG1HI // m = sign?-m:m = (m+sign)^sign.
+ | addu SFRETHI, SFRETHI, SFARG1HI
+ | sltu TMP0, SFRETLO, AT // Carry
+ | addu SFRETHI, SFRETHI, TMP0
+ | xor SFRETLO, SFRETLO, SFARG1HI
+ | jr ra
+ |. xor SFRETHI, SFRETHI, SFARG1HI
+ |2:
+ | srl TMP2, SFARG1LO, 1
+ | nor AT, r0, TMP0
+ | sllv SFRETHI, SFRETHI, TMP0 // Shift hi mantissa left for high exp.
+ | srlv TMP2, TMP2, AT // Shifted-out lo mantissa.
+ | sllv AT, SFARG1LO, TMP0 // Shift lo mantissa left for high exp.
+ | andi TMP0, TMP0, 0x20 // Conditional left shift by 32.
+ | or SFRETHI, SFRETHI, TMP2 // Merge into hi mantissa.
+ | movn SFRETHI, AT, TMP0
+ | b <1
+ |. movn AT, r0, TMP0
+ |3:
+ | jr ra
+ |. li SFRETHI, 0
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |.if FPU
+ |->vm_tobit:
+ | lui AT, 0x59c0 // 2^52 + 2^51 (float).
+ | mtc1 AT, FARG2
+ | cvt.d.s FARG2, FARG2
+ | add.d FARG1, FARG1, FARG2
+ | jr ra
+ |. mfc1 CRET1, FARG1
+ |.endif
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
| dinsu CRET2, AT, 21, 21
| slt AT, CARG1, r0
| dsrlv CRET1, CRET2, TMP0
- | dsubu CARG1, r0, CRET1
+ | negu CARG1, CRET1
|.if MIPSR6
| seleqz CRET1, CRET1, AT
| selnez CARG1, CARG1, AT
|.else
| movn CRET1, CARG1, AT
|.endif
- | li CARG1, 64
- | subu TMP0, CARG1, TMP0
+ | negu TMP0, TMP0
| dsllv CRET2, CRET2, TMP0 // Integer check.
| sextw AT, CRET1
| xor AT, CRET1, AT // Range check.
- |.if MIPSR6
- | seleqz AT, AT, CRET2
- | selnez CRET2, CRET2, CRET2
| jr ra
|. or CRET2, AT, CRET2
- |.else
- | jr ra
- |. movz CRET2, AT, CRET2
- |.endif
|1:
| jr ra
|. li CRET2, 1
| sfmin_max max, vm_sfcmpogt
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ |.if FPU
+ | trunc.w.d FARG2, FARG1
+ | mfc1 CRET1, FARG2
+ | cvt.d.w FARG2, FARG2
+ |.if MIPSR6
+ | cmp.eq.d FARG2, FARG1, FARG2
+ | bc1eqz FARG2, >2
+ |.else
+ | c.eq.d FARG1, FARG2
+ | bc1f 0, >2
+ |.endif
+ |. nop
+ | jr ra
+ |. zextw CRET1, CRET1
+ |
+ |.else
+ |
+ | dsll CRET2, CARG1, 1
+ | beqz CRET2, >1
+ |. li TMP0, 1076
+ | dsrl AT, CRET2, 53
+ | dsubu TMP0, TMP0, AT
+ | sltiu AT, TMP0, 54
+ | beqz AT, >2
+ |. dextm CRET2, CRET2, 0, 20
+ | dinsu CRET2, AT, 21, 21
+ | slt AT, CARG1, r0
+ | dsrlv CRET1, CRET2, TMP0
+ | negu CARG1, CRET1
+ |.if MIPSR6
+ | seleqz CRET1, CRET1, AT
+ | selnez CARG1, CARG1, AT
+ | or CRET1, CRET1, CARG1
+ |.else
+ | movn CRET1, CARG1, AT
+ |.endif
+ | negu TMP0, TMP0
+ | dsllv CRET2, CRET2, TMP0 // Integer check.
+ | sextw AT, CRET1
+ | xor AT, CRET1, AT // Range check.
+ | or AT, AT, CRET2
+ | bnez AT, >2
+ |. nop
+ | jr ra
+ |. zextw CRET1, CRET1
+ |1:
+ | jr ra
+ |. move CRET1, r0
+ |.endif
+ |2:
+ | lui CRET1, 0x8000
+ | dsll CRET1, CRET1, 16
+ | ori CRET1, CRET1, 0x8000
+ | jr ra
+ |. dsll CRET1, CRET1, 16
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ |.if FPU
+ | trunc.l.d FARG1, FARG1
+ | jr ra
+ |. dmfc1 CRET1, FARG1
+ |.else
+ |// fallthrough, same as lj_vm_num2u64 for soft-float.
+ |.endif
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ |.if FPU
+ | trunc.l.d FARG2, FARG1
+ | dmfc1 CRET1, FARG2
+ | li AT, -1
+ | dsrl AT, AT, 1
+ | beq CRET1, AT, >1
+ |. lui AT, 0xdf80 // -2^64 (float).
+ | jr ra
+ |. nop
+ |1:
+ | mtc1 AT, FARG2
+ | cvt.d.s FARG2, FARG2
+ | add.d FARG1, FARG1, FARG2
+ | trunc.l.d FARG2, FARG1
+ | jr ra
+ |. dmfc1 CRET1, FARG2
+ |
+ |.else
+ |
+ | dextu CARG2, CARG1, 20, 10
+ | addiu AT, CARG2, -1023
+ | sltiu AT, AT, 116
+ | beqz AT, >2 // Exponent out of range.
+ |. addiu CARG2, CARG2, -1075
+ | dextm CRET1, CARG1, 0, 19
+ | dsll AT, AT, 52
+ | dsra CARG1, CARG1, 63 // sign = 0 or -1.
+ | bgez CARG2, >1 // Shift mantissa left or right?
+ |. or CRET1, CRET1, AT // Merge leading 1 into masked mantissa.
+ | subu CARG2, r0, CARG2
+ | dsrlv CRET1, CRET1, CARG2 // Shift mantissa right for low exp.
+ | daddu CRET1, CRET1, CARG1
+ | jr ra
+ |. xor CRET1, CRET1, CARG1 // m = sign?-m:m = (m+sign)^sign.
+ |1:
+ | dsllv CRET1, CRET1, CARG2 // Shift mantissa left for high exp.
+ | daddu CRET1, CRET1, CARG1
+ | jr ra
+ |. xor CRET1, CRET1, CARG1 // m = sign?-m:m = (m+sign)^sign.
+ |2:
+ | jr ra
+ |. move CRET1, r0
+ |.endif
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |.if FPU
+ |->vm_tobit:
+ | lui AT, 0x59c0 // 2^52 + 2^51 (float).
+ | mtc1 AT, FARG2
+ | cvt.d.s FARG2, FARG2
+ | add.d FARG1, FARG1, FARG2
+ | mfc1 CRET1, FARG1
+ | jr ra
+ |. sextw CRET1, CRET1
+ |.endif
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
| blr
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ |.if FPU
+ | subi sp, sp, 16
+ | stfd FARG1, 0(sp)
+ | lwz CARG1, 0(sp)
+ | lwz CARG2, 4(sp)
+ |.endif
+ | slwi TMP1, CARG1, 1
+ |.if PPE
+ | or TMP1, TMP1, CARG2
+ | cmpwi TMP1, 0
+ |.else
+ | or. TMP1, TMP1, CARG2
+ |.endif
+ | beq >2 // Return 0 for +-0.
+ | rlwinm RB, CARG1, 12, 21, 31
+ | subfic RB, RB, 1054
+ | cmplwi RB, 32
+ | bge >1 // Fail if |x| < 0x1p0 || |x| >= 0x1p32.
+ | slwi CARG3, CARG1, 11
+ | rlwimi CARG3, CARG2, 11, 21, 31 // Left-aligned mantissa.
+ | subfic TMP1, RB, 32
+ | slw TMP1, CARG3, TMP1
+ | slwi TMP2, CARG2, 11
+ |.if PPE
+ | or. TMP1, TMP1, TMP2
+ |.else
+ | or TMP1, TMP1, TMP2
+ | cmpwi TMP1, 0
+ |.endif
+ | bne >1 // Fail if fractional part != 0.
+ | oris CARG3, CARG3, 0x8000 // Merge leading 1.
+ | srw CRET2, CARG3, RB // lo = right-aligned absolute value.
+ | srawi CARG4, CARG1, 31 // sign = 0 or -1.
+ |.if GPR64
+ | add CRET2, CRET2, CARG4
+ | cmpwi CRET2, 0
+ |.else
+ | add. CRET2, CRET2, CARG4
+ |.endif
+ | blt >1 // Fail if fractional part != 0.
+ | xor CRET2, CRET2, CARG4 // lo = sign?-lo:lo = (lo+sign)^sign.
+ |2:
+ |.if GPR64
+ | rldicl CRET1, CRET1, 0, 32
+ |.else
+ | li CRET1, 0
+ |.endif
+ |.if FPU
+ | addi sp, sp, 16
+ |.endif
+ | blr
+ |1:
+ |.if GPR64
+ | lus CRET1, 0x8000
+ | rldicr CRET1, CRET1, 32, 32
+ |.else
+ | lus CRET1, 0x8000
+ | lus CRET2, 0x8000
+ |.endif
+ |.if FPU
+ | addi sp, sp, 16
+ |.endif
+ | blr
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ |// fallthrough, same as lj_vm_num2u64.
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ |.if FPU
+ | subi sp, sp, 16
+ | stfd FARG1, 0(sp)
+ | lwz CARG1, 0(sp)
+ | lwz CARG2, 4(sp)
+ |.endif
+ | rlwinm RB, CARG1, 12, 21, 31
+ | addi RB, RB, -1023
+ | cmplwi RB, 116
+ | bge >3 // Exponent out of range.
+ | srawi CARG4, CARG1, 31 // sign = 0 or -1.
+ | clrlwi CARG1, CARG1, 12
+ | subfic RB, RB, 52
+ | oris CARG1, CARG1, 0x0010
+ | cmpwi RB, 0
+ | blt >2 // Shift mantissa left or right?
+ | subfic TMP1, RB, 32 // 64 bit right shift.
+ | srw CARG2, CARG2, RB
+ | slw TMP2, CARG1, TMP1
+ | addi TMP1, RB, -32
+ | or CARG2, CARG2, TMP2
+ | srw TMP2, CARG1, TMP1
+ | or CARG2, CARG2, TMP2
+ | srw CARG1, CARG1, RB
+ |1:
+ | addc CARG2, CARG2, CARG4
+ | adde CARG1, CARG1, CARG4
+ | xor CRET2, CARG2, CARG4
+ | xor CRET1, CARG1, CARG4
+ |.if GPR64
+ | rldimi CRET2, CRET1, 0, 32
+ | mr CRET1, CRET2
+ |.endif
+ | addi sp, sp, 16
+ | blr
+ |2:
+ | subfic TMP1, RB, 0 // 64 bit left shift.
+ | addi RB, RB, -32
+ | slw CARG1, CARG1, TMP1
+ | srw TMP2, CARG2, RB
+ | addi RB, TMP1, -32
+ | or CARG1, CARG1, TMP2
+ | slw TMP2, CARG2, RB
+ | or CARG1, CARG1, TMP2
+ | slw CARG2, CARG2, TMP1
+ | b <1
+ |3:
+ | li CRET1, 0
+ |.if not GPR64
+ | li CRET2, 0
+ |.endif
+ |.if FPU
+ | addi sp, sp, 16
+ |.endif
+ | blr
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |.if FPU
+ |->vm_tobit:
+ | lus TMP0, 0x59c0 // 2^52 + 2^51 (float).
+ | subi sp, sp, 16
+ | stw TMP0, 0(sp)
+ | lfs FARG2, 0(sp)
+ | fadd FARG1, FARG1, FARG2
+ | stfd FARG1, 0(sp)
+ | lwz CRET1, 4(sp)
+ | addi sp, sp, 16
+ | blr
+ |.endif
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
| ret
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ | cvttsd2si eax, xmm0
+ | xorps xmm1, xmm1
+ | cvtsi2sd xmm1, eax
+ | ucomisd xmm1, xmm0
+ | jp >1
+ | jne >1
+ | ret
+ |1:
+ | mov64 rax, U64x(80000000,80000000)
+ | ret
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ | cvttsd2si rax, xmm0
+ | ret
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ | cvttsd2si rax, xmm0 // Convert [-2^63..2^63) range.
+ | cmp rax, 1 // Indefinite result -0x8000000000000000LL - 1 sets overflow.
+ | jo >1
+ | ret
+ |1:
+ | mov64 rdx, U64x(c3f00000,00000000) // -0x1p64 (double).
+ | movd xmm1, rdx
+ | addsd xmm0, xmm1
+ | cvttsd2si rax, xmm0 // Convert [2^63..2^64+2^63) range.
+ | // Note that -0x1p63 converts to -0x8000000000000000LL either way.
+ | ret
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |->vm_tobit:
+ | sseconst_tobit xmm1, RC
+ | addsd xmm0, xmm1
+ | movd eax, xmm0
+ | ret
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|
| ret
|
|//-----------------------------------------------------------------------
+ |//-- Number conversion functions ----------------------------------------
+ |//-----------------------------------------------------------------------
+ |
+ |// int64_t lj_vm_num2int_check(double x)
+ |->vm_num2int_check:
+ |.if not X64
+ | movsd xmm0, qword [esp+4]
+ |.endif
+ | cvttsd2si eax, xmm0
+ | xorps xmm1, xmm1
+ | cvtsi2sd xmm1, eax
+ | ucomisd xmm1, xmm0
+ | jp >1
+ | jne >1
+ |.if not X64
+ | xor edx, edx
+ |.endif
+ | ret
+ |1:
+ |.if X64
+ | mov64 rax, U64x(80000000,80000000)
+ |.else
+ | mov eax, 0x80000000
+ | mov edx, eax
+ |.endif
+ | ret
+ |
+ |// int64_t lj_vm_num2i64(double x)
+ |->vm_num2i64:
+ |.if X64
+ | cvttsd2si rax, xmm0
+ | ret
+ |.else
+ | sub esp, 12
+ | fld qword [esp+16]
+ | fisttp qword [esp]
+ | mov eax, dword [esp]
+ | mov edx, dword [esp+4]
+ | add esp, 12
+ | ret
+ |.endif
+ |
+ |// uint64_t lj_vm_num2u64(double x)
+ |->vm_num2u64:
+ |.if X64
+ | cvttsd2si rax, xmm0 // Convert [-2^63..2^63) range.
+ | cmp rax, 1 // Indefinite result -0x8000000000000000LL - 1 sets overflow.
+ | jo >1
+ | ret
+ |1:
+ | mov64 rdx, U64x(c3f00000,00000000) // -0x1p64 (double).
+ | movd xmm1, rdx
+ | addsd xmm0, xmm1
+ | cvttsd2si rax, xmm0 // Convert [2^63..2^64+2^63) range.
+ | // Note that -0x1p63 converts to -0x8000000000000000LL either way.
+ | ret
+ |.else
+ | sub esp, 12
+ | fld qword [esp+16]
+ | fld st0
+ | fisttp qword [esp]
+ | mov edx, dword [esp+4]
+ | mov eax, dword [esp]
+ | cmp edx, 1
+ | jo >2
+ |1:
+ | fpop
+ | add esp, 12
+ | ret
+ |2:
+ | cmp eax, 0
+ | jne <1
+ | mov dword [esp+8], 0xdf800000 // -0x1p64 (float).
+ | fadd dword [esp+8]
+ | fisttp qword [esp]
+ | mov eax, dword [esp]
+ | mov edx, dword [esp+4]
+ | add esp, 12
+ | ret
+ |.endif
+ |
+ |// int32_t lj_vm_tobit(double x)
+ |->vm_tobit:
+ |.if not X64
+ | movsd xmm0, qword [esp+4]
+ |.endif
+ | sseconst_tobit xmm1, RCa
+ | addsd xmm0, xmm1
+ | movd eax, xmm0
+ | ret
+ |
+ |//-----------------------------------------------------------------------
|//-- Miscellaneous functions --------------------------------------------
|//-----------------------------------------------------------------------
|