- workaround bug in asmjit's register allocator for calls where the return register is already allocated in a physical register needed by one of the call arguments

This commit is contained in:
Magnus Norddahl 2018-10-07 06:29:54 +02:00
parent 5bf76523d6
commit d47988202a
5 changed files with 78 additions and 27 deletions

View file

@ -47,7 +47,7 @@ static void OutputJitLog(const asmjit::StringLogger &logger)
JitFuncPtr JitCompile(VMScriptFunction *sfunc) JitFuncPtr JitCompile(VMScriptFunction *sfunc)
{ {
#if defined(DEBUG_JIT) #if defined(DEBUG_JIT)
if (strcmp(sfunc->PrintableName.GetChars(), "Key.ShouldStay") != 0) if (strcmp(sfunc->PrintableName.GetChars(), "StatusScreen.drawNum") != 0)
return nullptr; return nullptr;
#else #else
if (!JitCompiler::CanJit(sfunc)) if (!JitCompiler::CanJit(sfunc))

View file

@ -56,14 +56,16 @@ void JitCompiler::EmitVTBL()
EmitThrowException(X_READ_NIL); EmitThrowException(X_READ_NIL);
cc.bind(notnull); cc.bind(notnull);
auto result = cc.newIntPtr();
auto call = CreateCall<VMFunction*, DObject*, int>([](DObject *o, int c) -> VMFunction* { auto call = CreateCall<VMFunction*, DObject*, int>([](DObject *o, int c) -> VMFunction* {
auto p = o->GetClass(); auto p = o->GetClass();
assert(c < (int)p->Virtuals.Size()); assert(c < (int)p->Virtuals.Size());
return p->Virtuals[c]; return p->Virtuals[c];
}); });
call->setRet(0, regA[A]); 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);
} }
void JitCompiler::EmitSCOPE() void JitCompiler::EmitSCOPE()

View file

@ -90,9 +90,11 @@ void JitCompiler::EmitMETA()
EmitThrowException(X_READ_NIL); EmitThrowException(X_READ_NIL);
cc.bind(label); cc.bind(label);
auto result = cc.newIntPtr();
auto call = CreateCall<uint8_t*, DObject*>([](DObject *o) { return o->GetClass()->Meta; }); auto call = CreateCall<uint8_t*, DObject*>([](DObject *o) { return o->GetClass()->Meta; });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
cc.mov(regA[A], result);
} }
void JitCompiler::EmitCLSS() void JitCompiler::EmitCLSS()
@ -103,9 +105,11 @@ void JitCompiler::EmitCLSS()
EmitThrowException(X_READ_NIL); EmitThrowException(X_READ_NIL);
cc.bind(label); cc.bind(label);
auto result = cc.newIntPtr();
auto call = CreateCall<PClass*, DObject*>([](DObject *o) { return o->GetClass(); }); auto call = CreateCall<PClass*, DObject*>([](DObject *o) { return o->GetClass(); });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
cc.mov(regA[A], result);
} }
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -222,9 +226,11 @@ void JitCompiler::EmitLO()
auto ptr = cc.newIntPtr(); auto ptr = cc.newIntPtr();
cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C])); cc.mov(ptr, asmjit::x86::ptr(regA[B], konstd[C]));
auto result = cc.newIntPtr();
auto call = CreateCall<DObject*,DObject*>([](DObject *p) { return GC::ReadBarrier(p); }); auto call = CreateCall<DObject*,DObject*>([](DObject *p) { return GC::ReadBarrier(p); });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, ptr); call->setArg(0, ptr);
cc.mov(regA[A], result);
} }
void JitCompiler::EmitLO_R() void JitCompiler::EmitLO_R()
@ -234,9 +240,11 @@ void JitCompiler::EmitLO_R()
auto ptr = cc.newIntPtr(); auto ptr = cc.newIntPtr();
cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C])); cc.mov(ptr, asmjit::x86::ptr(regA[B], regD[C]));
auto result = cc.newIntPtr();
auto call = CreateCall<DObject*, DObject*>([](DObject *p) { return GC::ReadBarrier(p); }); auto call = CreateCall<DObject*, DObject*>([](DObject *p) { return GC::ReadBarrier(p); });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, ptr); call->setArg(0, ptr);
cc.mov(regA[A], result);
} }
void JitCompiler::EmitLP() void JitCompiler::EmitLP()

View file

@ -17,11 +17,13 @@ void JitCompiler::EmitCONCAT()
void JitCompiler::EmitLENS() void JitCompiler::EmitLENS()
{ {
auto result = cc.newInt32();
auto call = CreateCall<int, FString*>([](FString* str) -> int { auto call = CreateCall<int, FString*>([](FString* str) -> int {
return static_cast<int>(str->Len()); return static_cast<int>(str->Len());
}); });
call->setRet(0, regD[A]); call->setRet(0, result);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], result);
} }
void JitCompiler::EmitCMPS() void JitCompiler::EmitCMPS()
@ -757,13 +759,15 @@ void JitCompiler::EmitMODF_RR()
EmitThrowException(X_DIVISION_BY_ZERO); EmitThrowException(X_DIVISION_BY_ZERO);
cc.bind(label); cc.bind(label);
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double auto call = CreateCall<double, double, double>([](double a, double b) -> double
{ {
return a - floor(a / b) * b; return a - floor(a / b) * b;
}); });
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitMODF_RK() void JitCompiler::EmitMODF_RK()
@ -777,12 +781,14 @@ void JitCompiler::EmitMODF_RK()
auto tmp = cc.newXmm(); auto tmp = cc.newXmm();
cc.movsd(tmp, asmjit::x86::ptr(ToMemAddress(&konstf[C]))); cc.movsd(tmp, asmjit::x86::ptr(ToMemAddress(&konstf[C])));
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double { auto call = CreateCall<double, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b; return a - floor(a / b) * b;
}); });
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, tmp); call->setArg(1, tmp);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitMODF_KR() void JitCompiler::EmitMODF_KR()
@ -798,20 +804,24 @@ void JitCompiler::EmitMODF_KR()
auto tmp = cc.newXmm(); auto tmp = cc.newXmm();
cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B]))); cc.movsd(tmp, x86::ptr(ToMemAddress(&konstf[B])));
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>([](double a, double b) -> double { auto call = CreateCall<double, double, double>([](double a, double b) -> double {
return a - floor(a / b) * b; return a - floor(a / b) * b;
}); });
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, tmp); call->setArg(0, tmp);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitPOWF_RR() void JitCompiler::EmitPOWF_RR()
{ {
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>(g_pow); auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitPOWF_RK() void JitCompiler::EmitPOWF_RK()
@ -821,10 +831,12 @@ void JitCompiler::EmitPOWF_RK()
cc.mov(tmp, asmjit::imm_ptr(&konstf[C])); cc.mov(tmp, asmjit::imm_ptr(&konstf[C]));
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp)); cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>(g_pow); auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, tmp2); call->setArg(1, tmp2);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitPOWF_KR() void JitCompiler::EmitPOWF_KR()
@ -834,10 +846,12 @@ void JitCompiler::EmitPOWF_KR()
cc.mov(tmp, asmjit::imm_ptr(&konstf[B])); cc.mov(tmp, asmjit::imm_ptr(&konstf[B]));
cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp)); cc.movsd(tmp2, asmjit::x86::qword_ptr(tmp));
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>(g_pow); auto call = CreateCall<double, double, double>(g_pow);
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, tmp2); call->setArg(0, tmp2);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
} }
void JitCompiler::EmitMINF_RR() void JitCompiler::EmitMINF_RR()
@ -876,10 +890,12 @@ void JitCompiler::EmitMAXF_RK()
void JitCompiler::EmitATAN2() void JitCompiler::EmitATAN2()
{ {
auto result = cc.newXmmSd();
auto call = CreateCall<double, double, double>(g_atan2); auto call = CreateCall<double, double, double>(g_atan2);
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, regF[B]); call->setArg(0, regF[B]);
call->setArg(1, regF[C]); call->setArg(1, regF[C]);
cc.movsd(regF[A], result);
static const double constant = 180 / M_PI; static const double constant = 180 / M_PI;
auto tmp = cc.newIntPtr(); auto tmp = cc.newIntPtr();
@ -940,9 +956,11 @@ void JitCompiler::EmitFLOP()
case FLOP_TANH: func = g_tanh; break; case FLOP_TANH: func = g_tanh; break;
} }
auto result = cc.newXmmSd();
auto call = CreateCall<double, double>(func); auto call = CreateCall<double, double>(func);
call->setRet(0, regF[A]); call->setRet(0, result);
call->setArg(0, v); call->setArg(0, v);
cc.movsd(regF[A], result);
if (C == FLOP_ACOS_DEG || C == FLOP_ASIN_DEG || C == FLOP_ATAN_DEG) if (C == FLOP_ACOS_DEG || C == FLOP_ASIN_DEG || C == FLOP_ATAN_DEG)
{ {
@ -1515,7 +1533,9 @@ void JitCompiler::EmitEQA_K()
void JitCompiler::CallSqrt(const asmjit::X86Xmm &a, const asmjit::X86Xmm &b) void JitCompiler::CallSqrt(const asmjit::X86Xmm &a, const asmjit::X86Xmm &b)
{ {
auto result = cc.newXmmSd();
auto call = CreateCall<double, double>(g_sqrt); auto call = CreateCall<double, double>(g_sqrt);
call->setRet(0, a); call->setRet(0, result);
call->setArg(0, b); call->setArg(0, b);
cc.movsd(a, result);
} }

View file

@ -40,7 +40,8 @@ void JitCompiler::EmitMOVEV3()
void JitCompiler::EmitCAST() void JitCompiler::EmitCAST()
{ {
asmjit::X86Gp tmp; asmjit::X86Gp tmp, resultD;
asmjit::X86Xmm resultF;
asmjit::CCFuncCall *call = nullptr; asmjit::CCFuncCall *call = nullptr;
switch (C) switch (C)
@ -96,19 +97,25 @@ void JitCompiler::EmitCAST()
call->setArg(1, regA[B]); call->setArg(1, regA[B]);
break; break;
case CAST_S2I: case CAST_S2I:
resultD = cc.newInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return (VM_SWORD)b->ToLong(); }); call = CreateCall<int, FString*>([](FString *b) -> int { return (VM_SWORD)b->ToLong(); });
call->setRet(0, regD[A]); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], resultD);
break; break;
case CAST_S2F: case CAST_S2F:
resultF = cc.newXmmSd();
call = CreateCall<double, FString*>([](FString *b) -> double { return b->ToDouble(); }); call = CreateCall<double, FString*>([](FString *b) -> double { return b->ToDouble(); });
call->setRet(0, regF[A]); call->setRet(0, resultF);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.movsd(regF[A], resultF);
break; break;
case CAST_S2N: case CAST_S2N:
resultD = cc.newInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return b->Len() == 0 ? FName(NAME_None) : FName(*b); }); call = CreateCall<int, FString*>([](FString *b) -> int { return b->Len() == 0 ? FName(NAME_None) : FName(*b); });
call->setRet(0, regD[A]); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
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>([](FString *a, int b) { FName name = FName(ENamedName(b)); *a = name.IsValidName() ? name.GetChars() : ""; });
@ -116,9 +123,11 @@ void JitCompiler::EmitCAST()
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_S2Co: case CAST_S2Co:
resultD = cc.newInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return V_GetColor(nullptr, *b); }); call = CreateCall<int, FString*>([](FString *b) -> int { return V_GetColor(nullptr, *b); });
call->setRet(0, regD[A]); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
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>([](FString *a, int b) { PalEntry c(b); a->Format("%02x %02x %02x", c.r, c.g, c.b); });
@ -126,9 +135,11 @@ void JitCompiler::EmitCAST()
call->setArg(1, regD[B]); call->setArg(1, regD[B]);
break; break;
case CAST_S2So: case CAST_S2So:
resultD = cc.newInt32();
call = CreateCall<int, FString*>([](FString *b) -> int { return FSoundID(*b); }); call = CreateCall<int, FString*>([](FString *b) -> int { return FSoundID(*b); });
call->setRet(0, regD[A]); call->setRet(0, resultD);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
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>([](FString *a, int b) { *a = S_sfx[b].name; });
@ -174,54 +185,64 @@ void JitCompiler::EmitCASTB()
} }
else else
{ {
auto result = cc.newInt32();
auto call = CreateCall<int, FString*>([](FString *s) -> int { return s->Len() > 0; }); auto call = CreateCall<int, FString*>([](FString *s) -> int { return s->Len() > 0; });
call->setRet(0, regD[A]); call->setRet(0, result);
call->setArg(0, regS[B]); call->setArg(0, regS[B]);
cc.mov(regD[A], result);
} }
} }
void JitCompiler::EmitDYNCAST_R() void JitCompiler::EmitDYNCAST_R()
{ {
auto result = cc.newIntPtr();
auto call = CreateCall<DObject*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* { auto call = CreateCall<DObject*, DObject*, PClass*>([](DObject *obj, PClass *cls) -> DObject* {
return (obj && obj->IsKindOf(cls)) ? obj : nullptr; return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
}); });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, regA[C]); call->setArg(1, regA[C]);
cc.mov(regA[A], result);
} }
void JitCompiler::EmitDYNCAST_K() void JitCompiler::EmitDYNCAST_K()
{ {
auto result = cc.newIntPtr();
auto c = cc.newIntPtr(); auto c = cc.newIntPtr();
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*>([](DObject *obj, PClass *cls) -> DObject* {
return (obj && obj->IsKindOf(cls)) ? obj : nullptr; return (obj && obj->IsKindOf(cls)) ? obj : nullptr;
}); });
call->setRet(0, regA[A]); 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);
} }
void JitCompiler::EmitDYNCASTC_R() void JitCompiler::EmitDYNCASTC_R()
{ {
auto result = cc.newIntPtr();
auto call = CreateCall<PClass*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* { auto call = CreateCall<PClass*, PClass*, PClass*>([](PClass *cls1, PClass *cls2) -> PClass* {
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr; return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
}); });
call->setRet(0, regA[A]); call->setRet(0, result);
call->setArg(0, regA[B]); call->setArg(0, regA[B]);
call->setArg(1, regA[C]); call->setArg(1, regA[C]);
cc.mov(regA[A], result);
} }
void JitCompiler::EmitDYNCASTC_K() void JitCompiler::EmitDYNCASTC_K()
{ {
using namespace asmjit; using namespace asmjit;
auto result = cc.newIntPtr();
auto c = cc.newIntPtr(); auto c = cc.newIntPtr();
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*>([](PClass *cls1, PClass *cls2) -> PClass* {
return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr; return (cls1 && cls1->IsDescendantOf(cls2)) ? cls1 : nullptr;
}); });
call->setRet(0, regA[A]); 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);
} }