2022-10-14 01:59:53 +03:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#include "EmitBuiltinsX64.h"
|
|
|
|
|
|
|
|
#include "Luau/AssemblyBuilderX64.h"
|
|
|
|
#include "Luau/Bytecode.h"
|
|
|
|
|
|
|
|
#include "EmitCommonX64.h"
|
2023-01-03 19:33:19 +02:00
|
|
|
#include "NativeState.h"
|
2022-10-14 01:59:53 +03:00
|
|
|
|
|
|
|
#include "lstate.h"
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
namespace CodeGen
|
|
|
|
{
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinAssert(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults != 0)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_ASSERT\n");
|
|
|
|
|
|
|
|
Label skip;
|
|
|
|
|
|
|
|
jumpIfFalsy(build, arg, fallback, skip);
|
|
|
|
|
|
|
|
// TODO: use of 'skip' causes a jump to a jump instruction that skips the fallback - can be optimized
|
|
|
|
build.setLabel(skip);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 0};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathFloor(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_FLOOR\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vroundsd(xmm0, xmm0, luauRegValue(arg), RoundingModeX64::RoundToNegativeInfinity);
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathCeil(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_CEIL\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vroundsd(xmm0, xmm0, luauRegValue(arg), RoundingModeX64::RoundToPositiveInfinity);
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathSqrt(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_SQRT\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vsqrtsd(xmm0, xmm0, luauRegValue(arg));
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
2023-01-03 19:33:19 +02:00
|
|
|
BuiltinImplResult emitBuiltinMathAbs(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_ABS\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vandpd(xmm0, xmm0, build.i64(~(1LL << 63)));
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
static BuiltinImplResult emitBuiltinMathSingleArgFunc(
|
|
|
|
AssemblyBuilderX64& build, int nparams, int ra, int arg, int nresults, Label& fallback, const char* name, int32_t offset)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined %s\n", name);
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.call(qword[rNativeContext + offset]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathExp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_EXP", offsetof(NativeContext, libm_exp));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathDeg(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_DEG\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
const double rpd = (3.14159265358979323846 / 180.0);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vdivsd(xmm0, xmm0, build.f64(rpd));
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathRad(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_RAD\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
const double rpd = (3.14159265358979323846 / 180.0);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vmulsd(xmm0, xmm0, build.f64(rpd));
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathFmod(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_FMOD\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_fmod)]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathPow(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_POW\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_pow)]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathMin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams != 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_MIN\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.vminsd(xmm0, xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathMax(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams != 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_MAX\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.vmaxsd(xmm0, xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathAsin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ASIN", offsetof(NativeContext, libm_asin));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathSin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SIN", offsetof(NativeContext, libm_sin));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathSinh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SINH", offsetof(NativeContext, libm_sinh));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathAcos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ACOS", offsetof(NativeContext, libm_acos));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathCos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COS", offsetof(NativeContext, libm_cos));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathCosh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COSH", offsetof(NativeContext, libm_cosh));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathAtan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ATAN", offsetof(NativeContext, libm_atan));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathTan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TAN", offsetof(NativeContext, libm_tan));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathTanh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TANH", offsetof(NativeContext, libm_tanh));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathAtan2(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_ATAN2\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_atan2)]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathLog10(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_LOG10", offsetof(NativeContext, libm_log10));
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathLog(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_LOG\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
if (nparams == 1)
|
|
|
|
{
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Label log10check, logdivlog, exit;
|
|
|
|
|
|
|
|
// Using 'rbx' for non-volatile temporary storage of log(arg1) result
|
|
|
|
RegisterX64 tmp = rbx;
|
|
|
|
OperandX64 arg2value = qword[args + offsetof(TValue, value)];
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm1, arg2value);
|
|
|
|
|
|
|
|
jumpOnNumberCmp(build, noreg, build.f64(2.0), xmm1, ConditionX64::NotEqual, log10check);
|
|
|
|
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log2)]);
|
|
|
|
build.jmp(exit);
|
|
|
|
|
|
|
|
build.setLabel(log10check);
|
|
|
|
jumpOnNumberCmp(build, noreg, build.f64(10.0), xmm1, ConditionX64::NotEqual, logdivlog);
|
|
|
|
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log10)]);
|
|
|
|
build.jmp(exit);
|
|
|
|
|
|
|
|
build.setLabel(logdivlog);
|
|
|
|
|
|
|
|
// log(arg1)
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
|
|
|
|
build.vmovq(tmp, xmm0);
|
|
|
|
|
|
|
|
// log(arg2)
|
|
|
|
build.vmovsd(xmm0, arg2value);
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
|
|
|
|
|
|
|
|
// log(arg1) / log(arg2)
|
|
|
|
build.vmovq(xmm1, tmp);
|
|
|
|
build.vdivsd(xmm0, xmm1, xmm0);
|
|
|
|
|
|
|
|
build.setLabel(exit);
|
|
|
|
}
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
2023-02-03 14:34:12 +02:00
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathLdexp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 2 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_LDEXP\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
if (build.abi == ABIX64::Windows)
|
|
|
|
build.vcvttsd2si(rArg2, qword[args + offsetof(TValue, value)]);
|
|
|
|
else
|
|
|
|
build.vcvttsd2si(rArg1, qword[args + offsetof(TValue, value)]);
|
|
|
|
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_ldexp)]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathRound(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_ROUND\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vandpd(xmm1, xmm0, build.f64x2(-0.0, -0.0));
|
|
|
|
build.vmovsd(xmm2, build.i64(0x3fdfffffffffffff)); // 0.49999999999999994
|
|
|
|
build.vorpd(xmm1, xmm1, xmm2);
|
|
|
|
build.vaddsd(xmm0, xmm0, xmm1);
|
|
|
|
build.vroundsd(xmm0, xmm0, xmm0, RoundingModeX64::RoundToZero);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathFrexp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 2)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_FREXP\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
if (build.abi == ABIX64::Windows)
|
|
|
|
build.lea(rArg2, sTemporarySlot);
|
|
|
|
else
|
|
|
|
build.lea(rArg1, sTemporarySlot);
|
|
|
|
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_frexp)]);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
build.vcvtsi2sd(xmm0, xmm0, dword[sTemporarySlot + 0]);
|
|
|
|
build.vmovsd(luauRegValue(ra + 1), xmm0);
|
|
|
|
build.mov(luauRegTag(ra + 1), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 2};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathModf(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 2)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_MODF\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
|
|
|
|
if (build.abi == ABIX64::Windows)
|
|
|
|
build.lea(rArg2, sTemporarySlot);
|
|
|
|
else
|
|
|
|
build.lea(rArg1, sTemporarySlot);
|
|
|
|
|
|
|
|
build.call(qword[rNativeContext + offsetof(NativeContext, libm_modf)]);
|
|
|
|
|
|
|
|
build.vmovsd(xmm1, qword[sTemporarySlot + 0]);
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm1);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra + 1), xmm0);
|
|
|
|
build.mov(luauRegTag(ra + 1), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 2};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathSign(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 1 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_SIGN\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
build.vmovsd(xmm0, luauRegValue(arg));
|
|
|
|
build.vxorpd(xmm1, xmm1, xmm1);
|
|
|
|
|
|
|
|
// Set xmm2 to -1 if arg < 0, else 0
|
|
|
|
build.vcmpltsd(xmm2, xmm0, xmm1);
|
|
|
|
build.vmovsd(xmm3, build.f64(-1));
|
|
|
|
build.vandpd(xmm2, xmm2, xmm3);
|
|
|
|
|
|
|
|
// Set mask bit to 1 if 0 < arg, else 0
|
|
|
|
build.vcmpltsd(xmm0, xmm1, xmm0);
|
|
|
|
|
|
|
|
// Result = (mask-bit == 1) ? 1.0 : xmm2
|
|
|
|
// If arg < 0 then xmm2 is -1 and mask-bit is 0, result is -1
|
|
|
|
// If arg == 0 then xmm2 is 0 and mask-bit is 0, result is 0
|
|
|
|
// If arg > 0 then xmm2 is 0 and mask-bit is 1, result is 1
|
|
|
|
build.vblendvpd(xmm0, xmm2, build.f64x2(1, 1), xmm0);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
BuiltinImplResult emitBuiltinMathClamp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
if (nparams < 3 || nresults > 1)
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
|
|
|
|
if (build.logText)
|
|
|
|
build.logAppend("; inlined LBF_MATH_CLAMP\n");
|
|
|
|
|
|
|
|
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
|
|
|
|
build.cmp(dword[args + sizeof(TValue) + offsetof(TValue, tt)], LUA_TNUMBER);
|
|
|
|
build.jcc(ConditionX64::NotEqual, fallback);
|
|
|
|
|
|
|
|
RegisterX64 min = xmm1;
|
|
|
|
RegisterX64 max = xmm2;
|
|
|
|
build.vmovsd(min, qword[args + offsetof(TValue, value)]);
|
|
|
|
build.vmovsd(max, qword[args + sizeof(TValue) + offsetof(TValue, value)]);
|
|
|
|
|
|
|
|
jumpOnNumberCmp(build, noreg, min, max, ConditionX64::NotLessEqual, fallback);
|
|
|
|
|
|
|
|
build.vmaxsd(xmm0, min, luauRegValue(arg));
|
|
|
|
build.vminsd(xmm0, max, xmm0);
|
|
|
|
|
|
|
|
build.vmovsd(luauRegValue(ra), xmm0);
|
|
|
|
|
|
|
|
if (ra != arg)
|
|
|
|
build.mov(luauRegTag(ra), LUA_TNUMBER);
|
|
|
|
|
|
|
|
return {BuiltinImplType::UsesFallback, 1};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-10-14 01:59:53 +03:00
|
|
|
BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
|
|
|
|
{
|
|
|
|
switch (bfid)
|
|
|
|
{
|
|
|
|
case LBF_ASSERT:
|
|
|
|
return emitBuiltinAssert(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_FLOOR:
|
|
|
|
return emitBuiltinMathFloor(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_CEIL:
|
|
|
|
return emitBuiltinMathCeil(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_SQRT:
|
|
|
|
return emitBuiltinMathSqrt(build, nparams, ra, arg, args, nresults, fallback);
|
2023-01-03 19:33:19 +02:00
|
|
|
case LBF_MATH_ABS:
|
|
|
|
return emitBuiltinMathAbs(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_EXP:
|
|
|
|
return emitBuiltinMathExp(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_DEG:
|
|
|
|
return emitBuiltinMathDeg(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_RAD:
|
|
|
|
return emitBuiltinMathRad(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_FMOD:
|
|
|
|
return emitBuiltinMathFmod(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_POW:
|
|
|
|
return emitBuiltinMathPow(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_MIN:
|
|
|
|
return emitBuiltinMathMin(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_MAX:
|
|
|
|
return emitBuiltinMathMax(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_ASIN:
|
|
|
|
return emitBuiltinMathAsin(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_SIN:
|
|
|
|
return emitBuiltinMathSin(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_SINH:
|
|
|
|
return emitBuiltinMathSinh(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_ACOS:
|
|
|
|
return emitBuiltinMathAcos(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_COS:
|
|
|
|
return emitBuiltinMathCos(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_COSH:
|
|
|
|
return emitBuiltinMathCosh(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_ATAN:
|
|
|
|
return emitBuiltinMathAtan(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_TAN:
|
|
|
|
return emitBuiltinMathTan(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_TANH:
|
|
|
|
return emitBuiltinMathTanh(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_ATAN2:
|
|
|
|
return emitBuiltinMathAtan2(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_LOG10:
|
|
|
|
return emitBuiltinMathLog10(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_LOG:
|
|
|
|
return emitBuiltinMathLog(build, nparams, ra, arg, args, nresults, fallback);
|
2023-02-03 14:34:12 +02:00
|
|
|
case LBF_MATH_LDEXP:
|
|
|
|
return emitBuiltinMathLdexp(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_ROUND:
|
|
|
|
return emitBuiltinMathRound(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_FREXP:
|
|
|
|
return emitBuiltinMathFrexp(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_MODF:
|
|
|
|
return emitBuiltinMathModf(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_SIGN:
|
|
|
|
return emitBuiltinMathSign(build, nparams, ra, arg, args, nresults, fallback);
|
|
|
|
case LBF_MATH_CLAMP:
|
|
|
|
return emitBuiltinMathClamp(build, nparams, ra, arg, args, nresults, fallback);
|
2022-10-14 01:59:53 +03:00
|
|
|
default:
|
|
|
|
return {BuiltinImplType::None, -1};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace CodeGen
|
|
|
|
} // namespace Luau
|