- removed all constant versions of vector instructions. The vector code does not use compound constants so there's no need to have instructions for them.

- fixed: The code generator had no good safeguards for exceeding the maximum amount of registers.

All there was was a handful of pitiful asserts which in production code do nothing at all but generate broken output.
Even worse, the VM was hardwired to at most 255 constants per type per function by storing the constant count in a byte! This has been extended to 65535, but since many instructions only have a byte available for the constant index, a workaround had to be added to do a two-instruction setup if larger indices are needed.
This commit is contained in:
Christoph Oelckers 2016-11-20 23:00:05 +01:00
parent 1c2c26eb08
commit e93961da96
7 changed files with 336 additions and 321 deletions

View file

@ -1993,7 +1993,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
if (regtype == REGT_INT) 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 else
{ {
@ -2077,7 +2077,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
ExpEmit assign(build, regtype); ExpEmit assign(build, regtype);
if (regtype == REGT_INT) 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 else
{ {
@ -2094,7 +2094,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
if (regtype == REGT_INT) if (regtype == REGT_INT)
{ {
build->Emit(OP_MOVE, out.RegNum, pointer.RegNum); 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 else
{ {
@ -2108,7 +2108,7 @@ ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build)
{ {
if (regtype == REGT_INT) 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 else
{ {

View file

@ -814,10 +814,10 @@ public:
VM_UBYTE NumRegF; VM_UBYTE NumRegF;
VM_UBYTE NumRegS; VM_UBYTE NumRegS;
VM_UBYTE NumRegA; VM_UBYTE NumRegA;
VM_UBYTE NumKonstD; VM_UHALF NumKonstD;
VM_UBYTE NumKonstF; VM_UHALF NumKonstF;
VM_UBYTE NumKonstS; VM_UHALF NumKonstS;
VM_UBYTE NumKonstA; VM_UHALF NumKonstA;
VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once VM_UHALF MaxParam; // Maximum number of parameters this function has on the stack at once
VM_UBYTE NumArgs; // Number of arguments this function takes 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. FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong.

View file

@ -36,6 +36,19 @@
#include "info.h" #include "info.h"
#include "m_argv.h" #include "m_argv.h"
#include "thingdef.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) 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(opcode >= 0 && opcode < NUM_OPS);
assert(opa >= 0 && opa <= 255); assert(opa >= 0);
assert(opb >= 0 && opb <= 255); assert(opb >= 0);
assert(opc >= 0 && opc <= 255); 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) if (opcode == OP_PARAM)
{ {
int chg; int chg;
@ -784,23 +862,31 @@ void FFunctionBuildList::Build()
} }
// Emit code // Emit code
item.Code->Emit(&buildit); try
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(); 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()); DumpFunction(dump, sfunc, item.PrintableName.GetChars(), (int)item.PrintableName.Len());
codesize += sfunc->CodeSize; codesize += sfunc->CodeSize;
}
sfunc->PrintableName = item.PrintableName;
sfunc->Unsafe = ctx.Unsafe;
}
catch (CRecoverableError &err)
{
// 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; delete item.Code;
if (dump != nullptr) if (dump != nullptr)

View file

@ -147,7 +147,7 @@
const VMOpInfo OpInfo[NUM_OPS] = 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" #include "vmops.h"
}; };

View file

@ -8,7 +8,7 @@ static int Exec(VMFrameStack *stack, const VMOP *pc, VMReturn *ret, int numret)
#if COMPGOTO #if COMPGOTO
static const void * const ops[256] = static const void * const ops[256] =
{ {
#define xx(op,sym,mode) &&op #define xx(op,sym,mode,alt,kreg,ktype) &&op
#include "vmops.h" #include "vmops.h"
}; };
#endif #endif
@ -425,12 +425,6 @@ begin:
DoCast(reg, f, a, B, C); DoCast(reg, f, a, B, C);
} }
NEXTOP; NEXTOP;
OP(DYNCAST_R):
// UNDONE
NEXTOP;
OP(DYNCAST_K):
// UNDONE
NEXTOP;
OP(TEST): OP(TEST):
ASSERTD(a); ASSERTD(a);
@ -1315,42 +1309,23 @@ begin:
OP(ADDV2_RR): OP(ADDV2_RR):
ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1);
fcp = &reg.f[C]; fcp = &reg.f[C];
Do_ADDV2:
fbp = &reg.f[B]; fbp = &reg.f[B];
reg.f[a] = fbp[0] + fcp[0]; reg.f[a] = fbp[0] + fcp[0];
reg.f[a+1] = fbp[1] + fcp[1]; reg.f[a+1] = fbp[1] + fcp[1];
NEXTOP; NEXTOP;
OP(ADDV2_RK):
fcp = &konstf[C];
goto Do_ADDV2;
OP(SUBV2_RR): OP(SUBV2_RR):
ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1); ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C+1);
fbp = &reg.f[B]; fbp = &reg.f[B];
fcp = &reg.f[C]; fcp = &reg.f[C];
Do_SUBV2:
reg.f[a] = fbp[0] - fcp[0]; reg.f[a] = fbp[0] - fcp[0];
reg.f[a+1] = fbp[1] - fcp[1]; reg.f[a+1] = fbp[1] - fcp[1];
NEXTOP; NEXTOP;
OP(SUBV2_RK):
ASSERTF(a+1); ASSERTF(B+1); ASSERTKF(C+1);
fbp = &reg.f[B];
fcp = &konstf[C];
goto Do_SUBV2;
OP(SUBV2_KR):
ASSERTF(A+1); ASSERTKF(B+1); ASSERTF(C+1);
fbp = &konstf[B];
fcp = &reg.f[C];
goto Do_SUBV2;
OP(DOTV2_RR): OP(DOTV2_RR):
ASSERTF(a); ASSERTF(B+1); ASSERTF(C+1); 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]; reg.f[a] = reg.f[B] * reg.f[C] + reg.f[B+1] * reg.f[C+1];
NEXTOP; 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): OP(MULVF2_RR):
ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C); ASSERTF(a+1); ASSERTF(B+1); ASSERTF(C);
@ -1414,50 +1389,30 @@ begin:
OP(ADDV3_RR): OP(ADDV3_RR):
ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
fcp = &reg.f[C]; fcp = &reg.f[C];
Do_ADDV3:
fbp = &reg.f[B]; fbp = &reg.f[B];
reg.f[a] = fbp[0] + fcp[0]; reg.f[a] = fbp[0] + fcp[0];
reg.f[a+1] = fbp[1] + fcp[1]; reg.f[a+1] = fbp[1] + fcp[1];
reg.f[a+2] = fbp[2] + fcp[2]; reg.f[a+2] = fbp[2] + fcp[2];
NEXTOP; NEXTOP;
OP(ADDV3_RK):
fcp = &konstf[C];
goto Do_ADDV3;
OP(SUBV3_RR): OP(SUBV3_RR):
ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
fbp = &reg.f[B]; fbp = &reg.f[B];
fcp = &reg.f[C]; fcp = &reg.f[C];
Do_SUBV3:
reg.f[a] = fbp[0] - fcp[0]; reg.f[a] = fbp[0] - fcp[0];
reg.f[a+1] = fbp[1] - fcp[1]; reg.f[a+1] = fbp[1] - fcp[1];
reg.f[a+2] = fbp[2] - fcp[2]; reg.f[a+2] = fbp[2] - fcp[2];
NEXTOP; NEXTOP;
OP(SUBV3_RK):
ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2);
fbp = &reg.f[B];
fcp = &konstf[C];
goto Do_SUBV3;
OP(SUBV3_KR):
ASSERTF(A+2); ASSERTKF(B+2); ASSERTF(C+2);
fbp = &konstf[B];
fcp = &reg.f[C];
goto Do_SUBV3;
OP(DOTV3_RR): OP(DOTV3_RR):
ASSERTF(a); ASSERTF(B+2); ASSERTF(C+2); 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]; 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; 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): OP(CROSSV_RR):
ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2); ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C+2);
fbp = &reg.f[B]; fbp = &reg.f[B];
fcp = &reg.f[C]; fcp = &reg.f[C];
Do_CROSSV:
{ {
double t[3]; double t[3];
t[2] = fbp[0] * fcp[1] - fbp[1] * fcp[0]; 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]; reg.f[a] = t[0]; reg.f[a+1] = t[1]; reg.f[a+2] = t[2];
} }
NEXTOP; NEXTOP;
OP(CROSSV_RK):
ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C+2);
fbp = &reg.f[B];
fcp = &konstf[C];
goto Do_CROSSV;
OP(CROSSV_KR):
ASSERTF(a+2); ASSERTKF(B+2); ASSERTF(C+2);
fbp = &reg.f[B];
fcp = &konstf[C];
goto Do_CROSSV;
OP(MULVF3_RR): OP(MULVF3_RR):
ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C);
fc = reg.f[C]; fc = reg.f[C];
fbp = &reg.f[B]; fbp = &reg.f[B];
Do_MULV3:
reg.f[a] = fbp[0] * fc; reg.f[a] = fbp[0] * fc;
reg.f[a+1] = fbp[1] * fc; reg.f[a+1] = fbp[1] * fc;
reg.f[a+2] = fbp[2] * fc; reg.f[a+2] = fbp[2] * fc;
NEXTOP; NEXTOP;
OP(MULVF3_RK):
ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C);
fc = konstf[C];
fbp = &reg.f[B];
goto Do_MULV3;
OP(DIVVF3_RR): OP(DIVVF3_RR):
ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C); ASSERTF(a+2); ASSERTF(B+2); ASSERTF(C);
fc = reg.f[C]; fc = reg.f[C];
fbp = &reg.f[B]; fbp = &reg.f[B];
Do_DIVV3:
reg.f[a] = fbp[0] / fc; reg.f[a] = fbp[0] / fc;
reg.f[a+1] = fbp[1] / fc; reg.f[a+1] = fbp[1] / fc;
reg.f[a+2] = fbp[2] / fc; reg.f[a+2] = fbp[2] / fc;
NEXTOP; NEXTOP;
OP(DIVVF3_RK):
ASSERTF(a+2); ASSERTF(B+2); ASSERTKF(C);
fc = konstf[C];
fbp = &reg.f[B];
goto Do_DIVV3;
OP(LENV3): OP(LENV3):
ASSERTF(a); ASSERTF(B+2); ASSERTF(a); ASSERTF(B+2);

View file

@ -86,10 +86,10 @@ void VMScriptFunction::Alloc(int numops, int numkonstd, int numkonstf, int numko
{ {
assert(Code == NULL); assert(Code == NULL);
assert(numops > 0); assert(numops > 0);
assert(numkonstd >= 0 && numkonstd <= 255); assert(numkonstd >= 0 && numkonstd <= 65535);
assert(numkonstf >= 0 && numkonstf <= 255); assert(numkonstf >= 0 && numkonstf <= 65535);
assert(numkonsts >= 0 && numkonsts <= 255); assert(numkonsts >= 0 && numkonsts <= 65535);
assert(numkonsta >= 0 && numkonsta <= 255); assert(numkonsta >= 0 && numkonsta <= 65535);
void *mem = M_Malloc(numops * sizeof(VMOP) + void *mem = M_Malloc(numops * sizeof(VMOP) +
numkonstd * sizeof(int) + numkonstd * sizeof(int) +
numkonstf * sizeof(double) + numkonstf * sizeof(double) +

View file

@ -1,251 +1,247 @@
#ifndef xx #ifndef xx
#define xx(op, name, mode) OP_##op #define xx(op, name, mode, alt, kreg, ktype) OP_##op
#endif #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. // Load constants.
xx(LI, li, LI), // load immediate signed 16-bit constant xx(LI, li, LI, NOP, 0, 0), // load immediate signed 16-bit constant
xx(LK, lk, LKI), // load integer constant xx(LK, lk, LKI, NOP, 0, 0), // load integer constant
xx(LKF, lk, LKF), // load float constant xx(LKF, lk, LKF, NOP, 0, 0), // load float constant
xx(LKS, lk, LKS), // load string constant xx(LKS, lk, LKS, NOP, 0, 0), // load string constant
xx(LKP, lk, LKP), // load pointer constant xx(LKP, lk, LKP, NOP, 0, 0), // load pointer constant
xx(LK_R, lk, RIRII8), // load integer constant indexed xx(LK_R, lk, RIRII8, NOP, 0, 0), // load integer constant indexed
xx(LKF_R, lk, RFRII8), // load float constant indexed xx(LKF_R, lk, RFRII8, NOP, 0, 0), // load float constant indexed
xx(LKS_R, lk, RSRII8), // load string constant indexed xx(LKS_R, lk, RSRII8, NOP, 0, 0), // load string constant indexed
xx(LKP_R, lk, RPRII8), // load pointer constant indexed xx(LKP_R, lk, RPRII8, NOP, 0, 0), // load pointer constant indexed
xx(LFP, lf, LFP), // load frame pointer xx(LFP, lf, LFP, NOP, 0, 0), // load frame pointer
// Load from memory. rA = *(rB + rkC) // Load from memory. rA = *(rB + rkC)
xx(LB, lb, RIRPKI), // load byte xx(LB, lb, RIRPKI, LB_R, 4, REGT_INT), // load byte
xx(LB_R, lb, RIRPRI), xx(LB_R, lb, RIRPRI, NOP, 0, 0),
xx(LH, lh, RIRPKI), // load halfword xx(LH, lh, RIRPKI, LH_R, 4, REGT_INT), // load halfword
xx(LH_R, lh, RIRPRI), xx(LH_R, lh, RIRPRI, NOP, 0, 0),
xx(LW, lw, RIRPKI), // load word xx(LW, lw, RIRPKI, LW_R, 4, REGT_INT), // load word
xx(LW_R, lw, RIRPRI), xx(LW_R, lw, RIRPRI, NOP, 0, 0),
xx(LBU, lbu, RIRPKI), // load byte unsigned xx(LBU, lbu, RIRPKI, LBU_R, 4, REGT_INT), // load byte unsigned
xx(LBU_R, lbu, RIRPRI), xx(LBU_R, lbu, RIRPRI, NOP, 0, 0),
xx(LHU, lhu, RIRPKI), // load halfword unsigned xx(LHU, lhu, RIRPKI, LHU_R, 4, REGT_INT), // load halfword unsigned
xx(LHU_R, lhu, RIRPRI), xx(LHU_R, lhu, RIRPRI, NOP, 0, 0),
xx(LSP, lsp, RFRPKI), // load single-precision fp xx(LSP, lsp, RFRPKI, LSP_R, 4, REGT_INT), // load single-precision fp
xx(LSP_R, lsp, RFRPRI), xx(LSP_R, lsp, RFRPRI, NOP, 0, 0),
xx(LDP, ldp, RFRPKI), // load double-precision fp xx(LDP, ldp, RFRPKI, LDP_R, 4, REGT_INT), // load double-precision fp
xx(LDP_R, ldp, RFRPRI), xx(LDP_R, ldp, RFRPRI, NOP, 0, 0),
xx(LS, ls, RSRPKI), // load string xx(LS, ls, RSRPKI, LS_R, 4, REGT_INT), // load string
xx(LS_R, ls, RSRPRI), xx(LS_R, ls, RSRPRI, NOP, 0, 0),
xx(LO, lo, RPRPKI), // load object xx(LO, lo, RPRPKI, LO_R, 4, REGT_INT), // load object
xx(LO_R, lo, RPRPRI), xx(LO_R, lo, RPRPRI, NOP, 0, 0),
xx(LP, lp, RPRPKI), // load pointer xx(LP, lp, RPRPKI, LP_R, 4, REGT_INT), // load pointer
xx(LP_R, lp, RPRPRI), xx(LP_R, lp, RPRPRI, NOP, 0, 0),
xx(LV2, lv2, RVRPKI), // load vector2 xx(LV2, lv2, RVRPKI, LV2_R, 4, REGT_INT), // load vector2
xx(LV2_R, lv2, RVRPRI), xx(LV2_R, lv2, RVRPRI, NOP, 0, 0),
xx(LV3, lv3, RVRPKI), // load vector3 xx(LV3, lv3, RVRPKI, LV3_R, 4, REGT_INT), // load vector3
xx(LV3_R, lv3, RVRPRI), 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 // Store instructions. *(rA + rkC) = rB
xx(SB, sb, RPRIKI), // store byte xx(SB, sb, RPRIKI, SB_R, 4, REGT_INT), // store byte
xx(SB_R, sb, RPRIRI), xx(SB_R, sb, RPRIRI, NOP, 0, 0),
xx(SH, sh, RPRIKI), // store halfword xx(SH, sh, RPRIKI, SH_R, 4, REGT_INT), // store halfword
xx(SH_R, sh, RPRIRI), xx(SH_R, sh, RPRIRI, NOP, 0, 0),
xx(SW, sw, RPRIKI), // store word xx(SW, sw, RPRIKI, SW_R, 4, REGT_INT), // store word
xx(SW_R, sw, RPRIRI), xx(SW_R, sw, RPRIRI, NOP, 0, 0),
xx(SSP, ssp, RPRFKI), // store single-precision fp xx(SSP, ssp, RPRFKI, SSP_R, 4, REGT_INT), // store single-precision fp
xx(SSP_R, ssp, RPRFRI), xx(SSP_R, ssp, RPRFRI, NOP, 0, 0),
xx(SDP, sdp, RPRFKI), // store double-precision fp xx(SDP, sdp, RPRFKI, SDP_R, 4, REGT_INT), // store double-precision fp
xx(SDP_R, sdp, RPRFRI), xx(SDP_R, sdp, RPRFRI, NOP, 0, 0),
xx(SS, ss, RPRSKI), // store string xx(SS, ss, RPRSKI, SS_R, 4, REGT_INT), // store string
xx(SS_R, ss, RPRSRI), xx(SS_R, ss, RPRSRI, NOP, 0, 0),
xx(SP, sp, RPRPKI), // store pointer xx(SP, sp, RPRPKI, SP_R, 4, REGT_INT), // store pointer
xx(SP_R, sp, RPRPRI), xx(SP_R, sp, RPRPRI, NOP, 0, 0),
xx(SV2, sv2, RPRVKI), // store vector2 xx(SV2, sv2, RPRVKI, SV2_R, 4, REGT_INT), // store vector2
xx(SV2_R, sv2, RPRVRI), xx(SV2_R, sv2, RPRVRI, NOP, 0, 0),
xx(SV3, sv3, RPRVKI), // store vector3 xx(SV3, sv3, RPRVKI, SV3_R, 4, REGT_INT), // store vector3
xx(SV3_R, sv3, RPRVRI), 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. // Move instructions.
xx(MOVE, mov, RIRI), // dA = dB xx(MOVE, mov, RIRI, NOP, 0, 0), // dA = dB
xx(MOVEF, mov, RFRF), // fA = fB xx(MOVEF, mov, RFRF, NOP, 0, 0), // fA = fB
xx(MOVES, mov, RSRS), // sA = sB xx(MOVES, mov, RSRS, NOP, 0, 0), // sA = sB
xx(MOVEA, mov, RPRP), // aA = aB xx(MOVEA, mov, RPRP, NOP, 0, 0), // aA = aB
xx(MOVEV2, mov2, RFRF), // fA = fB (2 elements) xx(MOVEV2, mov2, RFRF, NOP, 0, 0), // fA = fB (2 elements)
xx(MOVEV3, mov3, RFRF), // fA = fB (3 elements) xx(MOVEV3, mov3, RFRF, NOP, 0, 0), // fA = fB (3 elements)
xx(CAST, cast, CAST), // xA = xB, conversion specified by C xx(CAST, cast, CAST, NOP, 0, 0), // 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),
// Control flow. // Control flow.
xx(TEST, test, RII16), // if (dA != BC) then pc++ xx(TEST, test, RII16, NOP, 0, 0), // if (dA != BC) then pc++
xx(TESTN, testn, RII16), // if (dA != -BC) then pc++ xx(TESTN, testn, RII16, NOP, 0, 0), // if (dA != -BC) then pc++
xx(JMP, jmp, I24), // pc += ABC -- The ABC fields contain a signed 24-bit offset. xx(JMP, jmp, I24, NOP, 0, 0), // 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(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), // push parameter encoded in BC for function call (B=regtype, C=regnum) xx(PARAM, param, __BCP, NOP, 0, 0), // push parameter encoded in BC for function call (B=regtype, C=regnum)
xx(PARAMI, parami, I24), // push immediate, signed integer for function call xx(PARAMI, parami, I24, NOP, 0, 0), // 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, call, RPI8I8, NOP, 0, 0), // Call function pkA with parameter count B and expected result count C
xx(CALL_K, call, KPI8I8), xx(CALL_K, call, KPI8I8, CALL, 1, REGT_POINTER),
xx(VTBL, vtbl, RPRPI8), // dereferences a virtual method table. xx(VTBL, vtbl, RPRPI8, NOP, 0, 0), // dereferences a virtual method table.
xx(TAIL, tail, RPI8), // Call+Ret in a single instruction xx(TAIL, tail, RPI8, NOP, 0, 0), // Call+Ret in a single instruction
xx(TAIL_K, tail, KPI8), xx(TAIL_K, tail, KPI8, TAIL, 1, REGT_POINTER),
xx(RESULT, result, __BCP), // Result should go in register encoded in BC (in caller, after CALL) xx(RESULT, result, __BCP, NOP, 0, 0), // 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(RET, ret, I8BCP, NOP, 0, 0), // 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(RETI, reti, I8I16, NOP, 0, 0), // 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(TRY, try, I24, NOP, 0, 0), // 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(UNTRY, untry, I8, NOP, 0, 0), // Pop A entries off the exception stack
xx(THROW, throw, THROW), // A == 0: Throw exception object pB xx(THROW, throw, THROW, NOP, 0, 0), // A == 0: Throw exception object pB
// A == 1: Throw exception object pkB // A == 1: Throw exception object pkB
// A >= 2: Throw VM exception of type BC // A >= 2: Throw VM exception of type BC
xx(CATCH, catch, CATCH), // A == 0: continue search on next try 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 == 1: continue execution at instruction immediately following CATCH (catches any exception)
// A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH // A == 2: (pB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH // A == 3: (pkB == <type of exception thrown>) then pc++ ; next instruction must JMP to another CATCH
// for A > 0, exception is stored in pC // for A > 0, exception is stored in pC
xx(BOUND, bound, RII16), // if rA >= BC, throw exception xx(BOUND, bound, RII16, NOP, 0, 0), // if rA >= BC, throw exception
// String instructions. // String instructions.
xx(CONCAT, concat, RSRSRS), // sA = sB..sC xx(CONCAT, concat, RSRSRS, NOP, 0, 0), // sA = sB..sC
xx(LENS, lens, RIRS), // dA = sB.Length xx(LENS, lens, RIRS, NOP, 0, 0), // dA = sB.Length
xx(CMPS, cmps, I8RXRX), // if ((skB op skC) != (A & 1)) then pc++ xx(CMPS, cmps, I8RXRX, NOP, 0, 0), // if ((skB op skC) != (A & 1)) then pc++
// Integer math. // Integer math.
xx(SLL_RR, sll, RIRIRI), // dA = dkB << diC xx(SLL_RR, sll, RIRIRI, NOP, 0, 0), // dA = dkB << diC
xx(SLL_RI, sll, RIRII8), xx(SLL_RI, sll, RIRII8, NOP, 0, 0),
xx(SLL_KR, sll, RIKIRI), xx(SLL_KR, sll, RIKIRI, SLL_RR, 2, REGT_INT),
xx(SRL_RR, srl, RIRIRI), // dA = dkB >> diC -- unsigned xx(SRL_RR, srl, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- unsigned
xx(SRL_RI, srl, RIRII8), xx(SRL_RI, srl, RIRII8, NOP, 0, 0),
xx(SRL_KR, srl, RIKIRI), xx(SRL_KR, srl, RIKIRI, SRL_RR, 2, REGT_INT),
xx(SRA_RR, sra, RIRIRI), // dA = dkB >> diC -- signed xx(SRA_RR, sra, RIRIRI, NOP, 0, 0), // dA = dkB >> diC -- signed
xx(SRA_RI, sra, RIRII8), xx(SRA_RI, sra, RIRII8, NOP, 0, 0),
xx(SRA_KR, sra, RIKIRI), xx(SRA_KR, sra, RIKIRI, SRA_RR, 2, REGT_INT),
xx(ADD_RR, add, RIRIRI), // dA = dB + dkC xx(ADD_RR, add, RIRIRI, NOP, 0, 0), // dA = dB + dkC
xx(ADD_RK, add, RIRIKI), xx(ADD_RK, add, RIRIKI, ADD_RR, 4, REGT_INT),
xx(ADDI, addi, RIRIIs), // dA = dB + C -- C is a signed 8-bit constant xx(ADDI, addi, RIRIIs, NOP, 0, 0), // dA = dB + C -- C is a signed 8-bit constant
xx(SUB_RR, sub, RIRIRI), // dA = dkB - dkC xx(SUB_RR, sub, RIRIRI, NOP, 0, 0), // dA = dkB - dkC
xx(SUB_RK, sub, RIRIKI), xx(SUB_RK, sub, RIRIKI, SUB_RR, 4, REGT_INT),
xx(SUB_KR, sub, RIKIRI), xx(SUB_KR, sub, RIKIRI, SUB_RR, 2, REGT_INT),
xx(MUL_RR, mul, RIRIRI), // dA = dB * dkC xx(MUL_RR, mul, RIRIRI, NOP, 0, 0), // dA = dB * dkC
xx(MUL_RK, mul, RIRIKI), xx(MUL_RK, mul, RIRIKI, MUL_RR, 4, REGT_INT),
xx(DIV_RR, div, RIRIRI), // dA = dkB / dkC (signed) xx(DIV_RR, div, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (signed)
xx(DIV_RK, div, RIRIKI), xx(DIV_RK, div, RIRIKI, DIV_RR, 4, REGT_INT),
xx(DIV_KR, div, RIKIRI), xx(DIV_KR, div, RIKIRI, DIV_RR, 2, REGT_INT),
xx(DIVU_RR, divu, RIRIRI), // dA = dkB / dkC (unsigned) xx(DIVU_RR, divu, RIRIRI, NOP, 0, 0), // dA = dkB / dkC (unsigned)
xx(DIVU_RK, divu, RIRIKI), xx(DIVU_RK, divu, RIRIKI, DIVU_RR,4, REGT_INT),
xx(DIVU_KR, divu, RIKIRI), xx(DIVU_KR, divu, RIKIRI, DIVU_RR,2, REGT_INT),
xx(MOD_RR, mod, RIRIRI), // dA = dkB % dkC (signed) xx(MOD_RR, mod, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (signed)
xx(MOD_RK, mod, RIRIKI), xx(MOD_RK, mod, RIRIKI, MOD_RR, 4, REGT_INT),
xx(MOD_KR, mod, RIKIRI), xx(MOD_KR, mod, RIKIRI, MOD_RR, 2, REGT_INT),
xx(MODU_RR, modu, RIRIRI), // dA = dkB % dkC (unsigned) xx(MODU_RR, modu, RIRIRI, NOP, 0, 0), // dA = dkB % dkC (unsigned)
xx(MODU_RK, modu, RIRIKI), xx(MODU_RK, modu, RIRIKI, MODU_RR,4, REGT_INT),
xx(MODU_KR, modu, RIKIRI), xx(MODU_KR, modu, RIKIRI, MODU_RR,2, REGT_INT),
xx(AND_RR, and, RIRIRI), // dA = dB & dkC xx(AND_RR, and, RIRIRI, NOP, 0, 0), // dA = dB & dkC
xx(AND_RK, and, RIRIKI), xx(AND_RK, and, RIRIKI, AND_RR, 4, REGT_INT),
xx(OR_RR, or, RIRIRI), // dA = dB | dkC xx(OR_RR, or, RIRIRI, NOP, 0, 0), // dA = dB | dkC
xx(OR_RK, or, RIRIKI), xx(OR_RK, or, RIRIKI, OR_RR, 4, REGT_INT),
xx(XOR_RR, xor, RIRIRI), // dA = dB ^ dkC xx(XOR_RR, xor, RIRIRI, NOP, 0, 0), // dA = dB ^ dkC
xx(XOR_RK, xor, RIRIKI), xx(XOR_RK, xor, RIRIKI, XOR_RR, 4, REGT_INT),
xx(MIN_RR, min, RIRIRI), // dA = min(dB,dkC) xx(MIN_RR, min, RIRIRI, NOP, 0, 0), // dA = min(dB,dkC)
xx(MIN_RK, min, RIRIKI), xx(MIN_RK, min, RIRIKI, MIN_RR, 4, REGT_INT),
xx(MAX_RR, max, RIRIRI), // dA = max(dB,dkC) xx(MAX_RR, max, RIRIRI, NOP, 0, 0), // dA = max(dB,dkC)
xx(MAX_RK, max, RIRIKI), xx(MAX_RK, max, RIRIKI, MAX_RR, 4, REGT_INT),
xx(ABS, abs, RIRI), // dA = abs(dB) xx(ABS, abs, RIRI, NOP, 0, 0), // dA = abs(dB)
xx(NEG, neg, RIRI), // dA = -dB xx(NEG, neg, RIRI, NOP, 0, 0), // dA = -dB
xx(NOT, not, RIRI), // dA = ~dB xx(NOT, not, RIRI, NOP, 0, 0), // dA = ~dB
xx(SEXT, sext, RIRII8), // dA = dB, sign extended by shifting left then right by C xx(SEXT, sext, RIRII8, NOP, 0, 0), // 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_R, zap, RIRIRI, NOP, 0, 0), // dA = dB, with bytes zeroed where bits in C/dC are one
xx(ZAP_I, zap, RIRII8), xx(ZAP_I, zap, RIRII8, NOP, 0, 0),
xx(ZAPNOT_R, zapnot, RIRIRI), // dA = dB, with bytes zeroed where bits in C/dC are zero 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), xx(ZAPNOT_I, zapnot, RIRII8, NOP, 0, 0),
xx(EQ_R, beq, CIRR), // if ((dB == dkC) != A) then pc++ xx(EQ_R, beq, CIRR, NOP, 0, 0), // if ((dB == dkC) != A) then pc++
xx(EQ_K, beq, CIRK), xx(EQ_K, beq, CIRK, EQ_R, 4, REGT_INT),
xx(LT_RR, blt, CIRR), // if ((dkB < dkC) != A) then pc++ xx(LT_RR, blt, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++
xx(LT_RK, blt, CIRK), xx(LT_RK, blt, CIRK, LT_RR, 4, REGT_INT),
xx(LT_KR, blt, CIKR), xx(LT_KR, blt, CIKR, LT_RR, 2, REGT_INT),
xx(LE_RR, ble, CIRR), // if ((dkB <= dkC) != A) then pc++ xx(LE_RR, ble, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++
xx(LE_RK, ble, CIRK), xx(LE_RK, ble, CIRK, LE_RR, 4, REGT_INT),
xx(LE_KR, ble, CIKR), xx(LE_KR, ble, CIKR, LE_RR, 2, REGT_INT),
xx(LTU_RR, bltu, CIRR), // if ((dkB < dkC) != A) then pc++ -- unsigned xx(LTU_RR, bltu, CIRR, NOP, 0, 0), // if ((dkB < dkC) != A) then pc++ -- unsigned
xx(LTU_RK, bltu, CIRK), xx(LTU_RK, bltu, CIRK, LTU_RR, 4, REGT_INT),
xx(LTU_KR, bltu, CIKR), xx(LTU_KR, bltu, CIKR, LTU_RR, 2, REGT_INT),
xx(LEU_RR, bleu, CIRR), // if ((dkB <= dkC) != A) then pc++ -- unsigned xx(LEU_RR, bleu, CIRR, NOP, 0, 0), // if ((dkB <= dkC) != A) then pc++ -- unsigned
xx(LEU_RK, bleu, CIRK), xx(LEU_RK, bleu, CIRK, LEU_RR, 4, REGT_INT),
xx(LEU_KR, bleu, CIKR), xx(LEU_KR, bleu, CIKR, LEU_RR, 2, REGT_INT),
// Double-precision floating point math. // Double-precision floating point math.
xx(ADDF_RR, add, RFRFRF), // fA = fB + fkC xx(ADDF_RR, add, RFRFRF, NOP, 0, 0), // fA = fB + fkC
xx(ADDF_RK, add, RFRFKF), xx(ADDF_RK, add, RFRFKF, ADDF_RR,4, REGT_FLOAT),
xx(SUBF_RR, sub, RFRFRF), // fA = fkB - fkC xx(SUBF_RR, sub, RFRFRF, NOP, 0, 0), // fA = fkB - fkC
xx(SUBF_RK, sub, RFRFKF), xx(SUBF_RK, sub, RFRFKF, SUBF_RR,4, REGT_FLOAT),
xx(SUBF_KR, sub, RFKFRF), xx(SUBF_KR, sub, RFKFRF, SUBF_RR,2, REGT_FLOAT),
xx(MULF_RR, mul, RFRFRF), // fA = fB * fkC xx(MULF_RR, mul, RFRFRF, NOP, 0, 0), // fA = fB * fkC
xx(MULF_RK, mul, RFRFKF), xx(MULF_RK, mul, RFRFKF, MULF_RR,4, REGT_FLOAT),
xx(DIVF_RR, div, RFRFRF), // fA = fkB / fkC xx(DIVF_RR, div, RFRFRF, NOP, 0, 0), // fA = fkB / fkC
xx(DIVF_RK, div, RFRFKF), xx(DIVF_RK, div, RFRFKF, DIVF_RR,4, REGT_FLOAT),
xx(DIVF_KR, div, RFKFRF), xx(DIVF_KR, div, RFKFRF, DIVF_RR,2, REGT_FLOAT),
xx(MODF_RR, mod, RFRFRF), // fA = fkB % fkC xx(MODF_RR, mod, RFRFRF, NOP, 0, 0), // fA = fkB % fkC
xx(MODF_RK, mod, RFRFKF), xx(MODF_RK, mod, RFRFKF, MODF_RR,4, REGT_FLOAT),
xx(MODF_KR, mod, RFKFRF), xx(MODF_KR, mod, RFKFRF, MODF_RR,4, REGT_FLOAT),
xx(POWF_RR, pow, RFRFRF), // fA = fkB ** fkC xx(POWF_RR, pow, RFRFRF, NOP, 0, 0), // fA = fkB ** fkC
xx(POWF_RK, pow, RFRFKF), xx(POWF_RK, pow, RFRFKF, POWF_RR,4, REGT_FLOAT),
xx(POWF_KR, pow, RFKFRF), xx(POWF_KR, pow, RFKFRF, POWF_RR,2, REGT_FLOAT),
xx(MINF_RR, min, RFRFRF), // fA = min(fB),fkC) xx(MINF_RR, min, RFRFRF, NOP, 0, 0), // fA = min(fB),fkC)
xx(MINF_RK, min, RFRFKF), xx(MINF_RK, min, RFRFKF, MINF_RR,4, REGT_FLOAT),
xx(MAXF_RR, max, RFRFRF), // fA = max(fB),fkC) xx(MAXF_RR, max, RFRFRF, NOP, 0, 0), // fA = max(fB),fkC)
xx(MAXF_RK, max, RFRFKF), xx(MAXF_RK, max, RFRFKF, MAXF_RR,4, REGT_FLOAT),
xx(ATAN2, atan2, RFRFRF), // fA = atan2(fB,fC), result is in degrees xx(ATAN2, atan2, RFRFRF, NOP, 0, 0), // fA = atan2(fB,fC), result is in degrees
xx(FLOP, flop, RFRFI8), // fA = f(fB), where function is selected by C xx(FLOP, flop, RFRFI8, NOP, 0, 0), // fA = f(fB), where function is selected by C
xx(EQF_R, beq, CFRR), // if ((fB == fkC) != (A & 1)) then pc++ xx(EQF_R, beq, CFRR, NOP, 0, 0), // if ((fB == fkC) != (A & 1)) then pc++
xx(EQF_K, beq, CFRK), xx(EQF_K, beq, CFRK, EQF_R, 4, REGT_FLOAT),
xx(LTF_RR, blt, CFRR), // if ((fkB < fkC) != (A & 1)) then pc++ xx(LTF_RR, blt, CFRR, NOP, 0, 0), // if ((fkB < fkC) != (A & 1)) then pc++
xx(LTF_RK, blt, CFRK), xx(LTF_RK, blt, CFRK, LTF_RR, 4, REGT_FLOAT),
xx(LTF_KR, blt, CFKR), xx(LTF_KR, blt, CFKR, LTF_RR, 2, REGT_FLOAT),
xx(LEF_RR, ble, CFRR), // if ((fkb <= fkC) != (A & 1)) then pc++ xx(LEF_RR, ble, CFRR, NOP, 0, 0), // if ((fkb <= fkC) != (A & 1)) then pc++
xx(LEF_RK, ble, CFRK), xx(LEF_RK, ble, CFRK, LEF_RR, 4, REGT_FLOAT),
xx(LEF_KR, ble, CFKR), xx(LEF_KR, ble, CFKR, LEF_RR, 2, REGT_FLOAT),
// Vector math. (2D) // Vector math. (2D)
xx(NEGV2, negv2, RVRV), // vA = -vB xx(NEGV2, negv2, RVRV, NOP, 0, 0), // vA = -vB
xx(ADDV2_RR, addv2, RVRVRV), // vA = vB + vkC xx(ADDV2_RR, addv2, RVRVRV, NOP, 0, 0), // vA = vB + vkC
xx(ADDV2_RK, addv2, RVRVKV), xx(SUBV2_RR, subv2, RVRVRV, NOP, 0, 0), // vA = vkB - vkC
xx(SUBV2_RR, subv2, RVRVRV), // vA = vkB - vkC xx(DOTV2_RR, dotv2, RVRVRV, NOP, 0, 0), // va = vB dot vkC
xx(SUBV2_RK, subv2, RVRVKV), xx(MULVF2_RR, mulv2, RVRVRF, NOP, 0, 0), // vA = vkB * fkC
xx(SUBV2_KR, subv2, RVKVRV), xx(MULVF2_RK, mulv2, RVRVKF, MULVF2_RR,4, REGT_FLOAT),
xx(DOTV2_RR, dotv2, RVRVRV), // va = vB dot vkC xx(DIVVF2_RR, divv2, RVRVRF, NOP, 0, 0), // vA = vkB / fkC
xx(DOTV2_RK, dotv2, RVRVKV), xx(DIVVF2_RK, divv2, RVRVKF, DIVVF2_RR,4, REGT_FLOAT),
xx(MULVF2_RR, mulv2, RVRVRF), // vA = vkB * fkC xx(LENV2, lenv2, RFRV, NOP, 0, 0), // fA = vB.Length
xx(MULVF2_RK, mulv2, RVRVKF), xx(EQV2_R, beqv2, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 32)
xx(DIVVF2_RR, divv2, RVRVRF), // vA = vkB / fkC xx(EQV2_K, beqv2, CVRK, NOP, 0, 0), // this will never be used.
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),
// Vector math (3D) // Vector math (3D)
xx(NEGV3, negv3, RVRV), // vA = -vB xx(NEGV3, negv3, RVRV, NOP, 0, 0), // vA = -vB
xx(ADDV3_RR, addv3, RVRVRV), // vA = vB + vkC xx(ADDV3_RR, addv3, RVRVRV, NOP, 0, 0), // vA = vB + vkC
xx(ADDV3_RK, addv3, RVRVKV), xx(SUBV3_RR, subv3, RVRVRV, NOP, 0, 0), // vA = vkB - vkC
xx(SUBV3_RR, subv3, RVRVRV), // vA = vkB - vkC xx(DOTV3_RR, dotv3, RVRVRV, NOP, 0, 0), // va = vB dot vkC
xx(SUBV3_RK, subv3, RVRVKV), xx(CROSSV_RR, crossv, RVRVRV, NOP, 0, 0), // vA = vkB cross vkC
xx(SUBV3_KR, subv3, RVKVRV), xx(MULVF3_RR, mulv3, RVRVRF, NOP, 0, 0), // vA = vkB * fkC
xx(DOTV3_RR, dotv3, RVRVRV), // va = vB dot vkC xx(MULVF3_RK, mulv3, RVRVKF, MULVF3_RR,4, REGT_FLOAT),
xx(DOTV3_RK, dotv3, RVRVKV), xx(DIVVF3_RR, divv3, RVRVRF, NOP, 0, 0), // vA = vkB / fkC
xx(CROSSV_RR, crossv, RVRVRV), // vA = vkB cross vkC xx(DIVVF3_RK, divv3, RVRVKF, DIVVF3_RR,4, REGT_FLOAT),
xx(CROSSV_RK, crossv, RVRVKV), xx(LENV3, lenv3, RFRV, NOP, 0, 0), // fA = vB.Length
xx(CROSSV_KR, crossv, RVKVRV), xx(EQV3_R, beqv3, CVRR, NOP, 0, 0), // if ((vB == vkC) != A) then pc++ (inexact if A & 33)
xx(MULVF3_RR, mulv3, RVRVRF), // vA = vkB * fkC xx(EQV3_K, beqv3, CVRK, NOP, 0, 0), // this will never be used.
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),
// Pointer math. // Pointer math.
xx(ADDA_RR, add, RPRPRI), // pA = pB + dkC xx(ADDA_RR, add, RPRPRI, NOP, 0, 0), // pA = pB + dkC
xx(ADDA_RK, add, RPRPKI), xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_POINTER),
xx(SUBA, sub, RIRPRP), // dA = pB - pC xx(SUBA, sub, RIRPRP, NOP, 0, 0), // dA = pB - pC
xx(EQA_R, beq, CPRR), // if ((pB == pkC) != A) then pc++ xx(EQA_R, beq, CPRR, NOP, 0, 0), // if ((pB == pkC) != A) then pc++
xx(EQA_K, beq, CPRK), xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER),
#undef xx #undef xx