diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 9ca96de05..593737065 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -1993,7 +1993,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { - build->Emit(OP_ADDI, value.RegNum, value.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, value.RegNum, value.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2077,7 +2077,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) ExpEmit assign(build, regtype); if (regtype == REGT_INT) { - build->Emit(OP_ADDI, assign.RegNum, out.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, assign.RegNum, out.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2094,7 +2094,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) if (regtype == REGT_INT) { build->Emit(OP_MOVE, out.RegNum, pointer.RegNum); - build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { @@ -2108,7 +2108,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) { if (regtype == REGT_INT) { - build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, (Token == TK_Incr) ? 1 : -1); + build->Emit(OP_ADDI, pointer.RegNum, pointer.RegNum, uint8_t((Token == TK_Incr) ? 1 : -1)); } else { diff --git a/src/scripting/vm/vm.h b/src/scripting/vm/vm.h index 670c5a982..ab1708e08 100644 --- a/src/scripting/vm/vm.h +++ b/src/scripting/vm/vm.h @@ -814,10 +814,10 @@ public: VM_UBYTE NumRegF; VM_UBYTE NumRegS; VM_UBYTE NumRegA; - VM_UBYTE NumKonstD; - VM_UBYTE NumKonstF; - VM_UBYTE NumKonstS; - VM_UBYTE NumKonstA; + VM_UHALF NumKonstD; + VM_UHALF NumKonstF; + VM_UHALF NumKonstS; + VM_UHALF NumKonstA; VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once VM_UBYTE NumArgs; // Number of arguments this function takes FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. diff --git a/src/scripting/vm/vmbuilder.cpp b/src/scripting/vm/vmbuilder.cpp index 042753d32..3ccf67f95 100644 --- a/src/scripting/vm/vmbuilder.cpp +++ b/src/scripting/vm/vmbuilder.cpp @@ -36,6 +36,19 @@ #include "info.h" #include "m_argv.h" #include "thingdef.h" +#include "doomerrors.h" + +struct VMRemap +{ + BYTE altOp, kReg, kType; +}; + + +#define xx(op, name, mode, alt, kreg, ktype) {OP_##alt, kreg, ktype } +VMRemap opRemap[NUM_OPS] = { +#include "vmops.h" +}; +#undef xx //========================================================================== // @@ -523,10 +536,75 @@ size_t VMFunctionBuilder::GetAddress() size_t VMFunctionBuilder::Emit(int opcode, int opa, int opb, int opc) { + static BYTE opcodes[] = { OP_LK, OP_LKF, OP_LKS, OP_LKP }; + assert(opcode >= 0 && opcode < NUM_OPS); - assert(opa >= 0 && opa <= 255); - assert(opb >= 0 && opb <= 255); - assert(opc >= 0 && opc <= 255); + assert(opa >= 0); + assert(opb >= 0); + assert(opc >= 0); + + + // The following were just asserts, meaning this would silently create broken code if there was an overflow + // if this happened in a release build. Not good. + // These are critical errors that need to be reported to the user. + // In addition, the limit of 256 constants can easily be exceeded with arrays so this had to be extended to + // 65535 by adding some checks here that map byte-limited instructions to alternatives that can handle larger indices. + // (See vmops.h for the remapping info.) + + // Note: OP_CMPS also needs treatment, but I do not expect constant overflow to become an issue with strings, so for now there is no handling. + + if (opa > 255) + { + if (opRemap[opcode].kReg != 1 || opa > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opa); + opcode = opRemap[opcode].altOp; + opa = emit.RegNum; + emit.Free(this); + } + if (opb > 255) + { + if (opRemap[opcode].kReg != 2 || opb > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opb); + opcode = opRemap[opcode].altOp; + opb = emit.RegNum; + emit.Free(this); + } + if (opc > 255) + { + if (opcode == OP_PARAM && (opb & REGT_KONST) && opc <= 32767) + { + int regtype = opb & REGT_TYPE; + opb = regtype; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opc = emit.RegNum; + emit.Free(this); + } + else + { + if (opRemap[opcode].kReg != 4 || opc > 32767) + { + I_Error("Register limit exceeded"); + } + int regtype = opRemap[opcode].kType; + ExpEmit emit(this, regtype); + Emit(opcodes[regtype], emit.RegNum, opc); + opcode = opRemap[opcode].altOp; + opc = emit.RegNum; + emit.Free(this); + } + } + if (opcode == OP_PARAM) { int chg; @@ -784,23 +862,31 @@ void FFunctionBuildList::Build() } // Emit code - item.Code->Emit(&buildit); - buildit.MakeFunction(sfunc); - sfunc->NumArgs = 0; - // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. - // For the VM a vector is 2 or 3 args, depending on size. - for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + try { - sfunc->NumArgs += s->GetRegCount(); - } + item.Code->Emit(&buildit); + buildit.MakeFunction(sfunc); + sfunc->NumArgs = 0; + // NumArgs for the VMFunction must be the amount of stack elements, which can differ from the amount of logical function arguments if vectors are in the list. + // For the VM a vector is 2 or 3 args, depending on size. + for (auto s : item.Func->Variants[0].Proto->ArgumentTypes) + { + sfunc->NumArgs += s->GetRegCount(); + } - if (dump != nullptr) + if (dump != nullptr) + { + DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); + codesize += sfunc->CodeSize; + } + sfunc->PrintableName = item.PrintableName; + sfunc->Unsafe = ctx.Unsafe; + } + catch (CRecoverableError &err) { - DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len()); - codesize += sfunc->CodeSize; + // catch errors from the code generator and pring something meaningful. + item.Code->ScriptPosition.Message(MSG_ERROR, "%s in %s", err.GetMessage(), item.PrintableName); } - sfunc->PrintableName = item.PrintableName; - sfunc->Unsafe = ctx.Unsafe; } delete item.Code; if (dump != nullptr) diff --git a/src/scripting/vm/vmdisasm.cpp b/src/scripting/vm/vmdisasm.cpp index c95699613..d8fc16433 100644 --- a/src/scripting/vm/vmdisasm.cpp +++ b/src/scripting/vm/vmdisasm.cpp @@ -147,7 +147,7 @@ const VMOpInfo OpInfo[NUM_OPS] = { -#define xx(op, name, mode) { #name, mode } +#define xx(op, name, mode, alt, kreg, ktype) { #name, mode } #include "vmops.h" }; diff --git a/src/scripting/vm/vmexec.h b/src/scripting/vm/vmexec.h index 6202de3bb..477c5ac97 100644 --- a/src/scripting/vm/vmexec.h +++ b/src/scripting/vm/vmexec.h @@ -8,7 +8,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret) #if COMPGOTO static const void * const ops[256] = { -#define xx(op,sym,mode) &&op +#define xx(op,sym,mode,alt,kreg,ktype) &&op #include "vmops.h" }; #endif @@ -425,12 +425,6 @@ begin: DoCast(reg, f, a, B, C); } NEXTOP; - OP(DYNCAST_R): - // UNDONE - NEXTOP; - OP(DYNCAST_K): - // UNDONE - NEXTOP; OP(TEST): ASSERTD(a); @@ -1315,42 +1309,23 @@ begin: OP(ADDV2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); fcp = ®.f[C]; - Do_ADDV2: fbp = ®.f[B]; reg.f[a] = fbp[0] + fcp[0]; reg.f[a+1] = fbp[1] + fcp[1]; NEXTOP; - OP(ADDV2_RK): - fcp = &konstf[C]; - goto Do_ADDV2; OP(SUBV2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); fbp = ®.f[B]; fcp = ®.f[C]; - Do_SUBV2: reg.f[a] = fbp[0] - fcp[0]; reg.f[a+1] = fbp[1] - fcp[1]; NEXTOP; - OP(SUBV2_RK): - ASSERTF(a+1); ASSERTF(B+1); ASSERTKF(C+1); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV2; - OP(SUBV2_KR): - ASSERTF(A+1); ASSERTKF(B+1); ASSERTF(C+1); - fbp = &konstf[B]; - fcp = ®.f[C]; - goto Do_SUBV2; OP(DOTV2_RR): ASSERTF(a); ASSERTF(B+1); ASSERTF(C+1); reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1]; NEXTOP; - OP(DOTV2_RK): - ASSERTF(a); ASSERTF(B+1); ASSERTKF(C+1); - reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1]; - NEXTOP; OP(MULVF2_RR): ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C); @@ -1414,50 +1389,30 @@ begin: OP(ADDV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fcp = ®.f[C]; - Do_ADDV3: fbp = ®.f[B]; reg.f[a] = fbp[0] + fcp[0]; reg.f[a+1] = fbp[1] + fcp[1]; reg.f[a+2] = fbp[2] + fcp[2]; NEXTOP; - OP(ADDV3_RK): - fcp = &konstf[C]; - goto Do_ADDV3; OP(SUBV3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fbp = ®.f[B]; fcp = ®.f[C]; - Do_SUBV3: reg.f[a] = fbp[0] - fcp[0]; reg.f[a+1] = fbp[1] - fcp[1]; reg.f[a+2] = fbp[2] - fcp[2]; NEXTOP; - OP(SUBV3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_SUBV3; - OP(SUBV3_KR): - ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = &konstf[B]; - fcp = ®.f[C]; - goto Do_SUBV3; OP(DOTV3_RR): ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2); reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1] + reg.f[B+2] * reg.f[C+2]; NEXTOP; - OP(DOTV3_RK): - ASSERTF(a); ASSERTF(B+2); ASSERTKF(C+2); - reg.f[a] = reg.f[B] * konstf[C] + reg.f[B+1] * konstf[C+1] + reg.f[B+2] * konstf[C+2]; - NEXTOP; OP(CROSSV_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); fbp = ®.f[B]; fcp = ®.f[C]; - Do_CROSSV: { double t[3]; t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0]; @@ -1466,46 +1421,24 @@ begin: reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2]; } NEXTOP; - OP(CROSSV_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; - OP(CROSSV_KR): - ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2); - fbp = ®.f[B]; - fcp = &konstf[C]; - goto Do_CROSSV; OP(MULVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; - Do_MULV3: reg.f[a] = fbp[0] * fc; reg.f[a+1] = fbp[1] * fc; reg.f[a+2] = fbp[2] * fc; NEXTOP; - OP(MULVF3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); - fc = konstf[C]; - fbp = ®.f[B]; - goto Do_MULV3; - OP(DIVVF3_RR): + OP(DIVVF3_RR): ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); fc = reg.f[C]; fbp = ®.f[B]; - Do_DIVV3: reg.f[a] = fbp[0] / fc; reg.f[a+1] = fbp[1] / fc; reg.f[a+2] = fbp[2] / fc; NEXTOP; - OP(DIVVF3_RK): - ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C); - fc = konstf[C]; - fbp = ®.f[B]; - goto Do_DIVV3; OP(LENV3): ASSERTF(a); ASSERTF(B+2); diff --git a/src/scripting/vm/vmframe.cpp b/src/scripting/vm/vmframe.cpp index b20c8ac89..f35c3718d 100644 --- a/src/scripting/vm/vmframe.cpp +++ b/src/scripting/vm/vmframe.cpp @@ -86,10 +86,10 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko { assert(Code == NULL); assert(numops > 0); - assert(numkonstd >= 0 && numkonstd <= 255); - assert(numkonstf >= 0 && numkonstf <= 255); - assert(numkonsts >= 0 && numkonsts <= 255); - assert(numkonsta >= 0 && numkonsta <= 255); + assert(numkonstd >= 0 && numkonstd <= 65535); + assert(numkonstf >= 0 && numkonstf <= 65535); + assert(numkonsts >= 0 && numkonsts <= 65535); + assert(numkonsta >= 0 && numkonsta <= 65535); void *mem = M_Malloc(numops * sizeof(VMOP) + numkonstd * sizeof(int) + numkonstf * sizeof(double) + diff --git a/src/scripting/vm/vmops.h b/src/scripting/vm/vmops.h index 6f78e9e4e..cf2a75746 100644 --- a/src/scripting/vm/vmops.h +++ b/src/scripting/vm/vmops.h @@ -1,251 +1,247 @@ #ifndef xx -#define xx(op, name, mode) OP_##op +#define xx(op, name, mode, alt, kreg, ktype) OP_##op #endif -xx(NOP, nop, NOP), // no operation +// first row is the opcode +// second row is the disassembly name +// third row is the disassembly flags +// fourth row is the alternative opcode if all 256 constant registers are exhausted. +// fifth row is the constant register index in the opcode +// sixth row is the constant register type. +// OP_PARAM and OP_CMPS need special treatment because they encode this information in the instruction. + +xx(NOP, nop, NOP, NOP, 0, 0), // no operation // Load constants. -xx(LI, li, LI), // load immediate signed 16-bit constant -xx(LK, lk, LKI), // load integer constant -xx(LKF, lk, LKF), // load float constant -xx(LKS, lk, LKS), // load string constant -xx(LKP, lk, LKP), // load pointer constant -xx(LK_R, lk, RIRII8), // load integer constant indexed -xx(LKF_R, lk, RFRII8), // load float constant indexed -xx(LKS_R, lk, RSRII8), // load string constant indexed -xx(LKP_R, lk, RPRII8), // load pointer constant indexed -xx(LFP, lf, LFP), // load frame pointer +xx(LI, li, LI, NOP, 0, 0), // load immediate signed 16-bit constant +xx(LK, lk, LKI, NOP, 0, 0), // load integer constant +xx(LKF, lk, LKF, NOP, 0, 0), // load float constant +xx(LKS, lk, LKS, NOP, 0, 0), // load string constant +xx(LKP, lk, LKP, NOP, 0, 0), // load pointer constant +xx(LK_R, lk, RIRII8, NOP, 0, 0), // load integer constant indexed +xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed +xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed +xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed +xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer // Load from memory. rA = *(rB + rkC) -xx(LB, lb, RIRPKI), // load byte -xx(LB_R, lb, RIRPRI), -xx(LH, lh, RIRPKI), // load halfword -xx(LH_R, lh, RIRPRI), -xx(LW, lw, RIRPKI), // load word -xx(LW_R, lw, RIRPRI), -xx(LBU, lbu, RIRPKI), // load byte unsigned -xx(LBU_R, lbu, RIRPRI), -xx(LHU, lhu, RIRPKI), // load halfword unsigned -xx(LHU_R, lhu, RIRPRI), -xx(LSP, lsp, RFRPKI), // load single-precision fp -xx(LSP_R, lsp, RFRPRI), -xx(LDP, ldp, RFRPKI), // load double-precision fp -xx(LDP_R, ldp, RFRPRI), -xx(LS, ls, RSRPKI), // load string -xx(LS_R, ls, RSRPRI), -xx(LO, lo, RPRPKI), // load object -xx(LO_R, lo, RPRPRI), -xx(LP, lp, RPRPKI), // load pointer -xx(LP_R, lp, RPRPRI), -xx(LV2, lv2, RVRPKI), // load vector2 -xx(LV2_R, lv2, RVRPRI), -xx(LV3, lv3, RVRPKI), // load vector3 -xx(LV3_R, lv3, RVRPRI), +xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte +xx(LB_R, lb, RIRPRI, NOP, 0, 0), +xx(LH, lh, RIRPKI, LH_R, 4, REGT_INT), // load halfword +xx(LH_R, lh, RIRPRI, NOP, 0, 0), +xx(LW, lw, RIRPKI, LW_R, 4, REGT_INT), // load word +xx(LW_R, lw, RIRPRI, NOP, 0, 0), +xx(LBU, lbu, RIRPKI, LBU_R, 4, REGT_INT), // load byte unsigned +xx(LBU_R, lbu, RIRPRI, NOP, 0, 0), +xx(LHU, lhu, RIRPKI, LHU_R, 4, REGT_INT), // load halfword unsigned +xx(LHU_R, lhu, RIRPRI, NOP, 0, 0), +xx(LSP, lsp, RFRPKI, LSP_R, 4, REGT_INT), // load single-precision fp +xx(LSP_R, lsp, RFRPRI, NOP, 0, 0), +xx(LDP, ldp, RFRPKI, LDP_R, 4, REGT_INT), // load double-precision fp +xx(LDP_R, ldp, RFRPRI, NOP, 0, 0), +xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string +xx(LS_R, ls, RSRPRI, NOP, 0, 0), +xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object +xx(LO_R, lo, RPRPRI, NOP, 0, 0), +xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer +xx(LP_R, lp, RPRPRI, NOP, 0, 0), +xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2 +xx(LV2_R, lv2, RVRPRI, NOP, 0, 0), +xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3 +xx(LV3_R, lv3, RVRPRI, NOP, 0, 0), -xx(LBIT, lbit, RIRPI8), // rA = !!(*rB & C) -- *rB is a byte +xx(LBIT, lbit, RIRPI8, NOP, 0, 0), // rA = !!(*rB & C) -- *rB is a byte // Store instructions. *(rA + rkC) = rB -xx(SB, sb, RPRIKI), // store byte -xx(SB_R, sb, RPRIRI), -xx(SH, sh, RPRIKI), // store halfword -xx(SH_R, sh, RPRIRI), -xx(SW, sw, RPRIKI), // store word -xx(SW_R, sw, RPRIRI), -xx(SSP, ssp, RPRFKI), // store single-precision fp -xx(SSP_R, ssp, RPRFRI), -xx(SDP, sdp, RPRFKI), // store double-precision fp -xx(SDP_R, sdp, RPRFRI), -xx(SS, ss, RPRSKI), // store string -xx(SS_R, ss, RPRSRI), -xx(SP, sp, RPRPKI), // store pointer -xx(SP_R, sp, RPRPRI), -xx(SV2, sv2, RPRVKI), // store vector2 -xx(SV2_R, sv2, RPRVRI), -xx(SV3, sv3, RPRVKI), // store vector3 -xx(SV3_R, sv3, RPRVRI), +xx(SB, sb, RPRIKI, SB_R, 4, REGT_INT), // store byte +xx(SB_R, sb, RPRIRI, NOP, 0, 0), +xx(SH, sh, RPRIKI, SH_R, 4, REGT_INT), // store halfword +xx(SH_R, sh, RPRIRI, NOP, 0, 0), +xx(SW, sw, RPRIKI, SW_R, 4, REGT_INT), // store word +xx(SW_R, sw, RPRIRI, NOP, 0, 0), +xx(SSP, ssp, RPRFKI, SSP_R, 4, REGT_INT), // store single-precision fp +xx(SSP_R, ssp, RPRFRI, NOP, 0, 0), +xx(SDP, sdp, RPRFKI, SDP_R, 4, REGT_INT), // store double-precision fp +xx(SDP_R, sdp, RPRFRI, NOP, 0, 0), +xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string +xx(SS_R, ss, RPRSRI, NOP, 0, 0), +xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer +xx(SP_R, sp, RPRPRI, NOP, 0, 0), +xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2 +xx(SV2_R, sv2, RPRVRI, NOP, 0, 0), +xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3 +xx(SV3_R, sv3, RPRVRI, NOP, 0, 0), -xx(SBIT, sbit, RPRII8), // *rA |= C if rB is true, *rA &= ~C otherwise +xx(SBIT, sbit, RPRII8, NOP, 0, 0), // *rA |= C if rB is true, *rA &= ~C otherwise // Move instructions. -xx(MOVE, mov, RIRI), // dA = dB -xx(MOVEF, mov, RFRF), // fA = fB -xx(MOVES, mov, RSRS), // sA = sB -xx(MOVEA, mov, RPRP), // aA = aB -xx(MOVEV2, mov2, RFRF), // fA = fB (2 elements) -xx(MOVEV3, mov3, RFRF), // fA = fB (3 elements) -xx(CAST, cast, CAST), // xA = xB, conversion specified by C -xx(DYNCAST_R, dyncast,RPRPRP), // aA = aB after casting to rkC (specifying a class) -xx(DYNCAST_K, dyncast,RPRPKP), +xx(MOVE, mov, RIRI, NOP, 0, 0), // dA = dB +xx(MOVEF, mov, RFRF, NOP, 0, 0), // fA = fB +xx(MOVES, mov, RSRS, NOP, 0, 0), // sA = sB +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 // Control flow. -xx(TEST, test, RII16), // if (dA != BC) then pc++ -xx(TESTN, testn, RII16), // if (dA != -BC) then pc++ -xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. -xx(IJMP, ijmp, RII16), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. -xx(PARAM, param, __BCP), // push parameter encoded in BC for function call (B=regtype, C=regnum) -xx(PARAMI, parami, I24), // push immediate, signed integer for function call -xx(CALL, call, RPI8I8), // Call function pkA with parameter count B and expected result count C -xx(CALL_K, call, KPI8I8), -xx(VTBL, vtbl, RPRPI8), // dereferences a virtual method table. -xx(TAIL, tail, RPI8), // Call+Ret in a single instruction -xx(TAIL_K, tail, KPI8), -xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) -xx(RET, ret, I8BCP), // Copy value from register encoded in BC to return value A, possibly returning -xx(RETI, reti, I8I16), // Copy immediate from BC to return value A, possibly returning -xx(TRY, try, I24), // When an exception is thrown, start searching for a handler at pc + ABC -xx(UNTRY, untry, I8), // Pop A entries off the exception stack -xx(THROW, throw, THROW), // A == 0: Throw exception object pB - // A == 1: Throw exception object pkB - // A >= 2: Throw VM exception of type BC -xx(CATCH, catch, CATCH), // A == 0: continue search on next try - // A == 1: continue execution at instruction immediately following CATCH (catches any exception) - // A == 2: (pB == ) then pc++ ; next instruction must JMP to another CATCH - // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH - // for A > 0, exception is stored in pC -xx(BOUND, bound, RII16), // if rA >= BC, throw exception +xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++ +xx(TESTN, testn, RII16, NOP, 0, 0), // if (dA != -BC) then pc++ +xx(JMP, jmp, I24, NOP, 0, 0), // pc += ABC -- The ABC fields contain a signed 24-bit offset. +xx(IJMP, ijmp, RII16, NOP, 0, 0), // pc += dA + BC -- BC is a signed offset. The target instruction must be a JMP. +xx(PARAM, param, __BCP, NOP, 0, 0), // push parameter encoded in BC for function call (B=regtype, C=regnum) +xx(PARAMI, parami, I24, NOP, 0, 0), // push immediate, signed integer for function call +xx(CALL, call, RPI8I8, NOP, 0, 0), // Call function pkA with parameter count B and expected result count C +xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER), +xx(VTBL, vtbl, RPRPI8, NOP, 0, 0), // dereferences a virtual method table. +xx(TAIL, tail, RPI8, NOP, 0, 0), // Call+Ret in a single instruction +xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER), +xx(RESULT, result, __BCP, NOP, 0, 0), // Result should go in register encoded in BC (in caller, after CALL) +xx(RET, ret, I8BCP, NOP, 0, 0), // Copy value from register encoded in BC to return value A, possibly returning +xx(RETI, reti, I8I16, NOP, 0, 0), // Copy immediate from BC to return value A, possibly returning +xx(TRY, try, I24, NOP, 0, 0), // When an exception is thrown, start searching for a handler at pc + ABC +xx(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack +xx(THROW, throw, THROW, NOP, 0, 0), // A == 0: Throw exception object pB + // A == 1: Throw exception object pkB + // A >= 2: Throw VM exception of type BC +xx(CATCH, catch, CATCH, NOP, 0, 0), // A == 0: continue search on next try + // A == 1: continue execution at instruction immediately following CATCH (catches any exception) + // A == 2: (pB == ) then pc++ ; next instruction must JMP to another CATCH + // A == 3: (pkB == ) then pc++ ; next instruction must JMP to another CATCH + // for A > 0, exception is stored in pC +xx(BOUND, bound, RII16, NOP, 0, 0), // if rA >= BC, throw exception // String instructions. -xx(CONCAT, concat, RSRSRS), // sA = sB..sC -xx(LENS, lens, RIRS), // dA = sB.Length -xx(CMPS, cmps, I8RXRX), // if ((skB op skC) != (A & 1)) then pc++ +xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC +xx(LENS, lens, RIRS, NOP, 0, 0), // dA = sB.Length +xx(CMPS, cmps, I8RXRX, NOP, 0, 0), // if ((skB op skC) != (A & 1)) then pc++ // Integer math. -xx(SLL_RR, sll, RIRIRI), // dA = dkB << diC -xx(SLL_RI, sll, RIRII8), -xx(SLL_KR, sll, RIKIRI), -xx(SRL_RR, srl, RIRIRI), // dA = dkB >> diC -- unsigned -xx(SRL_RI, srl, RIRII8), -xx(SRL_KR, srl, RIKIRI), -xx(SRA_RR, sra, RIRIRI), // dA = dkB >> diC -- signed -xx(SRA_RI, sra, RIRII8), -xx(SRA_KR, sra, RIKIRI), -xx(ADD_RR, add, RIRIRI), // dA = dB + dkC -xx(ADD_RK, add, RIRIKI), -xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant -xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC -xx(SUB_RK, sub, RIRIKI), -xx(SUB_KR, sub, RIKIRI), -xx(MUL_RR, mul, RIRIRI), // dA = dB * dkC -xx(MUL_RK, mul, RIRIKI), -xx(DIV_RR, div, RIRIRI), // dA = dkB / dkC (signed) -xx(DIV_RK, div, RIRIKI), -xx(DIV_KR, div, RIKIRI), -xx(DIVU_RR, divu, RIRIRI), // dA = dkB / dkC (unsigned) -xx(DIVU_RK, divu, RIRIKI), -xx(DIVU_KR, divu, RIKIRI), -xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC (signed) -xx(MOD_RK, mod, RIRIKI), -xx(MOD_KR, mod, RIKIRI), -xx(MODU_RR, modu, RIRIRI), // dA = dkB % dkC (unsigned) -xx(MODU_RK, modu, RIRIKI), -xx(MODU_KR, modu, RIKIRI), -xx(AND_RR, and, RIRIRI), // dA = dB & dkC -xx(AND_RK, and, RIRIKI), -xx(OR_RR, or, RIRIRI), // dA = dB | dkC -xx(OR_RK, or, RIRIKI), -xx(XOR_RR, xor, RIRIRI), // dA = dB ^ dkC -xx(XOR_RK, xor, RIRIKI), -xx(MIN_RR, min, RIRIRI), // dA = min(dB,dkC) -xx(MIN_RK, min, RIRIKI), -xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) -xx(MAX_RK, max, RIRIKI), -xx(ABS, abs, RIRI), // dA = abs(dB) -xx(NEG, neg, RIRI), // dA = -dB -xx(NOT, not, RIRI), // dA = ~dB -xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C -xx(ZAP_R, zap, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are one -xx(ZAP_I, zap, RIRII8), -xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero -xx(ZAPNOT_I, zapnot, RIRII8), -xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++ -xx(EQ_K, beq, CIRK), -xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++ -xx(LT_RK, blt, CIRK), -xx(LT_KR, blt, CIKR), -xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++ -xx(LE_RK, ble, CIRK), -xx(LE_KR, ble, CIKR), -xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned -xx(LTU_RK, bltu, CIRK), -xx(LTU_KR, bltu, CIKR), -xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned -xx(LEU_RK, bleu, CIRK), -xx(LEU_KR, bleu, CIKR), +xx(SLL_RR, sll, RIRIRI, NOP, 0, 0), // dA = dkB << diC +xx(SLL_RI, sll, RIRII8, NOP, 0, 0), +xx(SLL_KR, sll, RIKIRI, SLL_RR, 2, REGT_INT), +xx(SRL_RR, srl, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- unsigned +xx(SRL_RI, srl, RIRII8, NOP, 0, 0), +xx(SRL_KR, srl, RIKIRI, SRL_RR, 2, REGT_INT), +xx(SRA_RR, sra, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- signed +xx(SRA_RI, sra, RIRII8, NOP, 0, 0), +xx(SRA_KR, sra, RIKIRI, SRA_RR, 2, REGT_INT), +xx(ADD_RR, add, RIRIRI, NOP, 0, 0), // dA = dB + dkC +xx(ADD_RK, add, RIRIKI, ADD_RR, 4, REGT_INT), +xx(ADDI, addi, RIRIIs, NOP, 0, 0), // dA = dB + C -- C is a signed 8-bit constant +xx(SUB_RR, sub, RIRIRI, NOP, 0, 0), // dA = dkB - dkC +xx(SUB_RK, sub, RIRIKI, SUB_RR, 4, REGT_INT), +xx(SUB_KR, sub, RIKIRI, SUB_RR, 2, REGT_INT), +xx(MUL_RR, mul, RIRIRI, NOP, 0, 0), // dA = dB * dkC +xx(MUL_RK, mul, RIRIKI, MUL_RR, 4, REGT_INT), +xx(DIV_RR, div, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (signed) +xx(DIV_RK, div, RIRIKI, DIV_RR, 4, REGT_INT), +xx(DIV_KR, div, RIKIRI, DIV_RR, 2, REGT_INT), +xx(DIVU_RR, divu, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (unsigned) +xx(DIVU_RK, divu, RIRIKI, DIVU_RR,4, REGT_INT), +xx(DIVU_KR, divu, RIKIRI, DIVU_RR,2, REGT_INT), +xx(MOD_RR, mod, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (signed) +xx(MOD_RK, mod, RIRIKI, MOD_RR, 4, REGT_INT), +xx(MOD_KR, mod, RIKIRI, MOD_RR, 2, REGT_INT), +xx(MODU_RR, modu, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (unsigned) +xx(MODU_RK, modu, RIRIKI, MODU_RR,4, REGT_INT), +xx(MODU_KR, modu, RIKIRI, MODU_RR,2, REGT_INT), +xx(AND_RR, and, RIRIRI, NOP, 0, 0), // dA = dB & dkC +xx(AND_RK, and, RIRIKI, AND_RR, 4, REGT_INT), +xx(OR_RR, or, RIRIRI, NOP, 0, 0), // dA = dB | dkC +xx(OR_RK, or, RIRIKI, OR_RR, 4, REGT_INT), +xx(XOR_RR, xor, RIRIRI, NOP, 0, 0), // dA = dB ^ dkC +xx(XOR_RK, xor, RIRIKI, XOR_RR, 4, REGT_INT), +xx(MIN_RR, min, RIRIRI, NOP, 0, 0), // dA = min(dB,dkC) +xx(MIN_RK, min, RIRIKI, MIN_RR, 4, REGT_INT), +xx(MAX_RR, max, RIRIRI, NOP, 0, 0), // dA = max(dB,dkC) +xx(MAX_RK, max, RIRIKI, MAX_RR, 4, REGT_INT), +xx(ABS, abs, RIRI, NOP, 0, 0), // dA = abs(dB) +xx(NEG, neg, RIRI, NOP, 0, 0), // dA = -dB +xx(NOT, not, RIRI, NOP, 0, 0), // dA = ~dB +xx(SEXT, sext, RIRII8, NOP, 0, 0), // dA = dB, sign extended by shifting left then right by C +xx(ZAP_R, zap, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are one +xx(ZAP_I, zap, RIRII8, NOP, 0, 0), +xx(ZAPNOT_R, zapnot, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are zero +xx(ZAPNOT_I, zapnot, RIRII8, NOP, 0, 0), +xx(EQ_R, beq, CIRR, NOP, 0, 0), // if ((dB == dkC) != A) then pc++ +xx(EQ_K, beq, CIRK, EQ_R, 4, REGT_INT), +xx(LT_RR, blt, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ +xx(LT_RK, blt, CIRK, LT_RR, 4, REGT_INT), +xx(LT_KR, blt, CIKR, LT_RR, 2, REGT_INT), +xx(LE_RR, ble, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ +xx(LE_RK, ble, CIRK, LE_RR, 4, REGT_INT), +xx(LE_KR, ble, CIKR, LE_RR, 2, REGT_INT), +xx(LTU_RR, bltu, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ -- unsigned +xx(LTU_RK, bltu, CIRK, LTU_RR, 4, REGT_INT), +xx(LTU_KR, bltu, CIKR, LTU_RR, 2, REGT_INT), +xx(LEU_RR, bleu, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ -- unsigned +xx(LEU_RK, bleu, CIRK, LEU_RR, 4, REGT_INT), +xx(LEU_KR, bleu, CIKR, LEU_RR, 2, REGT_INT), // Double-precision floating point math. -xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC -xx(ADDF_RK, add, RFRFKF), -xx(SUBF_RR, sub, RFRFRF), // fA = fkB - fkC -xx(SUBF_RK, sub, RFRFKF), -xx(SUBF_KR, sub, RFKFRF), -xx(MULF_RR, mul, RFRFRF), // fA = fB * fkC -xx(MULF_RK, mul, RFRFKF), -xx(DIVF_RR, div, RFRFRF), // fA = fkB / fkC -xx(DIVF_RK, div, RFRFKF), -xx(DIVF_KR, div, RFKFRF), -xx(MODF_RR, mod, RFRFRF), // fA = fkB % fkC -xx(MODF_RK, mod, RFRFKF), -xx(MODF_KR, mod, RFKFRF), -xx(POWF_RR, pow, RFRFRF), // fA = fkB ** fkC -xx(POWF_RK, pow, RFRFKF), -xx(POWF_KR, pow, RFKFRF), -xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC) -xx(MINF_RK, min, RFRFKF), -xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) -xx(MAXF_RK, max, RFRFKF), -xx(ATAN2, atan2, RFRFRF), // fA = atan2(fB,fC), result is in degrees -xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C -xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++ -xx(EQF_K, beq, CFRK), -xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++ -xx(LTF_RK, blt, CFRK), -xx(LTF_KR, blt, CFKR), -xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++ -xx(LEF_RK, ble, CFRK), -xx(LEF_KR, ble, CFKR), +xx(ADDF_RR, add, RFRFRF, NOP, 0, 0), // fA = fB + fkC +xx(ADDF_RK, add, RFRFKF, ADDF_RR,4, REGT_FLOAT), +xx(SUBF_RR, sub, RFRFRF, NOP, 0, 0), // fA = fkB - fkC +xx(SUBF_RK, sub, RFRFKF, SUBF_RR,4, REGT_FLOAT), +xx(SUBF_KR, sub, RFKFRF, SUBF_RR,2, REGT_FLOAT), +xx(MULF_RR, mul, RFRFRF, NOP, 0, 0), // fA = fB * fkC +xx(MULF_RK, mul, RFRFKF, MULF_RR,4, REGT_FLOAT), +xx(DIVF_RR, div, RFRFRF, NOP, 0, 0), // fA = fkB / fkC +xx(DIVF_RK, div, RFRFKF, DIVF_RR,4, REGT_FLOAT), +xx(DIVF_KR, div, RFKFRF, DIVF_RR,2, REGT_FLOAT), +xx(MODF_RR, mod, RFRFRF, NOP, 0, 0), // fA = fkB % fkC +xx(MODF_RK, mod, RFRFKF, MODF_RR,4, REGT_FLOAT), +xx(MODF_KR, mod, RFKFRF, MODF_RR,4, REGT_FLOAT), +xx(POWF_RR, pow, RFRFRF, NOP, 0, 0), // fA = fkB ** fkC +xx(POWF_RK, pow, RFRFKF, POWF_RR,4, REGT_FLOAT), +xx(POWF_KR, pow, RFKFRF, POWF_RR,2, REGT_FLOAT), +xx(MINF_RR, min, RFRFRF, NOP, 0, 0), // fA = min(fB),fkC) +xx(MINF_RK, min, RFRFKF, MINF_RR,4, REGT_FLOAT), +xx(MAXF_RR, max, RFRFRF, NOP, 0, 0), // fA = max(fB),fkC) +xx(MAXF_RK, max, RFRFKF, MAXF_RR,4, REGT_FLOAT), +xx(ATAN2, atan2, RFRFRF, NOP, 0, 0), // fA = atan2(fB,fC), result is in degrees +xx(FLOP, flop, RFRFI8, NOP, 0, 0), // fA = f(fB), where function is selected by C +xx(EQF_R, beq, CFRR, NOP, 0, 0), // if ((fB == fkC) != (A & 1)) then pc++ +xx(EQF_K, beq, CFRK, EQF_R, 4, REGT_FLOAT), +xx(LTF_RR, blt, CFRR, NOP, 0, 0), // if ((fkB < fkC) != (A & 1)) then pc++ +xx(LTF_RK, blt, CFRK, LTF_RR, 4, REGT_FLOAT), +xx(LTF_KR, blt, CFKR, LTF_RR, 2, REGT_FLOAT), +xx(LEF_RR, ble, CFRR, NOP, 0, 0), // if ((fkb <= fkC) != (A & 1)) then pc++ +xx(LEF_RK, ble, CFRK, LEF_RR, 4, REGT_FLOAT), +xx(LEF_KR, ble, CFKR, LEF_RR, 2, REGT_FLOAT), // Vector math. (2D) -xx(NEGV2, negv2, RVRV), // vA = -vB -xx(ADDV2_RR, addv2, RVRVRV), // vA = vB + vkC -xx(ADDV2_RK, addv2, RVRVKV), -xx(SUBV2_RR, subv2, RVRVRV), // vA = vkB - vkC -xx(SUBV2_RK, subv2, RVRVKV), -xx(SUBV2_KR, subv2, RVKVRV), -xx(DOTV2_RR, dotv2, RVRVRV), // va = vB dot vkC -xx(DOTV2_RK, dotv2, RVRVKV), -xx(MULVF2_RR, mulv2, RVRVRF), // vA = vkB * fkC -xx(MULVF2_RK, mulv2, RVRVKF), -xx(DIVVF2_RR, divv2, RVRVRF), // vA = vkB / fkC -xx(DIVVF2_RK, divv2, RVRVKF), -xx(LENV2, lenv2, RFRV), // fA = vB.Length -xx(EQV2_R, beqv2, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) -xx(EQV2_K, beqv2, CVRK), +xx(NEGV2, negv2, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV2_RR, addv2, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV2_RR, subv2, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV2_RR, dotv2, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(MULVF2_RR, mulv2, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF2_RK, mulv2, RVRVKF, MULVF2_RR,4, REGT_FLOAT), +xx(DIVVF2_RR, divv2, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF2_RK, divv2, RVRVKF, DIVVF2_RR,4, REGT_FLOAT), +xx(LENV2, lenv2, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV2_R, beqv2, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 32) +xx(EQV2_K, beqv2, CVRK, NOP, 0, 0), // this will never be used. // Vector math (3D) -xx(NEGV3, negv3, RVRV), // vA = -vB -xx(ADDV3_RR, addv3, RVRVRV), // vA = vB + vkC -xx(ADDV3_RK, addv3, RVRVKV), -xx(SUBV3_RR, subv3, RVRVRV), // vA = vkB - vkC -xx(SUBV3_RK, subv3, RVRVKV), -xx(SUBV3_KR, subv3, RVKVRV), -xx(DOTV3_RR, dotv3, RVRVRV), // va = vB dot vkC -xx(DOTV3_RK, dotv3, RVRVKV), -xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC -xx(CROSSV_RK, crossv, RVRVKV), -xx(CROSSV_KR, crossv, RVKVRV), -xx(MULVF3_RR, mulv3, RVRVRF), // vA = vkB * fkC -xx(MULVF3_RK, mulv3, RVRVKF), -xx(DIVVF3_RR, divv3, RVRVRF), // vA = vkB / fkC -xx(DIVVF3_RK, divv3, RVRVKF), -xx(LENV3, lenv3, RFRV), // fA = vB.Length -xx(EQV3_R, beqv3, CVRR), // if ((vB == vkC) != A) then pc++ (inexact if A & 33) -xx(EQV3_K, beqv3, CVRK), +xx(NEGV3, negv3, RVRV, NOP, 0, 0), // vA = -vB +xx(ADDV3_RR, addv3, RVRVRV, NOP, 0, 0), // vA = vB + vkC +xx(SUBV3_RR, subv3, RVRVRV, NOP, 0, 0), // vA = vkB - vkC +xx(DOTV3_RR, dotv3, RVRVRV, NOP, 0, 0), // va = vB dot vkC +xx(CROSSV_RR, crossv, RVRVRV, NOP, 0, 0), // vA = vkB cross vkC +xx(MULVF3_RR, mulv3, RVRVRF, NOP, 0, 0), // vA = vkB * fkC +xx(MULVF3_RK, mulv3, RVRVKF, MULVF3_RR,4, REGT_FLOAT), +xx(DIVVF3_RR, divv3, RVRVRF, NOP, 0, 0), // vA = vkB / fkC +xx(DIVVF3_RK, divv3, RVRVKF, DIVVF3_RR,4, REGT_FLOAT), +xx(LENV3, lenv3, RFRV, NOP, 0, 0), // fA = vB.Length +xx(EQV3_R, beqv3, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 33) +xx(EQV3_K, beqv3, CVRK, NOP, 0, 0), // this will never be used. // Pointer math. -xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC -xx(ADDA_RK, add, RPRPKI), -xx(SUBA, sub, RIRPRP), // dA = pB - pC -xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++ -xx(EQA_K, beq, CPRK), +xx(ADDA_RR, add, RPRPRI, NOP, 0, 0), // pA = pB + dkC +xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_POINTER), +xx(SUBA, sub, RIRPRP, NOP, 0, 0), // dA = pB - pC +xx(EQA_R, beq, CPRR, NOP, 0, 0), // if ((pB == pkC) != A) then pc++ +xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER), #undef xx