xref: /aosp_15_r20/art/runtime/interpreter/mterp/riscv64/arithmetic.S (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker//
2*795d594fSAndroid Build Coastguard Worker// unop vA, vB
3*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|op
4*795d594fSAndroid Build Coastguard Worker// (see floating_point.S for float/double ops)
5*795d594fSAndroid Build Coastguard Worker//
6*795d594fSAndroid Build Coastguard Worker
7*795d594fSAndroid Build Coastguard Worker// neg-int vA, vB
8*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|7b
9*795d594fSAndroid Build Coastguard Worker%def op_neg_int():
10*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="negw t1, t1")
11*795d594fSAndroid Build Coastguard Worker
12*795d594fSAndroid Build Coastguard Worker// not-int vA, vB
13*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|7c
14*795d594fSAndroid Build Coastguard Worker%def op_not_int():
15*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="not t1, t1")
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker// neg-long vA, vB
18*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|7d
19*795d594fSAndroid Build Coastguard Worker%def op_neg_long():
20*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="neg t1, t1", is_wide=True)
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker// not-long vA, vB
23*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|7e
24*795d594fSAndroid Build Coastguard Worker%def op_not_long():
25*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="not t1, t1", is_wide=True)
26*795d594fSAndroid Build Coastguard Worker
27*795d594fSAndroid Build Coastguard Worker// int-to-long vA, vB
28*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|81
29*795d594fSAndroid Build Coastguard Worker// Note: Sign extension of int32 into int64.
30*795d594fSAndroid Build Coastguard Worker// Read from 32-bit vreg and write to 64-bit vreg, hence a custom impl.
31*795d594fSAndroid Build Coastguard Worker%def op_int_to_long():
32*795d594fSAndroid Build Coastguard Worker   srliw t1, xINST, 12   // t1 := B
33*795d594fSAndroid Build Coastguard Worker   srliw t2, xINST, 8    // t2 := B|A
34*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1")  #  t1 := fp[B] with sign extension to 64 bits
35*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 1  // advance xPC, load xINST
36*795d594fSAndroid Build Coastguard Worker   and t2, t2, 0xF       // t2 := A
37*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t3    // t3 holds next opcode
38*795d594fSAndroid Build Coastguard Worker   SET_VREG_WIDE t1, t2, z0=t0
39*795d594fSAndroid Build Coastguard Worker                         // fp[A:A+1] := t1
40*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t3        // continue to next
41*795d594fSAndroid Build Coastguard Worker
42*795d594fSAndroid Build Coastguard Worker// long-to-int vA, vB
43*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|84
44*795d594fSAndroid Build Coastguard Worker// Note: Truncation of int64 into int32.
45*795d594fSAndroid Build Coastguard Worker// Implemented as a read from the low bits from vB, write them to vA.
46*795d594fSAndroid Build Coastguard Worker// Note: instr is intentionally empty.
47*795d594fSAndroid Build Coastguard Worker%def op_long_to_int():
48*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="")
49*795d594fSAndroid Build Coastguard Worker
50*795d594fSAndroid Build Coastguard Worker// int-to-byte vA, vB
51*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8d
52*795d594fSAndroid Build Coastguard Worker// Note: Truncation of int32 to int8, sign extending the result.
53*795d594fSAndroid Build Coastguard Worker%def op_int_to_byte():
54*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="sext.b t1, t1")
55*795d594fSAndroid Build Coastguard Worker
56*795d594fSAndroid Build Coastguard Worker// int-to-byte vA, vB
57*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8e
58*795d594fSAndroid Build Coastguard Worker// Note: Truncation of int32 to uint16, without sign extension.
59*795d594fSAndroid Build Coastguard Worker%def op_int_to_char():
60*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="zext.h t1, t1")
61*795d594fSAndroid Build Coastguard Worker
62*795d594fSAndroid Build Coastguard Worker// int-to-byte vA, vB
63*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|8f
64*795d594fSAndroid Build Coastguard Worker// Note: Truncation of int32 to int16, sign extending the result.
65*795d594fSAndroid Build Coastguard Worker%def op_int_to_short():
66*795d594fSAndroid Build Coastguard Worker%  generic_unop(instr="sext.h t1, t1")
67*795d594fSAndroid Build Coastguard Worker
68*795d594fSAndroid Build Coastguard Worker// unop boilerplate
69*795d594fSAndroid Build Coastguard Worker// instr: operand held in t1, result written to t1.
70*795d594fSAndroid Build Coastguard Worker// instr must not clobber t2.
71*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2
72*795d594fSAndroid Build Coastguard Worker%def generic_unop(instr, is_wide=False):
73*795d594fSAndroid Build Coastguard Worker   srliw t1, xINST, 12   // t1 := B
74*795d594fSAndroid Build Coastguard Worker   srliw t2, xINST, 8    // t2 := B|A
75*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1", is_wide=is_wide)
76*795d594fSAndroid Build Coastguard Worker                         // t1 := fp[B]
77*795d594fSAndroid Build Coastguard Worker   and t2, t2, 0xF       // t2 := A
78*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 1  // advance xPC, load xINST
79*795d594fSAndroid Build Coastguard Worker   $instr                // read t1, write result to t1.
80*795d594fSAndroid Build Coastguard Worker                         // do not clobber t2!
81*795d594fSAndroid Build Coastguard Worker%  set_vreg("t1", "t2", z0="t0", is_wide=is_wide)
82*795d594fSAndroid Build Coastguard Worker                         // fp[A] := t1
83*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t0    // t0 holds next opcode
84*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t0        // continue to next
85*795d594fSAndroid Build Coastguard Worker
86*795d594fSAndroid Build Coastguard Worker//
87*795d594fSAndroid Build Coastguard Worker// binop vAA, vBB, vCC
88*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|op CC|BB
89*795d594fSAndroid Build Coastguard Worker// (see floating_point.S for float/double ops)
90*795d594fSAndroid Build Coastguard Worker//
91*795d594fSAndroid Build Coastguard Worker
92*795d594fSAndroid Build Coastguard Worker// add-int vAA, vBB, vCC
93*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|90 CC|BB
94*795d594fSAndroid Build Coastguard Worker%def op_add_int():
95*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="addw t1, t1, t2")
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker// sub-int vAA, vBB, vCC
98*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|91 CC|BB
99*795d594fSAndroid Build Coastguard Worker%def op_sub_int():
100*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="subw t1, t1, t2")
101*795d594fSAndroid Build Coastguard Worker
102*795d594fSAndroid Build Coastguard Worker// mul-int vAA, vBB, vCC
103*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|92 CC|BB
104*795d594fSAndroid Build Coastguard Worker%def op_mul_int():
105*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="mulw t1, t1, t2")
106*795d594fSAndroid Build Coastguard Worker
107*795d594fSAndroid Build Coastguard Worker// div-int vAA, vBB, vCC
108*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|93 CC|BB
109*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws
110*795d594fSAndroid Build Coastguard Worker// ArithmeticException if b == 0.
111*795d594fSAndroid Build Coastguard Worker%def op_div_int():
112*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="divw t1, t1, t2", divz_throw=True)
113*795d594fSAndroid Build Coastguard Worker
114*795d594fSAndroid Build Coastguard Worker// rem-int vAA, vBB, vCC
115*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|94 CC|BB
116*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement remainder after division. The sign of the result is the same as that of a,
117*795d594fSAndroid Build Coastguard Worker// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if
118*795d594fSAndroid Build Coastguard Worker// b == 0.
119*795d594fSAndroid Build Coastguard Worker%def op_rem_int():
120*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="remw t1, t1, t2", divz_throw=True)
121*795d594fSAndroid Build Coastguard Worker
122*795d594fSAndroid Build Coastguard Worker// and-int vAA, vBB, vCC
123*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|95 CC|BB
124*795d594fSAndroid Build Coastguard Worker%def op_and_int():
125*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="and t1, t1, t2")
126*795d594fSAndroid Build Coastguard Worker
127*795d594fSAndroid Build Coastguard Worker// or-int vAA, vBB, vCC
128*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|96 CC|BB
129*795d594fSAndroid Build Coastguard Worker%def op_or_int():
130*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="or t1, t1, t2")
131*795d594fSAndroid Build Coastguard Worker
132*795d594fSAndroid Build Coastguard Worker// xor-int vAA, vBB, vCC
133*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|97 CC|BB
134*795d594fSAndroid Build Coastguard Worker%def op_xor_int():
135*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="xor t1, t1, t2")
136*795d594fSAndroid Build Coastguard Worker
137*795d594fSAndroid Build Coastguard Worker// shl-int vAA, vBB, vCC
138*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|98 CC|BB
139*795d594fSAndroid Build Coastguard Worker// Note: SLLW uses t2[4:0] for the shift amount.
140*795d594fSAndroid Build Coastguard Worker%def op_shl_int():
141*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="sllw t1, t1, t2")
142*795d594fSAndroid Build Coastguard Worker
143*795d594fSAndroid Build Coastguard Worker// shr-int vAA, vBB, vCC
144*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|99 CC|BB
145*795d594fSAndroid Build Coastguard Worker// Note: SRAW uses t2[4:0] for the shift amount.
146*795d594fSAndroid Build Coastguard Worker%def op_shr_int():
147*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="sraw t1, t1, t2")
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard Worker// ushr-int vAA, vBB, vCC
150*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9a CC|BB
151*795d594fSAndroid Build Coastguard Worker// Note: SRLW uses t2[4:0] for the shift amount.
152*795d594fSAndroid Build Coastguard Worker%def op_ushr_int():
153*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="srlw t1, t1, t2")
154*795d594fSAndroid Build Coastguard Worker
155*795d594fSAndroid Build Coastguard Worker// add-long vAA, vBB, vCC
156*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9b CC|BB
157*795d594fSAndroid Build Coastguard Worker%def op_add_long():
158*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="add t1, t1, t2", is_wide=True)
159*795d594fSAndroid Build Coastguard Worker
160*795d594fSAndroid Build Coastguard Worker// sub-long vAA, vBB, vCC
161*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9c CC|BB
162*795d594fSAndroid Build Coastguard Worker%def op_sub_long():
163*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="sub t1, t1, t2", is_wide=True)
164*795d594fSAndroid Build Coastguard Worker
165*795d594fSAndroid Build Coastguard Worker// mul-long vAA, vBB, vCC
166*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9d CC|BB
167*795d594fSAndroid Build Coastguard Worker%def op_mul_long():
168*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="mul t1, t1, t2", is_wide=True)
169*795d594fSAndroid Build Coastguard Worker
170*795d594fSAndroid Build Coastguard Worker// div-long vAA, vBB, vCC
171*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9e CC|BB
172*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws
173*795d594fSAndroid Build Coastguard Worker// ArithmeticException if b == 0.
174*795d594fSAndroid Build Coastguard Worker%def op_div_long():
175*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="div t1, t1, t2", divz_throw=True, is_wide=True)
176*795d594fSAndroid Build Coastguard Worker
177*795d594fSAndroid Build Coastguard Worker// rem-long vAA, vBB, vCC
178*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|9f CC|BB
179*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement remainder after division. The sign of the result is the same as that of a,
180*795d594fSAndroid Build Coastguard Worker// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if
181*795d594fSAndroid Build Coastguard Worker// b == 0.
182*795d594fSAndroid Build Coastguard Worker%def op_rem_long():
183*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="rem t1, t1, t2", divz_throw=True, is_wide=True)
184*795d594fSAndroid Build Coastguard Worker
185*795d594fSAndroid Build Coastguard Worker// and-long vAA, vBB, vCC
186*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a0 CC|BB
187*795d594fSAndroid Build Coastguard Worker%def op_and_long():
188*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="and t1, t1, t2", is_wide=True)
189*795d594fSAndroid Build Coastguard Worker
190*795d594fSAndroid Build Coastguard Worker// or-long vAA, vBB, vCC
191*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a1 CC|BB
192*795d594fSAndroid Build Coastguard Worker%def op_or_long():
193*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="or t1, t1, t2", is_wide=True)
194*795d594fSAndroid Build Coastguard Worker
195*795d594fSAndroid Build Coastguard Worker// xor-long vAA, vBB, vCC
196*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a2 CC|BB
197*795d594fSAndroid Build Coastguard Worker%def op_xor_long():
198*795d594fSAndroid Build Coastguard Worker%  generic_binop(instr="xor t1, t1, t2", is_wide=True)
199*795d594fSAndroid Build Coastguard Worker
200*795d594fSAndroid Build Coastguard Worker// shl-long vAA, vBB, vCC
201*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a3 CC|BB
202*795d594fSAndroid Build Coastguard Worker// Note: SLL uses t2[5:0] for the shift amount.
203*795d594fSAndroid Build Coastguard Worker%def op_shl_long():
204*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide(instr="sll t1, t1, t2")
205*795d594fSAndroid Build Coastguard Worker
206*795d594fSAndroid Build Coastguard Worker// shr-long vAA, vBB, vCC
207*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a4 CC|BB
208*795d594fSAndroid Build Coastguard Worker// Note: SRA uses t2[5:0] for the shift amount.
209*795d594fSAndroid Build Coastguard Worker%def op_shr_long():
210*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide(instr="sra t1, t1, t2")
211*795d594fSAndroid Build Coastguard Worker
212*795d594fSAndroid Build Coastguard Worker// ushr-long vAA, vBB, vCC
213*795d594fSAndroid Build Coastguard Worker// Format 23x: AA|a5 CC|BB
214*795d594fSAndroid Build Coastguard Worker// Note: SRL uses t2[5:0] for the shift amount.
215*795d594fSAndroid Build Coastguard Worker%def op_ushr_long():
216*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide(instr="srl t1, t1, t2")
217*795d594fSAndroid Build Coastguard Worker
218*795d594fSAndroid Build Coastguard Worker// binop boilerplate
219*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 and t2, result written to t1.
220*795d594fSAndroid Build Coastguard Worker// instr must not throw. Exceptions to be thrown prior to instr.
221*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
222*795d594fSAndroid Build Coastguard Worker//
223*795d594fSAndroid Build Coastguard Worker// The divz_throw flag generates check-and-throw code for div/0.
224*795d594fSAndroid Build Coastguard Worker// The is_wide flag ensures vregs are read and written in 64-bit widths.
225*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3
226*795d594fSAndroid Build Coastguard Worker%def generic_binop(instr, divz_throw=False, is_wide=False):
227*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1     // t1 := CC|BB
228*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8    // t3 := AA
229*795d594fSAndroid Build Coastguard Worker   srliw t2, t1, 8       // t2 := CC
230*795d594fSAndroid Build Coastguard Worker   and t1, t1, 0xFF      // t1 := BB
231*795d594fSAndroid Build Coastguard Worker%  get_vreg("t2", "t2", is_wide=is_wide)  # t2 := fp[CC]
232*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1", is_wide=is_wide)  # t1 := fp[BB]
233*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
234*795d594fSAndroid Build Coastguard Worker     beqz t2, 1f         // Must throw before FETCH_ADVANCE_INST.
235*795d594fSAndroid Build Coastguard Worker%#:
236*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2  // advance xPC, load xINST
237*795d594fSAndroid Build Coastguard Worker   $instr                // read t1 and t2, write result to t1.
238*795d594fSAndroid Build Coastguard Worker                         // do not clobber t3!
239*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2    // t2 holds next opcode
240*795d594fSAndroid Build Coastguard Worker%  set_vreg("t1", "t3", z0="t0", is_wide=is_wide)
241*795d594fSAndroid Build Coastguard Worker                         // fp[AA] := t1
242*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2        // continue to next
243*795d594fSAndroid Build Coastguard Worker1:
244*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
245*795d594fSAndroid Build Coastguard Worker     tail common_errDivideByZero
246*795d594fSAndroid Build Coastguard Worker%#:
247*795d594fSAndroid Build Coastguard Worker
248*795d594fSAndroid Build Coastguard Worker// binop wide shift boilerplate
249*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 (64-bit) and t2 (32-bit), result written to t1.
250*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
251*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3
252*795d594fSAndroid Build Coastguard Worker//
253*795d594fSAndroid Build Coastguard Worker// Note: Contrary to other -long mathematical operations (which take register pairs for both their
254*795d594fSAndroid Build Coastguard Worker// first and their second source), shl-long, shr-long, and ushr-long take a register pair for their
255*795d594fSAndroid Build Coastguard Worker// first source (the value to be shifted), but a single register for their second source (the
256*795d594fSAndroid Build Coastguard Worker// shifting distance).
257*795d594fSAndroid Build Coastguard Worker%def generic_shift_wide(instr):
258*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1     // t1 := CC|BB
259*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8    // t3 := AA
260*795d594fSAndroid Build Coastguard Worker   srliw t2, t1, 8       // t2 := CC
261*795d594fSAndroid Build Coastguard Worker   and t1, t1, 0xFF      // t1 := BB
262*795d594fSAndroid Build Coastguard Worker%  get_vreg("t2", "t2")  #  t2 := fp[CC]
263*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE t1, t1  // t1 := fp[BB]
264*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2  // advance xPC, load xINST
265*795d594fSAndroid Build Coastguard Worker   $instr                // read t1 and t2, write result to t1.
266*795d594fSAndroid Build Coastguard Worker                         // do not clobber t3!
267*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2    // t2 holds next opcode
268*795d594fSAndroid Build Coastguard Worker   SET_VREG_WIDE t1, t3, z0=t0
269*795d594fSAndroid Build Coastguard Worker                         // fp[AA] := t1
270*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2        // continue to next
271*795d594fSAndroid Build Coastguard Worker
272*795d594fSAndroid Build Coastguard Worker//
273*795d594fSAndroid Build Coastguard Worker// binop/2addr vA, vB
274*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|op
275*795d594fSAndroid Build Coastguard Worker// (see floating_point.S for float/double ops)
276*795d594fSAndroid Build Coastguard Worker//
277*795d594fSAndroid Build Coastguard Worker
278*795d594fSAndroid Build Coastguard Worker// add-int/2addr vA, vB
279*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b0
280*795d594fSAndroid Build Coastguard Worker%def op_add_int_2addr():
281*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="addw t1, t1, t2")
282*795d594fSAndroid Build Coastguard Worker
283*795d594fSAndroid Build Coastguard Worker// sub-int/2addr vA, vB
284*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b1
285*795d594fSAndroid Build Coastguard Worker%def op_sub_int_2addr():
286*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="subw t1, t1, t2")
287*795d594fSAndroid Build Coastguard Worker
288*795d594fSAndroid Build Coastguard Worker// mul-int/2addr vA, vB
289*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b2
290*795d594fSAndroid Build Coastguard Worker%def op_mul_int_2addr():
291*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="mulw t1, t1, t2")
292*795d594fSAndroid Build Coastguard Worker
293*795d594fSAndroid Build Coastguard Worker// div-int/2addr vA, vB
294*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b3
295*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws
296*795d594fSAndroid Build Coastguard Worker// ArithmeticException if b == 0.
297*795d594fSAndroid Build Coastguard Worker%def op_div_int_2addr():
298*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="divw t1, t1, t2", divz_throw=True)
299*795d594fSAndroid Build Coastguard Worker
300*795d594fSAndroid Build Coastguard Worker// rem-int/2addr vA, vB
301*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b4
302*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement remainder after division. The sign of the result is the same as that of a,
303*795d594fSAndroid Build Coastguard Worker// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if
304*795d594fSAndroid Build Coastguard Worker// b == 0.
305*795d594fSAndroid Build Coastguard Worker%def op_rem_int_2addr():
306*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="remw t1, t1, t2", divz_throw=True)
307*795d594fSAndroid Build Coastguard Worker
308*795d594fSAndroid Build Coastguard Worker// and-int/2addr vA, vB
309*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b5
310*795d594fSAndroid Build Coastguard Worker%def op_and_int_2addr():
311*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="and t1, t1, t2")
312*795d594fSAndroid Build Coastguard Worker
313*795d594fSAndroid Build Coastguard Worker// or-int/2addr vA, vB
314*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b6
315*795d594fSAndroid Build Coastguard Worker%def op_or_int_2addr():
316*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="or t1, t1, t2")
317*795d594fSAndroid Build Coastguard Worker
318*795d594fSAndroid Build Coastguard Worker// xor-int/2addr vA, vB
319*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b7
320*795d594fSAndroid Build Coastguard Worker%def op_xor_int_2addr():
321*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="xor t1, t1, t2")
322*795d594fSAndroid Build Coastguard Worker
323*795d594fSAndroid Build Coastguard Worker// shl-int/2addr vA, vB
324*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b8
325*795d594fSAndroid Build Coastguard Worker%def op_shl_int_2addr():
326*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="sllw t1, t1, t2")
327*795d594fSAndroid Build Coastguard Worker
328*795d594fSAndroid Build Coastguard Worker// shr-int/2addr vA, vB
329*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|b9
330*795d594fSAndroid Build Coastguard Worker%def op_shr_int_2addr():
331*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="sraw t1, t1, t2")
332*795d594fSAndroid Build Coastguard Worker
333*795d594fSAndroid Build Coastguard Worker// ushr-int/2addr vA, vB
334*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|ba
335*795d594fSAndroid Build Coastguard Worker%def op_ushr_int_2addr():
336*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="srlw t1, t1, t2")
337*795d594fSAndroid Build Coastguard Worker
338*795d594fSAndroid Build Coastguard Worker// add-long/2addr vA, vB
339*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|bb
340*795d594fSAndroid Build Coastguard Worker%def op_add_long_2addr():
341*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="add t1, t1, t2", is_wide=True)
342*795d594fSAndroid Build Coastguard Worker
343*795d594fSAndroid Build Coastguard Worker// sub-long/2addr vA, vB
344*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|bc
345*795d594fSAndroid Build Coastguard Worker%def op_sub_long_2addr():
346*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="sub t1, t1, t2", is_wide=True)
347*795d594fSAndroid Build Coastguard Worker
348*795d594fSAndroid Build Coastguard Worker// mul-long/2addr vA, vB
349*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|bd
350*795d594fSAndroid Build Coastguard Worker%def op_mul_long_2addr():
351*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="mul t1, t1, t2", is_wide=True)
352*795d594fSAndroid Build Coastguard Worker
353*795d594fSAndroid Build Coastguard Worker// div-long/2addr vA, vB
354*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|be
355*795d594fSAndroid Build Coastguard Worker%def op_div_long_2addr():
356*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="div t1, t1, t2", divz_throw=True, is_wide=True)
357*795d594fSAndroid Build Coastguard Worker
358*795d594fSAndroid Build Coastguard Worker// rem-long/2addr vA, vB
359*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|bf
360*795d594fSAndroid Build Coastguard Worker%def op_rem_long_2addr():
361*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="rem t1, t1, t2", divz_throw=True, is_wide=True)
362*795d594fSAndroid Build Coastguard Worker
363*795d594fSAndroid Build Coastguard Worker// and-long/2addr vA, vB
364*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c0
365*795d594fSAndroid Build Coastguard Worker%def op_and_long_2addr():
366*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="and t1, t1, t2", is_wide=True)
367*795d594fSAndroid Build Coastguard Worker
368*795d594fSAndroid Build Coastguard Worker// or-long/2addr vA, vB
369*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c1
370*795d594fSAndroid Build Coastguard Worker%def op_or_long_2addr():
371*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="or t1, t1, t2", is_wide=True)
372*795d594fSAndroid Build Coastguard Worker
373*795d594fSAndroid Build Coastguard Worker// xor-long/2addr vA, vB
374*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c2
375*795d594fSAndroid Build Coastguard Worker%def op_xor_long_2addr():
376*795d594fSAndroid Build Coastguard Worker%  generic_binop_2addr(instr="xor t1, t1, t2", is_wide=True)
377*795d594fSAndroid Build Coastguard Worker
378*795d594fSAndroid Build Coastguard Worker// shl-long/2addr vA, vB
379*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c3
380*795d594fSAndroid Build Coastguard Worker// Note: SLL uses t2[5:0] for the shift amount.
381*795d594fSAndroid Build Coastguard Worker%def op_shl_long_2addr():
382*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide_2addr(instr="sll t1, t1, t2")
383*795d594fSAndroid Build Coastguard Worker
384*795d594fSAndroid Build Coastguard Worker// shr-long/2addr vA, vB
385*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c4
386*795d594fSAndroid Build Coastguard Worker// Note: SRA uses t2[5:0] for the shift amount.
387*795d594fSAndroid Build Coastguard Worker%def op_shr_long_2addr():
388*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide_2addr(instr="sra t1, t1, t2")
389*795d594fSAndroid Build Coastguard Worker
390*795d594fSAndroid Build Coastguard Worker// ushr-long/2addr vA, vB
391*795d594fSAndroid Build Coastguard Worker// Format 12x: B|A|c5
392*795d594fSAndroid Build Coastguard Worker// Note: SRL uses t2[5:0] for the shift amount.
393*795d594fSAndroid Build Coastguard Worker%def op_ushr_long_2addr():
394*795d594fSAndroid Build Coastguard Worker%  generic_shift_wide_2addr(instr="srl t1, t1, t2")
395*795d594fSAndroid Build Coastguard Worker
396*795d594fSAndroid Build Coastguard Worker// binop 2addr boilerplate
397*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 and t2, result written to t1.
398*795d594fSAndroid Build Coastguard Worker// instr must not throw. Exceptions to be thrown prior to instr.
399*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
400*795d594fSAndroid Build Coastguard Worker//
401*795d594fSAndroid Build Coastguard Worker// The divz_throw flag generates check-and-throw code for div/0.
402*795d594fSAndroid Build Coastguard Worker// The is_wide flag ensures vregs are read and written in 64-bit widths.
403*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3, t4
404*795d594fSAndroid Build Coastguard Worker%def generic_binop_2addr(instr, divz_throw=False, is_wide=False):
405*795d594fSAndroid Build Coastguard Worker   srliw t2, xINST, 12   // t2 := B
406*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8    // t3 := B|A
407*795d594fSAndroid Build Coastguard Worker%  get_vreg("t2", "t2", is_wide=is_wide)
408*795d594fSAndroid Build Coastguard Worker                         // t2 := fp[B]
409*795d594fSAndroid Build Coastguard Worker   and t3, t3, 0xF       // t3 := A (cached for SET_VREG)
410*795d594fSAndroid Build Coastguard Worker   mv t4, t3             // t4 := A
411*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t4", is_wide=is_wide)
412*795d594fSAndroid Build Coastguard Worker                         // t1 := fp[A]
413*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
414*795d594fSAndroid Build Coastguard Worker     beqz t2, 1f         // Must throw before FETCH_ADVANCE_INST.
415*795d594fSAndroid Build Coastguard Worker%#:
416*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 1  // advance xPC, load xINST
417*795d594fSAndroid Build Coastguard Worker   $instr                // read t1 and t2, write result to t1.
418*795d594fSAndroid Build Coastguard Worker                         // do not clobber t3!
419*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2    // t2 holds next opcode
420*795d594fSAndroid Build Coastguard Worker%  set_vreg("t1", "t3", z0="t0", is_wide=is_wide)
421*795d594fSAndroid Build Coastguard Worker                         // fp[A] := t1
422*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2        // continue to next
423*795d594fSAndroid Build Coastguard Worker1:
424*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
425*795d594fSAndroid Build Coastguard Worker     tail common_errDivideByZero
426*795d594fSAndroid Build Coastguard Worker%#:
427*795d594fSAndroid Build Coastguard Worker
428*795d594fSAndroid Build Coastguard Worker// binop wide shift 2addr boilerplate
429*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 (64-bit) and t2 (32-bit), result written to t1.
430*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
431*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3, t4
432*795d594fSAndroid Build Coastguard Worker//
433*795d594fSAndroid Build Coastguard Worker// Note: Contrary to other -long/2addr mathematical operations (which take register pairs for both
434*795d594fSAndroid Build Coastguard Worker// their destination/first source and their second source), shl-long/2addr, shr-long/2addr, and
435*795d594fSAndroid Build Coastguard Worker// ushr-long/2addr take a register pair for their destination/first source (the value to be
436*795d594fSAndroid Build Coastguard Worker// shifted), but a single register for their second source (the shifting distance).
437*795d594fSAndroid Build Coastguard Worker%def generic_shift_wide_2addr(instr):
438*795d594fSAndroid Build Coastguard Worker   srliw t2, xINST, 12   // t2 := B
439*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8    // t3 := B|A
440*795d594fSAndroid Build Coastguard Worker%  get_vreg("t2", "t2")  #  t2 := fp[B]
441*795d594fSAndroid Build Coastguard Worker   and t3, t3, 0xF       // t3 := A (cached for SET_VREG_WIDE)
442*795d594fSAndroid Build Coastguard Worker   mv t4, t3             // t4 := A
443*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 1  // advance xPC, load xINST
444*795d594fSAndroid Build Coastguard Worker   GET_VREG_WIDE t1, t4  // t1 := fp[A]
445*795d594fSAndroid Build Coastguard Worker   $instr                // read t1 and t2, write result to t1.
446*795d594fSAndroid Build Coastguard Worker                         // do not clobber t3!
447*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2    // t2 holds next opcode
448*795d594fSAndroid Build Coastguard Worker   SET_VREG_WIDE t1, t3, z0=t0
449*795d594fSAndroid Build Coastguard Worker                         // fp[A] := t1
450*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2        // continue to next
451*795d594fSAndroid Build Coastguard Worker
452*795d594fSAndroid Build Coastguard Worker//
453*795d594fSAndroid Build Coastguard Worker// binop/lit16 vA, vB, #+CCCC
454*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|op CCCC
455*795d594fSAndroid Build Coastguard Worker//
456*795d594fSAndroid Build Coastguard Worker
457*795d594fSAndroid Build Coastguard Worker// add-int/lit16 vA, vB, #+CCCC
458*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d0 CCCC
459*795d594fSAndroid Build Coastguard Worker%def op_add_int_lit16():
460*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="addw t1, t1, t2")
461*795d594fSAndroid Build Coastguard Worker
462*795d594fSAndroid Build Coastguard Worker// rsub-int vA, vB, #+CCCC
463*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d1 CCCC
464*795d594fSAndroid Build Coastguard Worker// Note: rsub-int does not have a suffix since this version is the main opcode of its family.
465*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement reverse subtraction.
466*795d594fSAndroid Build Coastguard Worker%def op_rsub_int():
467*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="subw t1, t2, t1")
468*795d594fSAndroid Build Coastguard Worker
469*795d594fSAndroid Build Coastguard Worker// mul-int/lit16 vA, vB, #+CCCC
470*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d2 CCCC
471*795d594fSAndroid Build Coastguard Worker%def op_mul_int_lit16():
472*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="mulw t1, t1, t2")
473*795d594fSAndroid Build Coastguard Worker
474*795d594fSAndroid Build Coastguard Worker// div-int/lit16 vA, vB, #+CCCC
475*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d3 CCCC
476*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws
477*795d594fSAndroid Build Coastguard Worker// ArithmeticException if b == 0.
478*795d594fSAndroid Build Coastguard Worker%def op_div_int_lit16():
479*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="divw t1, t1, t2", divz_throw=True)
480*795d594fSAndroid Build Coastguard Worker
481*795d594fSAndroid Build Coastguard Worker// rem-int/lit16 vA, vB, #+CCCC
482*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d4 CCCC
483*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement remainder after division. The sign of the result is the same as that of a,
484*795d594fSAndroid Build Coastguard Worker// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if
485*795d594fSAndroid Build Coastguard Worker// b == 0.
486*795d594fSAndroid Build Coastguard Worker%def op_rem_int_lit16():
487*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="remw t1, t1, t2", divz_throw=True)
488*795d594fSAndroid Build Coastguard Worker
489*795d594fSAndroid Build Coastguard Worker// and-int/lit16 vA, vB, #+CCCC
490*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d5 CCCC
491*795d594fSAndroid Build Coastguard Worker%def op_and_int_lit16():
492*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="and t1, t1, t2")
493*795d594fSAndroid Build Coastguard Worker
494*795d594fSAndroid Build Coastguard Worker// or-int/lit16 vA, vB, #+CCCC
495*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d6 CCCC
496*795d594fSAndroid Build Coastguard Worker%def op_or_int_lit16():
497*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="or t1, t1, t2")
498*795d594fSAndroid Build Coastguard Worker
499*795d594fSAndroid Build Coastguard Worker// xor-int/lit16 vA, vB, #+CCCC
500*795d594fSAndroid Build Coastguard Worker// Format 22s: B|A|d7 CCCC
501*795d594fSAndroid Build Coastguard Worker%def op_xor_int_lit16():
502*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit16(instr="xor t1, t1, t2")
503*795d594fSAndroid Build Coastguard Worker
504*795d594fSAndroid Build Coastguard Worker// binop lit16 boilerplate
505*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 and t2, result written to t1.
506*795d594fSAndroid Build Coastguard Worker// instr must not throw. Exceptions to be thrown prior to instr.
507*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
508*795d594fSAndroid Build Coastguard Worker//
509*795d594fSAndroid Build Coastguard Worker// The divz_throw flag generates check-and-throw code for div/0.
510*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3
511*795d594fSAndroid Build Coastguard Worker%def generic_binop_lit16(instr, divz_throw=False):
512*795d594fSAndroid Build Coastguard Worker   FETCH t2, count=1, signed=1  // t2 := ssssCCCC
513*795d594fSAndroid Build Coastguard Worker   srliw t1, xINST, 12          // t1 := B
514*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8           // t3 := B|A
515*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
516*795d594fSAndroid Build Coastguard Worker     beqz t2, 1f                // Must throw before FETCH_ADVANCE_INST.
517*795d594fSAndroid Build Coastguard Worker%#:
518*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1")         #  t1 := fp[B]
519*795d594fSAndroid Build Coastguard Worker   and t3, t3, 0xF              // t3 := A
520*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2         // advance xPC, load xINST
521*795d594fSAndroid Build Coastguard Worker   $instr                       // read t1 and t2, write result to t1.
522*795d594fSAndroid Build Coastguard Worker                                // do not clobber t3!
523*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2           // t2 holds next opcode
524*795d594fSAndroid Build Coastguard Worker%  set_vreg("t1", "t3", z0="t0")  # fp[A] := t1
525*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2               // continue to next
526*795d594fSAndroid Build Coastguard Worker1:
527*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
528*795d594fSAndroid Build Coastguard Worker     tail common_errDivideByZero
529*795d594fSAndroid Build Coastguard Worker%#:
530*795d594fSAndroid Build Coastguard Worker
531*795d594fSAndroid Build Coastguard Worker//
532*795d594fSAndroid Build Coastguard Worker// binop/lit8 vAA, vBB, #+CC
533*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|op CC|BB
534*795d594fSAndroid Build Coastguard Worker//
535*795d594fSAndroid Build Coastguard Worker
536*795d594fSAndroid Build Coastguard Worker// add-int/lit8, vAA, vBB, #+CC
537*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|d8, CC|BB
538*795d594fSAndroid Build Coastguard Worker%def op_add_int_lit8():
539*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="addw t1, t1, t2")
540*795d594fSAndroid Build Coastguard Worker
541*795d594fSAndroid Build Coastguard Worker// rsub-int/lit8, vAA, vBB, #+CC
542*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|d9, CC|BB
543*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement reverse subtraction.
544*795d594fSAndroid Build Coastguard Worker%def op_rsub_int_lit8():
545*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="subw t1, t2, t1")
546*795d594fSAndroid Build Coastguard Worker
547*795d594fSAndroid Build Coastguard Worker// mul-int/lit8, vAA, vBB, #+CC
548*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|da, CC|BB
549*795d594fSAndroid Build Coastguard Worker%def op_mul_int_lit8():
550*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="mulw t1, t1, t2")
551*795d594fSAndroid Build Coastguard Worker
552*795d594fSAndroid Build Coastguard Worker// div-int/lit8, vAA, vBB, #+CC
553*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|db, CC|BB
554*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement division, rounded towards zero (that is, truncated to integer). This throws
555*795d594fSAndroid Build Coastguard Worker// ArithmeticException if b == 0.
556*795d594fSAndroid Build Coastguard Worker%def op_div_int_lit8():
557*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="divw t1, t1, t2", divz_throw=True)
558*795d594fSAndroid Build Coastguard Worker
559*795d594fSAndroid Build Coastguard Worker// rem-int/lit8, vAA, vBB, #+CC
560*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|dc, CC|BB
561*795d594fSAndroid Build Coastguard Worker// Note: Twos-complement remainder after division. The sign of the result is the same as that of a,
562*795d594fSAndroid Build Coastguard Worker// and it is more precisely defined as result == a - (a / b) * b. This throws ArithmeticException if
563*795d594fSAndroid Build Coastguard Worker// b == 0.
564*795d594fSAndroid Build Coastguard Worker%def op_rem_int_lit8():
565*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="remw t1, t1, t2", divz_throw=True)
566*795d594fSAndroid Build Coastguard Worker
567*795d594fSAndroid Build Coastguard Worker// and-int/lit8, vAA, vBB, #+CC
568*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|dd, CC|BB
569*795d594fSAndroid Build Coastguard Worker%def op_and_int_lit8():
570*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="and t1, t1, t2")
571*795d594fSAndroid Build Coastguard Worker
572*795d594fSAndroid Build Coastguard Worker// or-int/lit8, vAA, vBB, #+CC
573*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|de, CC|BB
574*795d594fSAndroid Build Coastguard Worker%def op_or_int_lit8():
575*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="or t1, t1, t2")
576*795d594fSAndroid Build Coastguard Worker
577*795d594fSAndroid Build Coastguard Worker// xor-int/lit8, vAA, vBB, #+CC
578*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|df, CC|BB
579*795d594fSAndroid Build Coastguard Worker%def op_xor_int_lit8():
580*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="xor t1, t1, t2")
581*795d594fSAndroid Build Coastguard Worker
582*795d594fSAndroid Build Coastguard Worker// shl-int/lit8, vAA, vBB, #+CC
583*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|e0, CC|BB
584*795d594fSAndroid Build Coastguard Worker// Note: SLLW uses t2[4:0] for the shift amount.
585*795d594fSAndroid Build Coastguard Worker%def op_shl_int_lit8():
586*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="sllw t1, t1, t2")
587*795d594fSAndroid Build Coastguard Worker
588*795d594fSAndroid Build Coastguard Worker// shr-int/lit8, vAA, vBB, #+CC
589*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|e1, CC|BB
590*795d594fSAndroid Build Coastguard Worker// Note: SRAW uses t2[4:0] for the shift amount.
591*795d594fSAndroid Build Coastguard Worker%def op_shr_int_lit8():
592*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="sraw t1, t1, t2")
593*795d594fSAndroid Build Coastguard Worker
594*795d594fSAndroid Build Coastguard Worker// ushr-int/lit8, vAA, vBB, #+CC
595*795d594fSAndroid Build Coastguard Worker// Format 22b: AA|e2, CC|BB
596*795d594fSAndroid Build Coastguard Worker// Note: SRLW uses t2[4:0] for the shift amount.
597*795d594fSAndroid Build Coastguard Worker%def op_ushr_int_lit8():
598*795d594fSAndroid Build Coastguard Worker%  generic_binop_lit8(instr="srlw t1, t1, t2")
599*795d594fSAndroid Build Coastguard Worker
600*795d594fSAndroid Build Coastguard Worker// binop lit8 boilerplate
601*795d594fSAndroid Build Coastguard Worker// instr: operands held in t1 and t2, result written to t1.
602*795d594fSAndroid Build Coastguard Worker// instr must not throw. Exceptions to be thrown prior to instr.
603*795d594fSAndroid Build Coastguard Worker// instr must not clobber t3.
604*795d594fSAndroid Build Coastguard Worker//
605*795d594fSAndroid Build Coastguard Worker// The divz_throw flag generates check-and-throw code for div/0.
606*795d594fSAndroid Build Coastguard Worker// Clobbers: t0, t1, t2, t3
607*795d594fSAndroid Build Coastguard Worker%def generic_binop_lit8(instr, divz_throw=False):
608*795d594fSAndroid Build Coastguard Worker   FETCH t1, count=1, signed=1  // t1 := ssssCC|BB
609*795d594fSAndroid Build Coastguard Worker   srliw t3, xINST, 8           // t3 := AA
610*795d594fSAndroid Build Coastguard Worker   sraiw t2, t1, 8              // t2 := ssssssCC
611*795d594fSAndroid Build Coastguard Worker   andi t1, t1, 0xFF            // t1 := BB
612*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
613*795d594fSAndroid Build Coastguard Worker     beqz t2, 1f                // Must throw before FETCH_ADVANCE_INST.
614*795d594fSAndroid Build Coastguard Worker%#:
615*795d594fSAndroid Build Coastguard Worker%  get_vreg("t1", "t1")         #  t1 := fp[BB]
616*795d594fSAndroid Build Coastguard Worker   FETCH_ADVANCE_INST 2         // advance xPC, load xINST
617*795d594fSAndroid Build Coastguard Worker   $instr                       // read t1 and t2, write result to t1.
618*795d594fSAndroid Build Coastguard Worker                                // do not clobber t3!
619*795d594fSAndroid Build Coastguard Worker   GET_INST_OPCODE t2           // t2 holds next opcode
620*795d594fSAndroid Build Coastguard Worker%  set_vreg("t1", "t3", z0="t0")  # fp[AA] := t1
621*795d594fSAndroid Build Coastguard Worker   GOTO_OPCODE t2               // continue to next
622*795d594fSAndroid Build Coastguard Worker1:
623*795d594fSAndroid Build Coastguard Worker%  if divz_throw:
624*795d594fSAndroid Build Coastguard Worker     tail common_errDivideByZero
625*795d594fSAndroid Build Coastguard Worker%#:
626