blob: 0b03e02b5ffeddde796a0a8343b7ddae79f5ba19 [file] [log] [blame]
David Srbeckyb2b52a52018-09-06 16:41:23 +01001%def binop(preinstr="", result="a0", chkzero="0", instr=""):
2 /*
3 * Generic 32-bit binary operation. Provide an "instr" line that
4 * specifies an instruction that performs "result = a0 op a1".
5 * This could be a MIPS instruction or a function call. (If the result
6 * comes back in a register other than a0, you can override "result".)
7 *
8 * If "chkzero" is set to 1, we perform a divide-by-zero check on
9 * vCC (a1). Useful for integer division and modulus. Note that we
10 * *don't* check for (INT_MIN / -1) here, because the CPU handles it
11 * correctly.
12 *
13 * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
14 * xor-int, shl-int, shr-int, ushr-int
15 */
16 /* binop vAA, vBB, vCC */
17 srl a4, rINST, 8 # a4 <- AA
18 lbu a2, 2(rPC) # a2 <- BB
19 lbu a3, 3(rPC) # a3 <- CC
20 GET_VREG a0, a2 # a0 <- vBB
21 GET_VREG a1, a3 # a1 <- vCC
22 .if $chkzero
23 beqz a1, common_errDivideByZero # is second operand zero?
24 .endif
25 FETCH_ADVANCE_INST 2 # advance rPC, load rINST
26 $preinstr # optional op
27 $instr # $result <- op, a0-a3 changed
28 GET_INST_OPCODE v0 # extract opcode from rINST
29 SET_VREG $result, a4 # vAA <- $result
30 GOTO_OPCODE v0 # jump to next instruction
31
32%def binop2addr(preinstr="", result="a0", chkzero="0", instr=""):
33 /*
34 * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
35 * that specifies an instruction that performs "result = a0 op a1".
36 * This could be a MIPS instruction or a function call. (If the result
37 * comes back in a register other than a0, you can override "result".)
38 *
39 * If "chkzero" is set to 1, we perform a divide-by-zero check on
40 * vB (a1). Useful for integer division and modulus. Note that we
41 * *don't* check for (INT_MIN / -1) here, because the CPU handles it
42 * correctly.
43 *
44 * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
45 * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
46 * shl-int/2addr, shr-int/2addr, ushr-int/2addr
47 */
48 /* binop/2addr vA, vB */
49 ext a2, rINST, 8, 4 # a2 <- A
50 ext a3, rINST, 12, 4 # a3 <- B
51 GET_VREG a0, a2 # a0 <- vA
52 GET_VREG a1, a3 # a1 <- vB
53 .if $chkzero
54 beqz a1, common_errDivideByZero # is second operand zero?
55 .endif
56 FETCH_ADVANCE_INST 1 # advance rPC, load rINST
57 $preinstr # optional op
58 $instr # $result <- op, a0-a3 changed
59 GET_INST_OPCODE v0 # extract opcode from rINST
60 SET_VREG $result, a2 # vA <- $result
61 GOTO_OPCODE v0 # jump to next instruction
62
63%def binopLit16(preinstr="", result="a0", chkzero="0", instr=""):
64 /*
65 * Generic 32-bit "lit16" binary operation. Provide an "instr" line
66 * that specifies an instruction that performs "result = a0 op a1".
67 * This could be an MIPS instruction or a function call. (If the result
68 * comes back in a register other than a0, you can override "result".)
69 *
70 * If "chkzero" is set to 1, we perform a divide-by-zero check on
71 * CCCC (a1). Useful for integer division and modulus.
72 *
73 * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
74 * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
75 */
76 /* binop/lit16 vA, vB, #+CCCC */
77 lh a1, 2(rPC) # a1 <- sign-extended CCCC
78 ext a2, rINST, 8, 4 # a2 <- A
79 ext a3, rINST, 12, 4 # a3 <- B
80 GET_VREG a0, a3 # a0 <- vB
81 .if $chkzero
82 beqz a1, common_errDivideByZero # is second operand zero?
83 .endif
84 FETCH_ADVANCE_INST 2 # advance rPC, load rINST
85 $preinstr # optional op
86 $instr # $result <- op, a0-a3 changed
87 GET_INST_OPCODE v0 # extract opcode from rINST
88 SET_VREG $result, a2 # vA <- $result
89 GOTO_OPCODE v0 # jump to next instruction
90
91
92%def binopLit8(preinstr="", result="a0", chkzero="0", instr=""):
93 /*
94 * Generic 32-bit "lit8" binary operation. Provide an "instr" line
95 * that specifies an instruction that performs "result = a0 op a1".
96 * This could be an MIPS instruction or a function call. (If the result
97 * comes back in a register other than a0, you can override "result".)
98 *
99 * If "chkzero" is set to 1, we perform a divide-by-zero check on
100 * CC (a1). Useful for integer division and modulus.
101 *
102 * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
103 * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
104 * shl-int/lit8, shr-int/lit8, ushr-int/lit8
105 */
106 /* binop/lit8 vAA, vBB, #+CC */
107 lbu a3, 2(rPC) # a3 <- BB
108 lb a1, 3(rPC) # a1 <- sign-extended CC
109 srl a2, rINST, 8 # a2 <- AA
110 GET_VREG a0, a3 # a0 <- vBB
111 .if $chkzero
112 beqz a1, common_errDivideByZero # is second operand zero?
113 .endif
114 FETCH_ADVANCE_INST 2 # advance rPC, load rINST
115 $preinstr # optional op
116 $instr # $result <- op, a0-a3 changed
117 GET_INST_OPCODE v0 # extract opcode from rINST
118 SET_VREG $result, a2 # vAA <- $result
119 GOTO_OPCODE v0 # jump to next instruction
120
121
122%def binopWide(preinstr="", result="a0", chkzero="0", instr=""):
123 /*
124 * Generic 64-bit binary operation. Provide an "instr" line that
125 * specifies an instruction that performs "result = a0 op a1".
126 * This could be a MIPS instruction or a function call. (If the result
127 * comes back in a register other than a0, you can override "result".)
128 *
129 * If "chkzero" is set to 1, we perform a divide-by-zero check on
130 * vCC (a1). Useful for integer division and modulus. Note that we
131 * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
132 * correctly.
133 *
134 * For: add-long, sub-long, mul-long, div-long, rem-long, and-long, or-long,
135 * xor-long, shl-long, shr-long, ushr-long
136 */
137 /* binop vAA, vBB, vCC */
138 srl a4, rINST, 8 # a4 <- AA
139 lbu a2, 2(rPC) # a2 <- BB
140 lbu a3, 3(rPC) # a3 <- CC
141 GET_VREG_WIDE a0, a2 # a0 <- vBB
142 GET_VREG_WIDE a1, a3 # a1 <- vCC
143 .if $chkzero
144 beqz a1, common_errDivideByZero # is second operand zero?
145 .endif
146 FETCH_ADVANCE_INST 2 # advance rPC, load rINST
147 $preinstr # optional op
148 $instr # $result <- op, a0-a3 changed
149 GET_INST_OPCODE v0 # extract opcode from rINST
150 SET_VREG_WIDE $result, a4 # vAA <- $result
151 GOTO_OPCODE v0 # jump to next instruction
152
153%def binopWide2addr(preinstr="", result="a0", chkzero="0", instr=""):
154 /*
155 * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
156 * that specifies an instruction that performs "result = a0 op a1".
157 * This could be a MIPS instruction or a function call. (If the result
158 * comes back in a register other than a0, you can override "result".)
159 *
160 * If "chkzero" is set to 1, we perform a divide-by-zero check on
161 * vB (a1). Useful for integer division and modulus. Note that we
162 * *don't* check for (LONG_MIN / -1) here, because the CPU handles it
163 * correctly.
164 *
165 * For: add-long/2addr, sub-long/2addr, mul-long/2addr, div-long/2addr,
166 * rem-long/2addr, and-long/2addr, or-long/2addr, xor-long/2addr,
167 * shl-long/2addr, shr-long/2addr, ushr-long/2addr
168 */
169 /* binop/2addr vA, vB */
170 ext a2, rINST, 8, 4 # a2 <- A
171 ext a3, rINST, 12, 4 # a3 <- B
172 GET_VREG_WIDE a0, a2 # a0 <- vA
173 GET_VREG_WIDE a1, a3 # a1 <- vB
174 .if $chkzero
175 beqz a1, common_errDivideByZero # is second operand zero?
176 .endif
177 FETCH_ADVANCE_INST 1 # advance rPC, load rINST
178 $preinstr # optional op
179 $instr # $result <- op, a0-a3 changed
180 GET_INST_OPCODE v0 # extract opcode from rINST
181 SET_VREG_WIDE $result, a2 # vA <- $result
182 GOTO_OPCODE v0 # jump to next instruction
183
184%def unop(preinstr="", instr=""):
185 /*
186 * Generic 32-bit unary operation. Provide an "instr" line that
187 * specifies an instruction that performs "a0 = op a0".
188 *
189 * for: int-to-byte, int-to-char, int-to-short,
190 * not-int, neg-int
191 */
192 /* unop vA, vB */
193 ext a3, rINST, 12, 4 # a3 <- B
194 GET_VREG a0, a3 # a0 <- vB
195 ext a2, rINST, 8, 4 # a2 <- A
196 $preinstr # optional op
197 FETCH_ADVANCE_INST 1 # advance rPC, load rINST
198 $instr # a0 <- op, a0-a3 changed
199 GET_INST_OPCODE v0 # extract opcode from rINST
200 SET_VREG a0, a2 # vA <- a0
201 GOTO_OPCODE v0 # jump to next instruction
202
203%def unopWide(preinstr="", instr=""):
204 /*
205 * Generic 64-bit unary operation. Provide an "instr" line that
206 * specifies an instruction that performs "a0 = op a0".
207 *
208 * For: not-long, neg-long
209 */
210 /* unop vA, vB */
211 ext a3, rINST, 12, 4 # a3 <- B
212 GET_VREG_WIDE a0, a3 # a0 <- vB
213 ext a2, rINST, 8, 4 # a2 <- A
214 $preinstr # optional op
215 FETCH_ADVANCE_INST 1 # advance rPC, load rINST
216 $instr # a0 <- op, a0-a3 changed
217 GET_INST_OPCODE v0 # extract opcode from rINST
218 SET_VREG_WIDE a0, a2 # vA <- a0
219 GOTO_OPCODE v0 # jump to next instruction
220
221%def op_add_int():
222% binop(instr="addu a0, a0, a1")
223
224%def op_add_int_2addr():
225% binop2addr(instr="addu a0, a0, a1")
226
227%def op_add_int_lit16():
228% binopLit16(instr="addu a0, a0, a1")
229
230%def op_add_int_lit8():
231% binopLit8(instr="addu a0, a0, a1")
232
233%def op_add_long():
234% binopWide(instr="daddu a0, a0, a1")
235
236%def op_add_long_2addr():
237% binopWide2addr(instr="daddu a0, a0, a1")
238
239%def op_and_int():
240% binop(instr="and a0, a0, a1")
241
242%def op_and_int_2addr():
243% binop2addr(instr="and a0, a0, a1")
244
245%def op_and_int_lit16():
246% binopLit16(instr="and a0, a0, a1")
247
248%def op_and_int_lit8():
249% binopLit8(instr="and a0, a0, a1")
250
251%def op_and_long():
252% binopWide(instr="and a0, a0, a1")
253
254%def op_and_long_2addr():
255% binopWide2addr(instr="and a0, a0, a1")
256
257%def op_cmp_long():
258 /* cmp-long vAA, vBB, vCC */
259 lbu a2, 2(rPC) # a2 <- BB
260 lbu a3, 3(rPC) # a3 <- CC
261 srl a4, rINST, 8 # a4 <- AA
262 GET_VREG_WIDE a0, a2 # a0 <- vBB
263 GET_VREG_WIDE a1, a3 # a1 <- vCC
264 FETCH_ADVANCE_INST 2 # advance rPC, load rINST
265 slt a2, a0, a1
266 slt a0, a1, a0
267 subu a0, a0, a2
268 GET_INST_OPCODE v0 # extract opcode from rINST
269 SET_VREG a0, a4 # vAA <- result
270 GOTO_OPCODE v0 # jump to next instruction
271
272%def op_div_int():
273% binop(instr="div a0, a0, a1", chkzero="1")
274
275%def op_div_int_2addr():
276% binop2addr(instr="div a0, a0, a1", chkzero="1")
277
278%def op_div_int_lit16():
279% binopLit16(instr="div a0, a0, a1", chkzero="1")
280
281%def op_div_int_lit8():
282% binopLit8(instr="div a0, a0, a1", chkzero="1")
283
284%def op_div_long():
285% binopWide(instr="ddiv a0, a0, a1", chkzero="1")
286
287%def op_div_long_2addr():
288% binopWide2addr(instr="ddiv a0, a0, a1", chkzero="1")
289
290%def op_int_to_byte():
291% unop(instr="seb a0, a0")
292
293%def op_int_to_char():
294% unop(instr="and a0, a0, 0xffff")
295
296%def op_int_to_long():
297 /* int-to-long vA, vB */
298 ext a3, rINST, 12, 4 # a3 <- B
299 GET_VREG a0, a3 # a0 <- vB (sign-extended to 64 bits)
300 ext a2, rINST, 8, 4 # a2 <- A
301 FETCH_ADVANCE_INST 1 # advance rPC, load rINST
302 GET_INST_OPCODE v0 # extract opcode from rINST
303 SET_VREG_WIDE a0, a2 # vA <- vB
304 GOTO_OPCODE v0 # jump to next instruction
305
306%def op_int_to_short():
307% unop(instr="seh a0, a0")
308
309%def op_long_to_int():
310/* we ignore the high word, making this equivalent to a 32-bit reg move */
311% op_move()
312
313%def op_mul_int():
314% binop(instr="mul a0, a0, a1")
315
316%def op_mul_int_2addr():
317% binop2addr(instr="mul a0, a0, a1")
318
319%def op_mul_int_lit16():
320% binopLit16(instr="mul a0, a0, a1")
321
322%def op_mul_int_lit8():
323% binopLit8(instr="mul a0, a0, a1")
324
325%def op_mul_long():
326% binopWide(instr="dmul a0, a0, a1")
327
328%def op_mul_long_2addr():
329% binopWide2addr(instr="dmul a0, a0, a1")
330
331%def op_neg_int():
332% unop(instr="subu a0, zero, a0")
333
334%def op_neg_long():
335% unopWide(instr="dsubu a0, zero, a0")
336
337%def op_not_int():
338% unop(instr="nor a0, zero, a0")
339
340%def op_not_long():
341% unopWide(instr="nor a0, zero, a0")
342
343%def op_or_int():
344% binop(instr="or a0, a0, a1")
345
346%def op_or_int_2addr():
347% binop2addr(instr="or a0, a0, a1")
348
349%def op_or_int_lit16():
350% binopLit16(instr="or a0, a0, a1")
351
352%def op_or_int_lit8():
353% binopLit8(instr="or a0, a0, a1")
354
355%def op_or_long():
356% binopWide(instr="or a0, a0, a1")
357
358%def op_or_long_2addr():
359% binopWide2addr(instr="or a0, a0, a1")
360
361%def op_rem_int():
362% binop(instr="mod a0, a0, a1", chkzero="1")
363
364%def op_rem_int_2addr():
365% binop2addr(instr="mod a0, a0, a1", chkzero="1")
366
367%def op_rem_int_lit16():
368% binopLit16(instr="mod a0, a0, a1", chkzero="1")
369
370%def op_rem_int_lit8():
371% binopLit8(instr="mod a0, a0, a1", chkzero="1")
372
373%def op_rem_long():
374% binopWide(instr="dmod a0, a0, a1", chkzero="1")
375
376%def op_rem_long_2addr():
377% binopWide2addr(instr="dmod a0, a0, a1", chkzero="1")
378
379%def op_rsub_int():
380% binopLit16(instr="subu a0, a1, a0")
381
382%def op_rsub_int_lit8():
383% binopLit8(instr="subu a0, a1, a0")
384
385%def op_shl_int():
386% binop(instr="sll a0, a0, a1")
387
388%def op_shl_int_2addr():
389% binop2addr(instr="sll a0, a0, a1")
390
391%def op_shl_int_lit8():
392% binopLit8(instr="sll a0, a0, a1")
393
394%def op_shl_long():
395% binopWide(instr="dsll a0, a0, a1")
396
397%def op_shl_long_2addr():
398% binopWide2addr(instr="dsll a0, a0, a1")
399
400%def op_shr_int():
401% binop(instr="sra a0, a0, a1")
402
403%def op_shr_int_2addr():
404% binop2addr(instr="sra a0, a0, a1")
405
406%def op_shr_int_lit8():
407% binopLit8(instr="sra a0, a0, a1")
408
409%def op_shr_long():
410% binopWide(instr="dsra a0, a0, a1")
411
412%def op_shr_long_2addr():
413% binopWide2addr(instr="dsra a0, a0, a1")
414
415%def op_sub_int():
416% binop(instr="subu a0, a0, a1")
417
418%def op_sub_int_2addr():
419% binop2addr(instr="subu a0, a0, a1")
420
421%def op_sub_long():
422% binopWide(instr="dsubu a0, a0, a1")
423
424%def op_sub_long_2addr():
425% binopWide2addr(instr="dsubu a0, a0, a1")
426
427%def op_ushr_int():
428% binop(instr="srl a0, a0, a1")
429
430%def op_ushr_int_2addr():
431% binop2addr(instr="srl a0, a0, a1")
432
433%def op_ushr_int_lit8():
434% binopLit8(instr="srl a0, a0, a1")
435
436%def op_ushr_long():
437% binopWide(instr="dsrl a0, a0, a1")
438
439%def op_ushr_long_2addr():
440% binopWide2addr(instr="dsrl a0, a0, a1")
441
442%def op_xor_int():
443% binop(instr="xor a0, a0, a1")
444
445%def op_xor_int_2addr():
446% binop2addr(instr="xor a0, a0, a1")
447
448%def op_xor_int_lit16():
449% binopLit16(instr="xor a0, a0, a1")
450
451%def op_xor_int_lit8():
452% binopLit8(instr="xor a0, a0, a1")
453
454%def op_xor_long():
455% binopWide(instr="xor a0, a0, a1")
456
457%def op_xor_long_2addr():
458% binopWide2addr(instr="xor a0, a0, a1")