- stop using lambda functions for CreateCall because MSVC lambas use a different calling convention and "converts" them to the right one by generating a thunk function

This commit is contained in:
Magnus Norddahl 2018-11-17 05:12:47 +01:00
parent f082a8af98
commit f99bba48dc
5 changed files with 234 additions and 163 deletions

View file

@ -560,26 +560,29 @@ void JitCompiler::SetupSimpleFrame()
cc.xor_(regA[i], regA[i]); cc.xor_(regA[i], regA[i]);
} }
static VMFrameStack *CreateFullVMFrame(VMScriptFunction *func, VMValue *args, int numargs)
{
try
{
VMFrameStack *stack = &GlobalVMStack;
VMFrame *newf = stack->AllocFrame(func);
CurrentJitExceptInfo->vmframes++;
VMFillParams(args, newf, numargs);
return stack;
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
}
void JitCompiler::SetupFullVMFrame() void JitCompiler::SetupFullVMFrame()
{ {
using namespace asmjit; using namespace asmjit;
stack = cc.newIntPtr("stack"); stack = cc.newIntPtr("stack");
auto allocFrame = CreateCall<VMFrameStack *, VMScriptFunction *, VMValue *, int>([](VMScriptFunction *func, VMValue *args, int numargs) -> VMFrameStack* { auto allocFrame = CreateCall<VMFrameStack *, VMScriptFunction *, VMValue *, int>(CreateFullVMFrame);
try
{
VMFrameStack *stack = &GlobalVMStack;
VMFrame *newf = stack->AllocFrame(func);
CurrentJitExceptInfo->vmframes++;
VMFillParams(args, newf, numargs);
return stack;
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
});
allocFrame->setRet(0, stack); allocFrame->setRet(0, stack);
allocFrame->setArg(0, imm_ptr(sfunc)); allocFrame->setArg(0, imm_ptr(sfunc));
allocFrame->setArg(1, args); allocFrame->setArg(1, args);
@ -601,21 +604,24 @@ void JitCompiler::SetupFullVMFrame()
cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*))); cc.mov(regA[i], x86::ptr(vmframe, offsetA + i * sizeof(void*)));
} }
static void PopFullVMFrame(VMFrameStack *stack)
{
try
{
stack->PopFrame();
CurrentJitExceptInfo->vmframes--;
}
catch (...)
{
VMThrowException(std::current_exception());
}
}
void JitCompiler::EmitPopFrame() void JitCompiler::EmitPopFrame()
{ {
if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0) if (sfunc->SpecialInits.Size() != 0 || sfunc->NumRegS != 0)
{ {
auto popFrame = CreateCall<void, VMFrameStack *>([](VMFrameStack *stack) { auto popFrame = CreateCall<void, VMFrameStack *>(PopFullVMFrame);
try
{
stack->PopFrame();
CurrentJitExceptInfo->vmframes--;
}
catch (...)
{
VMThrowException(std::current_exception());
}
});
popFrame->setArg(0, stack); popFrame->setArg(0, stack);
} }
} }

View file

@ -48,6 +48,13 @@ void JitCompiler::EmitIJMP()
EmitThrowException(X_OTHER); EmitThrowException(X_OTHER);
} }
static VMFunction *GetVirtual(DObject *o, int c)
{
auto p = o->GetClass();
assert(c < (int)p->Virtuals.Size());
return p->Virtuals[c];
}
void JitCompiler::EmitVTBL() void JitCompiler::EmitVTBL()
{ {
auto label = EmitThrowExceptionLabel(X_READ_NIL); auto label = EmitThrowExceptionLabel(X_READ_NIL);
@ -55,17 +62,25 @@ void JitCompiler::EmitVTBL()
cc.jz(label); cc.jz(label);
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<VMFunction*, DObject*, int>([](DObject *o, int c) -> VMFunction* { auto call = CreateCall<VMFunction*, DObject*, int>(GetVirtual);
auto p = o->GetClass();
assert(c < (int)p->Virtuals.Size());
return p->Virtuals[c];
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, asmjit::Imm(C)); call->setArg(1, asmjit::Imm(C));
cc.mov(regA[A], result); cc.mov(regA[A], result);
} }
static void ValidateCall(DObject *o, VMFunction *f, int b)
{
try
{
FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1);
}
catch (...)
{
VMThrowException(std::current_exception());
}
}
void JitCompiler::EmitSCOPE() void JitCompiler::EmitSCOPE()
{ {
auto label = EmitThrowExceptionLabel(X_READ_NIL); auto label = EmitThrowExceptionLabel(X_READ_NIL);
@ -76,21 +91,17 @@ void JitCompiler::EmitSCOPE()
cc.mov(f, asmjit::imm_ptr(konsta[C].v)); cc.mov(f, asmjit::imm_ptr(konsta[C].v));
typedef int(*FuncPtr)(DObject*, VMFunction*, int); typedef int(*FuncPtr)(DObject*, VMFunction*, int);
auto call = CreateCall<void, DObject*, VMFunction*, int>([](DObject *o, VMFunction *f, int b) { auto call = CreateCall<void, DObject*, VMFunction*, int>(ValidateCall);
try
{
FScopeBarrier::ValidateCall(o->GetClass(), f, b - 1);
}
catch (...)
{
VMThrowException(std::current_exception());
}
});
call->setArg(0, regA[A]); call->setArg(0, regA[A]);
call->setArg(1, f); call->setArg(1, f);
call->setArg(2, asmjit::Imm(B)); call->setArg(2, asmjit::Imm(B));
} }
static void SetString(VMReturn* ret, FString* str)
{
ret->SetString(*str);
}
void JitCompiler::EmitRET() void JitCompiler::EmitRET()
{ {
using namespace asmjit; using namespace asmjit;
@ -179,9 +190,7 @@ void JitCompiler::EmitRET()
auto ptr = newTempIntPtr(); auto ptr = newTempIntPtr();
cc.mov(ptr, ret); cc.mov(ptr, ret);
cc.add(ptr, (int)(retnum * sizeof(VMReturn))); cc.add(ptr, (int)(retnum * sizeof(VMReturn)));
auto call = CreateCall<void, VMReturn*, FString*>([](VMReturn* ret, FString* str) -> void { auto call = CreateCall<void, VMReturn*, FString*>(SetString);
ret->SetString(*str);
});
call->setArg(0, ptr); call->setArg(0, ptr);
if (regtype & REGT_KONST) call->setArg(1, asmjit::imm_ptr(&konsts[regnum])); if (regtype & REGT_KONST) call->setArg(1, asmjit::imm_ptr(&konsts[regnum]));
else call->setArg(1, regS[regnum]); else call->setArg(1, regS[regnum]);
@ -254,35 +263,38 @@ void JitCompiler::EmitRETI()
} }
} }
static DObject* CreateNew(PClass *cls, int c)
{
try
{
if (!cls->ConstructNative)
{
ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars());
}
else if (cls->bAbstract)
{
ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
}
else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
{
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
}
// [ZZ] validate readonly and between scope construction
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
return cls->CreateNew();
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
}
void JitCompiler::EmitNEW() void JitCompiler::EmitNEW()
{ {
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<DObject*, PClass*, int>([](PClass *cls, int c) -> DObject* { auto call = CreateCall<DObject*, PClass*, int>(CreateNew);
try
{
if (!cls->ConstructNative)
{
ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars());
}
else if (cls->bAbstract)
{
ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
}
else if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
{
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
}
// [ZZ] validate readonly and between scope construction
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
return cls->CreateNew();
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, asmjit::Imm(C)); call->setArg(1, asmjit::Imm(C));
@ -290,6 +302,43 @@ void JitCompiler::EmitNEW()
cc.mov(regA[A], result); cc.mov(regA[A], result);
} }
static void ThrowNewK(PClass *cls, int c)
{
try
{
if (!cls->ConstructNative)
{
ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars());
}
else if (cls->bAbstract)
{
ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
}
else // if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
{
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
}
}
catch (...)
{
VMThrowException(std::current_exception());
}
}
static DObject *CreateNewK(PClass *cls, int c)
{
try
{
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
return cls->CreateNew();
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
}
void JitCompiler::EmitNEW_K() void JitCompiler::EmitNEW_K()
{ {
PClass *cls = (PClass*)konsta[B].v; PClass *cls = (PClass*)konsta[B].v;
@ -298,44 +347,13 @@ void JitCompiler::EmitNEW_K()
if (!cls->ConstructNative || cls->bAbstract || cls->IsDescendantOf(NAME_Actor)) if (!cls->ConstructNative || cls->bAbstract || cls->IsDescendantOf(NAME_Actor))
{ {
auto call = CreateCall<void, PClass*, int>([](PClass *cls, int c) { auto call = CreateCall<void, PClass*, int>(ThrowNewK);
try
{
if (!cls->ConstructNative)
{
ThrowAbortException(X_OTHER, "Class %s requires native construction", cls->TypeName.GetChars());
}
else if (cls->bAbstract)
{
ThrowAbortException(X_OTHER, "Cannot instantiate abstract class %s", cls->TypeName.GetChars());
}
else // if (cls->IsDescendantOf(NAME_Actor)) // Creating actors here must be outright prohibited
{
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
}
}
catch (...)
{
VMThrowException(std::current_exception());
}
});
call->setArg(0, regcls); call->setArg(0, regcls);
} }
else else
{ {
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<DObject*, PClass*, int>([](PClass *cls, int c) -> DObject* { auto call = CreateCall<DObject*, PClass*, int>(CreateNewK);
try
{
if (c) FScopeBarrier::ValidateNew(cls, c - 1);
return cls->CreateNew();
}
catch (...)
{
VMThrowException(std::current_exception());
return nullptr;
}
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regcls); call->setArg(0, regcls);
call->setArg(1, asmjit::Imm(C)); call->setArg(1, asmjit::Imm(C));

View file

@ -76,6 +76,11 @@ void JitCompiler::EmitLFP()
cc.lea(regA[A], asmjit::x86::ptr(vmframe, offsetExtra)); cc.lea(regA[A], asmjit::x86::ptr(vmframe, offsetExtra));
} }
static uint8_t *GetClassMeta(DObject *o)
{
return o->GetClass()->Meta;
}
void JitCompiler::EmitMETA() void JitCompiler::EmitMETA()
{ {
auto label = EmitThrowExceptionLabel(X_READ_NIL); auto label = EmitThrowExceptionLabel(X_READ_NIL);
@ -83,12 +88,17 @@ void JitCompiler::EmitMETA()
cc.je(label); cc.je(label);
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<uint8_t*, DObject*>([](DObject *o) { return o->GetClass()->Meta; }); auto call = CreateCall<uint8_t*, DObject*>(GetClassMeta);
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
cc.mov(regA[A], result); cc.mov(regA[A], result);
} }
static PClass *GetClass(DObject *o)
{
return o->GetClass();
}
void JitCompiler::EmitCLSS() void JitCompiler::EmitCLSS()
{ {
auto label = EmitThrowExceptionLabel(X_READ_NIL); auto label = EmitThrowExceptionLabel(X_READ_NIL);
@ -96,7 +106,7 @@ void JitCompiler::EmitCLSS()
cc.je(label); cc.je(label);
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<PClass*, DObject*>([](DObject *o) { return o->GetClass(); }); auto call = CreateCall<PClass*, DObject*>(GetClass);
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
cc.mov(regA[A], result); cc.mov(regA[A], result);
@ -211,6 +221,11 @@ void JitCompiler::EmitLS_R()
call->setArg(1, ptr); call->setArg(1, ptr);
} }
static DObject *ReadBarrier(DObject *p)
{
return GC::ReadBarrier(p);
}
void JitCompiler::EmitLO() void JitCompiler::EmitLO()
{ {
EmitNullPointerThrow(B, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
@ -219,7 +234,7 @@ void JitCompiler::EmitLO()
cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C])); cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C]));
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<DObject*,DObject*>([](DObject *p) { return GC::ReadBarrier(p); }); auto call = CreateCall<DObject*, DObject*>(ReadBarrier);
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, ptr); call->setArg(0, ptr);
cc.mov(regA[A], result); cc.mov(regA[A], result);
@ -233,7 +248,7 @@ void JitCompiler::EmitLO_R()
cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C])); cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C]));
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<DObject*, DObject*>([](DObject *p) { return GC::ReadBarrier(p); }); auto call = CreateCall<DObject*, DObject*>(ReadBarrier);
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, ptr); call->setArg(0, ptr);
cc.mov(regA[A], result); cc.mov(regA[A], result);
@ -289,12 +304,17 @@ void JitCompiler::EmitLV3_R()
cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16)); cc.movsd(regF[A + 2], asmjit::x86::qword_ptr(tmp, 16));
} }
static void SetString(FString *to, char **from)
{
*to = *from;
}
void JitCompiler::EmitLCS() void JitCompiler::EmitLCS()
{ {
EmitNullPointerThrow(B, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto ptr = newTempIntPtr(); auto ptr = newTempIntPtr();
cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C])); cc.lea(ptr, asmjit::x86::ptr(regA[B], konstd[C]));
auto call = CreateCall<void, FString*, char**>([](FString* to, char** from) { *to = *from; }); auto call = CreateCall<void, FString*, char**>(SetString);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, ptr); call->setArg(1, ptr);
} }
@ -304,7 +324,7 @@ void JitCompiler::EmitLCS_R()
EmitNullPointerThrow(B, X_READ_NIL); EmitNullPointerThrow(B, X_READ_NIL);
auto ptr = newTempIntPtr(); auto ptr = newTempIntPtr();
cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C])); cc.lea(ptr, asmjit::x86::ptr(regA[B], regD[C]));
auto call = CreateCall<void, FString*, char**>([](FString* to, char** from) { *to = *from; }); auto call = CreateCall<void, FString*, char**>(SetString);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, ptr); call->setArg(1, ptr);
} }

View file

@ -4,41 +4,49 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// String instructions. // String instructions.
static void ConcatString(FString* to, FString* first, FString* second)
{
*to = *first + *second;
}
void JitCompiler::EmitCONCAT() void JitCompiler::EmitCONCAT()
{ {
auto rc = CheckRegS(C, A); auto rc = CheckRegS(C, A);
auto call = CreateCall<void, FString*, FString*, FString*>([](FString* to, FString* first, FString* second) { auto call = CreateCall<void, FString*, FString*, FString*>(ConcatString);
*to = *first + *second;
});
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regS[B]); call->setArg(1, regS[B]);
call->setArg(2, rc); call->setArg(2, rc);
} }
static int StringLength(FString* str)
{
return static_cast<int>(str->Len());
}
void JitCompiler::EmitLENS() void JitCompiler::EmitLENS()
{ {
auto result = newResultInt32(); auto result = newResultInt32();
auto call = CreateCall<int, FString*>([](FString* str) -> int { auto call = CreateCall<int, FString*>(StringLength);
return static_cast<int>(str->Len());
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], result); cc.mov(regD[A], result);
} }
static int StringCompareNoCase(FString* first, FString* second)
{
return first->CompareNoCase(*second);
}
static int StringCompare(FString* first, FString* second)
{
return first->Compare(*second);
}
void JitCompiler::EmitCMPS() void JitCompiler::EmitCMPS()
{ {
EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) { EmitComparisonOpcode([&](bool check, asmjit::Label& fail, asmjit::Label& success) {
auto compareNoCaseLambda = [](FString* first, FString* second) -> int {
return first->CompareNoCase(*second);
};
auto compareLambda = [](FString* first, FString* second) -> int {
return first->Compare(*second);
};
auto call = static_cast<bool>(A & CMP_APPROX) ? auto call = CreateCall<int, FString*, FString*>(static_cast<bool>(A & CMP_APPROX) ? StringCompareNoCase : StringCompare);
CreateCall<int, FString*, FString*>(compareNoCaseLambda) :
CreateCall<int, FString*, FString*>(compareLambda);
auto result = newResultInt32(); auto result = newResultInt32();
call->setRet(0, result); call->setRet(0, result);
@ -738,6 +746,11 @@ void JitCompiler::EmitDIVF_KR()
cc.divsd(regF[A], rc); cc.divsd(regF[A], rc);
} }
static double DoubleModF(double a, double b)
{
return a - floor(a / b) * b;
}
void JitCompiler::EmitMODF_RR() void JitCompiler::EmitMODF_RR()
{ {
auto label = EmitThrowExceptionLabel(X_DIVISION_BY_ZERO); auto label = EmitThrowExceptionLabel(X_DIVISION_BY_ZERO);
@ -745,10 +758,7 @@ void JitCompiler::EmitMODF_RR()
cc.je(label); cc.je(label);
auto result = newResultXmmSd(); auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double auto call = CreateCall<double, double, double>(DoubleModF);
{
return a - floor(a / b) * b;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
@ -770,9 +780,7 @@ void JitCompiler::EmitMODF_RK()
cc.movsd(tmp, asmjit::x86::qword_ptr(tmpPtr)); cc.movsd(tmp, asmjit::x86::qword_ptr(tmpPtr));
auto result = newResultXmmSd(); auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double { auto call = CreateCall<double, double, double>(DoubleModF);
return a - floor(a / b) * b;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, tmp); call->setArg(1, tmp);
@ -792,9 +800,7 @@ void JitCompiler::EmitMODF_KR()
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B]))); cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B])));
auto result = newResultXmmSd(); auto result = newResultXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double { auto call = CreateCall<double, double, double>(DoubleModF);
return a - floor(a / b) * b;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, tmp); call->setArg(0, tmp);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);

View file

@ -38,6 +38,23 @@ void JitCompiler::EmitMOVEV3()
cc.movsd(regF[A + 2], regF[B + 2]); cc.movsd(regF[A + 2], regF[B + 2]);
} }
static void CastI2S(FString *a, int b) { a->Format("%d", b); }
static void CastU2S(FString *a, int b) { a->Format("%u", b); }
static void CastF2S(FString *a, double b) { a->Format("%.5f", b); }
static void CastV22S(FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); }
static void CastV32S(FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); }
static void CastP2S(FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); }
static int CastS2I(FString *b) { return (VM_SWORD)b->ToLong(); }
static double CastS2F(FString *b) { return b->ToDouble(); }
static int CastS2N(FString *b) { return b->Len() == 0 ? FName(NAME_None) : FName(*b); }
static void CastN2S(FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; }
static int CastS2Co(FString *b) { return V_GetColor(nullptr, *b); }
static void CastCo2S(FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); }
static int CastS2So(FString *b) { return FSoundID(*b); }
static void CastSo2S(FString *a, int b) { *a = S_sfx[b].name; }
static void CastSID2S(FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; }
static void CastTID2S(FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); }
void JitCompiler::EmitCAST() void JitCompiler::EmitCAST()
{ {
asmjit::X86Gp tmp, resultD; asmjit::X86Gp tmp, resultD;
@ -64,95 +81,95 @@ void JitCompiler::EmitCAST()
cc.mov(regD[A], tmp.r32()); cc.mov(regD[A], tmp.r32());
break; break;
case CAST_I2S: case CAST_I2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { a->Format("%d", b); }); call = CreateCall<void, FString*, int>(CastI2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_U2S: case CAST_U2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { a->Format("%u", b); }); call = CreateCall<void, FString*, int>(CastU2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_F2S: case CAST_F2S:
call = CreateCall<void, FString*, double>([](FString *a, double b) { a->Format("%.5f", b); }); call = CreateCall<void, FString*, double>(CastF2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regF[B]); call->setArg(1, regF[B]);
break; break;
case CAST_V22S: case CAST_V22S:
call = CreateCall<void, FString*, double, double>([](FString *a, double b, double b1) { a->Format("(%.5f, %.5f)", b, b1); }); call = CreateCall<void, FString*, double, double>(CastV22S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regF[B]); call->setArg(1, regF[B]);
call->setArg(2, regF[B + 1]); call->setArg(2, regF[B + 1]);
break; break;
case CAST_V32S: case CAST_V32S:
call = CreateCall<void, FString*, double, double, double>([](FString *a, double b, double b1, double b2) { a->Format("(%.5f, %.5f, %.5f)", b, b1, b2); }); call = CreateCall<void, FString*, double, double, double>(CastV32S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regF[B]); call->setArg(1, regF[B]);
call->setArg(2, regF[B + 1]); call->setArg(2, regF[B + 1]);
call->setArg(3, regF[B + 2]); call->setArg(3, regF[B + 2]);
break; break;
case CAST_P2S: case CAST_P2S:
call = CreateCall<void, FString*, void*>([](FString *a, void *b) { if (b == nullptr) *a = "null"; else a->Format("%p", b); }); call = CreateCall<void, FString*, void*>(CastP2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regA[B]); call->setArg(1, regA[B]);
break; break;
case CAST_S2I: case CAST_S2I:
resultD = newResultInt32(); resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return (VM_SWORD)b->ToLong(); }); call = CreateCall<int, FString*>(CastS2I);
call->setRet(0, resultD); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], resultD); cc.mov(regD[A], resultD);
break; break;
case CAST_S2F: case CAST_S2F:
resultF = newResultXmmSd(); resultF = newResultXmmSd();
call = CreateCall<double, FString*>([](FString *b) -> double { return b->ToDouble(); }); call = CreateCall<double, FString*>(CastS2F);
call->setRet(0, resultF); call->setRet(0, resultF);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.movsd(regF[A], resultF); cc.movsd(regF[A], resultF);
break; break;
case CAST_S2N: case CAST_S2N:
resultD = newResultInt32(); resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return b->Len() == 0 ? FName(NAME_None) : FName(*b); }); call = CreateCall<int, FString*>(CastS2N);
call->setRet(0, resultD); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], resultD); cc.mov(regD[A], resultD);
break; break;
case CAST_N2S: case CAST_N2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; }); call = CreateCall<void, FString*, int>(CastN2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_S2Co: case CAST_S2Co:
resultD = newResultInt32(); resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return V_GetColor(nullptr, *b); }); call = CreateCall<int, FString*>(CastS2Co);
call->setRet(0, resultD); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], resultD); cc.mov(regD[A], resultD);
break; break;
case CAST_Co2S: case CAST_Co2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); }); call = CreateCall<void, FString*, int>(CastCo2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_S2So: case CAST_S2So:
resultD = newResultInt32(); resultD = newResultInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return FSoundID(*b); }); call = CreateCall<int, FString*>(CastS2So);
call->setRet(0, resultD); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], resultD); cc.mov(regD[A], resultD);
break; break;
case CAST_So2S: case CAST_So2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { *a = S_sfx[b].name; }); call = CreateCall<void, FString*, int>(CastSo2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_SID2S: case CAST_SID2S:
call = CreateCall<void, FString*, unsigned int>([](FString *a, unsigned int b) { *a = (b >= sprites.Size()) ? "TNT1" : sprites[b].name; }); call = CreateCall<void, FString*, unsigned int>(CastSID2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_TID2S: case CAST_TID2S:
call = CreateCall<void, FString*, int>([](FString *a, int b) { auto tex = TexMan[*(FTextureID*)&b]; *a = (tex == nullptr) ? "(null)" : tex->Name.GetChars(); }); call = CreateCall<void, FString*, int>(CastTID2S);
call->setArg(0, regS[A]); call->setArg(0, regS[A]);
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
@ -161,6 +178,8 @@ void JitCompiler::EmitCAST()
} }
} }
static int CastB_S(FString *s) { return s->Len() > 0; }
void JitCompiler::EmitCASTB() void JitCompiler::EmitCASTB()
{ {
if (C == CASTB_I) if (C == CASTB_I)
@ -189,19 +208,22 @@ void JitCompiler::EmitCASTB()
else else
{ {
auto result = newResultInt32(); auto result = newResultInt32();
auto call = CreateCall<int, FString*>([](FString *s) -> int { return s->Len() > 0; }); auto call = CreateCall<int, FString*>(CastB_S);
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], result); cc.mov(regD[A], result);
} }
} }
static DObject *DynCast(DObject *obj, PClass *cls)
{
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
}
void JitCompiler::EmitDYNCAST_R() void JitCompiler::EmitDYNCAST_R()
{ {
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<DObject*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* { auto call = CreateCall<DObject*, DObject*, PClass*>(DynCast);
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, regA[C]); call->setArg(1, regA[C]);
@ -213,21 +235,22 @@ void JitCompiler::EmitDYNCAST_K()
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto c = newTempIntPtr(); auto c = newTempIntPtr();
cc.mov(c, asmjit::imm_ptr(konsta[C].o)); cc.mov(c, asmjit::imm_ptr(konsta[C].o));
auto call = CreateCall<DObject*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* { auto call = CreateCall<DObject*, DObject*, PClass*>(DynCast);
return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, c); call->setArg(1, c);
cc.mov(regA[A], result); cc.mov(regA[A], result);
} }
static PClass *DynCastC(PClass *cls1, PClass *cls2)
{
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
}
void JitCompiler::EmitDYNCASTC_R() void JitCompiler::EmitDYNCASTC_R()
{ {
auto result = newResultIntPtr(); auto result = newResultIntPtr();
auto call = CreateCall<PClass*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* { auto call = CreateCall<PClass*, PClass*, PClass*>(DynCastC);
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, regA[C]); call->setArg(1, regA[C]);
@ -241,9 +264,7 @@ void JitCompiler::EmitDYNCASTC_K()
auto c = newTempIntPtr(); auto c = newTempIntPtr();
cc.mov(c, asmjit::imm_ptr(konsta[C].o)); cc.mov(c, asmjit::imm_ptr(konsta[C].o));
typedef PClass*(*FuncPtr)(PClass*, PClass*); typedef PClass*(*FuncPtr)(PClass*, PClass*);
auto call = CreateCall<PClass*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* { auto call = CreateCall<PClass*, PClass*, PClass*>(DynCastC);
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
});
call->setRet(0, result); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, c); call->setArg(1, c);