diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index da919e139..df9d2bb46 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -758,25 +758,7 @@ ExpEmit FxBoolCast::Emit(VMFunctionBuilder *build) ExpEmit to(build, REGT_INT); from.Free(build); // Preload result with 0. - build->Emit(OP_LI, to.RegNum, 0); - - // Check source against 0. - if (from.RegType == REGT_INT) - { - build->Emit(OP_EQ_R, 1, from.RegNum, to.RegNum); - } - else if (from.RegType == REGT_FLOAT) - { - build->Emit(OP_EQF_K, 1, from.RegNum, build->GetConstantFloat(0.)); - } - else if (from.RegType == REGT_POINTER) - { - build->Emit(OP_EQA_K, 1, from.RegNum, build->GetConstantAddress(nullptr, ATAG_GENERIC)); - } - build->Emit(OP_JMP, 1); - - // Reload result with 1 if the comparison fell through. - build->Emit(OP_LI, to.RegNum, 1); + build->Emit(OP_CASTB, to.RegNum, from.RegNum, from.RegType == REGT_INT ? CASTB_I : from.RegType == REGT_FLOAT ? CASTB_F : CASTB_A); return to; } else diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 9bd0a4bc9..0ccde006f 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -130,6 +130,11 @@ enum CAST_V32S, CAST_SID2S, CAST_TID2S, + + CASTB_I, + CASTB_F, + CASTB_A, + CASTB_S }; // Register types for VMParam diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index 2158139ab..d21e38d20 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -90,6 +90,7 @@ #define THROW MODE_AIMMZ | MODE_BCTHROW #define CATCH MODE_AIMMZ | MODE_BCCATCH #define CAST MODE_AX | MODE_BX | MODE_CIMMZ | MODE_BCCAST +#define CASTB MODE_AI | MODE_BX | MODE_CIMMZ | MODE_BCCAST #define RSRSRS MODE_AS | MODE_BS | MODE_CS #define RIRS MODE_AI | MODE_BS | MODE_CUNUSED @@ -381,10 +382,18 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; default: + + if ((mode & MODE_BCTYPE) == MODE_BCCAST) { switch (code[i].c) { + case CASTB_I: + mode = MODE_AI | MODE_BI | MODE_CUNUSED; + break; + case CASTB_A: + mode = MODE_AI | MODE_BP | MODE_CUNUSED; + break; case CAST_I2F: case CAST_U2F: mode = MODE_AF | MODE_BI | MODE_CUNUSED; @@ -398,6 +407,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction break; case CAST_F2I: case CAST_F2U: + case CASTB_F: mode = MODE_AI | MODE_BF | MODE_CUNUSED; break; case CAST_F2S: @@ -412,6 +422,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction case CAST_S2So: case CAST_S2N: case CAST_S2I: + case CASTB_S: mode = MODE_AI | MODE_BS | MODE_CUNUSED; break; case CAST_S2F: diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index f5e61b5b9..d19850554 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -419,12 +419,12 @@ begin: if (C == CAST_I2F) { ASSERTF(a); ASSERTD(B); - reg.f[A] = reg.d[B]; + reg.f[a] = reg.d[B]; } else if (C == CAST_F2I) { ASSERTD(a); ASSERTF(B); - reg.d[A] = (int)reg.f[B]; + reg.d[a] = (int)reg.f[B]; } else { @@ -432,6 +432,29 @@ begin: } NEXTOP; + OP(CASTB): + if (C == CASTB_I) + { + ASSERTD(a); ASSERTD(B); + reg.f[a] = !!reg.d[B]; + } + else if (C == CASTB_F) + { + ASSERTD(a); ASSERTF(B); + reg.d[a] = reg.f[B] != 0; + } + else if (c == CASTB_A) + { + ASSERTD(a); ASSERTA(B); + reg.d[a] = reg.a[B] != nullptr; + } + else + { + ASSERTD(a); ASSERTS(B); + reg.d[a] = reg.s[B].Len() > 0; + } + NEXTOP; + OP(TEST): ASSERTD(a); if (reg.d[a] != BC) diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index e5b6d34eb..826bdb4e3 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -83,6 +83,7 @@ xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements) xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements) xx(CAST, cast, CAST, NOP, 0, 0), // xA = xB, conversion specified by C +xx(CASTB, castb, CAST, NOP, 0, 0), // xA = !!xB, type specified by C // Control flow. xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++