-
Notifications
You must be signed in to change notification settings - Fork 536
/
vmops.h
258 lines (242 loc) · 13.4 KB
/
vmops.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#ifndef xx
#define xx(op, name, mode, alt, kreg, ktype) OP_##op,
#endif
// 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, 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
xx(META, meta, RPRP, NOP, 0, 0) // load a class's meta data address
xx(CLSS, clss, RPRP, NOP, 0, 0) // load a class's descriptor address
// Load from memory. rA = *(rB + rkC)
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(LCS, lcs, RSRPKI, LCS_R, 4, REGT_INT) // load string from char ptr.
xx(LCS_R, lcs, RSRPRI, NOP, 0, 0)
xx(LBIT, lbit, RIRPI8, NOP, 0, 0) // rA = !!(*rB & C) -- *rB is a byte
// Store instructions. *(rA + rkC) = rB
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(SO, so, RPRPKI, SO_R, 4, REGT_INT) // store object pointer with write barrier (only needed for non thinkers and non types)
xx(SO_R, so, 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, NOP, 0, 0) // *rA |= C if rB is true, *rA &= ~C otherwise
// Move instructions.
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
xx(CASTB, castb, CAST, NOP, 0, 0) // xA = !!xB, type specified by C
xx(DYNCAST_R, dyncast, RPRPRP, NOP, 0, 0) // aA = dyn_cast<aC>(aB);
xx(DYNCAST_K, dyncast, RPRPKP, NOP, 0, 0) // aA = dyn_cast<aKC>(aB);
xx(DYNCASTC_R, dyncastc, RPRPRP, NOP, 0, 0) // aA = dyn_cast<aC>(aB); for class types
xx(DYNCASTC_K, dyncastc, RPRPKP, NOP, 0, 0) // aA = dyn_cast<aKC>(aB);
// Control flow.
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(SCOPE, scope, RPI8, NOP, 0, 0) // Scope check at runtime.
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 == <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
xx(BOUND, bound, RII16, NOP, 0, 0) // if rA < 0 or rA >= BC, throw exception
xx(BOUND_K, bound, LKI, NOP, 0, 0) // if rA < 0 or rA >= const[BC], throw exception
xx(BOUND_R, bound, RIRI, NOP, 0, 0) // if rA < 0 or rA >= rB, throw exception
// String instructions.
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, 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(MINU_RR, minu, RIRIRI, NOP, 0, 0) // dA = min(dB,dkC) unsigned
xx(MINU_RK, minu, RIRIKI, MIN_RR, 4, REGT_INT)
xx(MAXU_RR, maxu, RIRIRI, NOP, 0, 0) // dA = max(dB,dkC) unsigned
xx(MAXU_RK, maxu, 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(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, 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, 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, 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, NOP, 0, 0) // pA = pB + dkC
xx(ADDA_RK, add, RPRPKI, ADDA_RR,4, REGT_INT)
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