1%def fbinop(instr=""):
2    /*:
3     * Generic 32-bit floating-point operation.
4     *
5     * For: add-float, sub-float, mul-float, div-float.
6     * form: <op> f0, f0, f1
7     */
8    /* binop vAA, vBB, vCC */
9    srl     a4, rINST, 8                # a4 <- AA
10    lbu     a2, 2(rPC)                  # a2 <- BB
11    lbu     a3, 3(rPC)                  # a3 <- CC
12    GET_VREG_FLOAT f0, a2               # f0 <- vBB
13    GET_VREG_FLOAT f1, a3               # f1 <- vCC
14    $instr                              # f0 <- f0 op f1
15    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
16    GET_INST_OPCODE v0                  # extract opcode from rINST
17    SET_VREG_FLOAT f0, a4               # vAA <- f0
18    GOTO_OPCODE v0                      # jump to next instruction
19
20%def fbinop2addr(instr=""):
21    /*:
22     * Generic 32-bit "/2addr" floating-point operation.
23     *
24     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr.
25     * form: <op> f0, f0, f1
26     */
27    /* binop/2addr vA, vB */
28    ext     a2, rINST, 8, 4             # a2 <- A
29    ext     a3, rINST, 12, 4            # a3 <- B
30    GET_VREG_FLOAT f0, a2               # f0 <- vA
31    GET_VREG_FLOAT f1, a3               # f1 <- vB
32    $instr                              # f0 <- f0 op f1
33    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
34    GET_INST_OPCODE v0                  # extract opcode from rINST
35    SET_VREG_FLOAT f0, a2               # vA <- f0
36    GOTO_OPCODE v0                      # jump to next instruction
37
38%def fbinopWide(instr=""):
39    /*:
40     * Generic 64-bit floating-point operation.
41     *
42     * For: add-double, sub-double, mul-double, div-double.
43     * form: <op> f0, f0, f1
44     */
45    /* binop vAA, vBB, vCC */
46    srl     a4, rINST, 8                # a4 <- AA
47    lbu     a2, 2(rPC)                  # a2 <- BB
48    lbu     a3, 3(rPC)                  # a3 <- CC
49    GET_VREG_DOUBLE f0, a2              # f0 <- vBB
50    GET_VREG_DOUBLE f1, a3              # f1 <- vCC
51    $instr                              # f0 <- f0 op f1
52    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
53    GET_INST_OPCODE v0                  # extract opcode from rINST
54    SET_VREG_DOUBLE f0, a4              # vAA <- f0
55    GOTO_OPCODE v0                      # jump to next instruction
56
57%def fbinopWide2addr(instr=""):
58    /*:
59     * Generic 64-bit "/2addr" floating-point operation.
60     *
61     * For: add-double/2addr, sub-double/2addr, mul-double/2addr, div-double/2addr.
62     * form: <op> f0, f0, f1
63     */
64    /* binop/2addr vA, vB */
65    ext     a2, rINST, 8, 4             # a2 <- A
66    ext     a3, rINST, 12, 4            # a3 <- B
67    GET_VREG_DOUBLE f0, a2              # f0 <- vA
68    GET_VREG_DOUBLE f1, a3              # f1 <- vB
69    $instr                              # f0 <- f0 op f1
70    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
71    GET_INST_OPCODE v0                  # extract opcode from rINST
72    SET_VREG_DOUBLE f0, a2              # vA <- f0
73    GOTO_OPCODE v0                      # jump to next instruction
74
75%def fcmp(gt_bias=""):
76    /*
77     * Compare two floating-point values.  Puts 0, 1, or -1 into the
78     * destination register based on the results of the comparison.
79     *
80     * For: cmpl-float, cmpg-float
81     */
82    /* op vAA, vBB, vCC */
83    srl     a4, rINST, 8                # a4 <- AA
84    lbu     a2, 2(rPC)                  # a2 <- BB
85    lbu     a3, 3(rPC)                  # a3 <- CC
86    GET_VREG_FLOAT f0, a2               # f0 <- vBB
87    GET_VREG_FLOAT f1, a3               # f1 <- vCC
88    cmp.eq.s f2, f0, f1
89    li      a0, 0
90    bc1nez  f2, 1f                      # done if vBB == vCC (ordered)
91    .if $gt_bias
92    cmp.lt.s f2, f0, f1
93    li      a0, -1
94    bc1nez  f2, 1f                      # done if vBB < vCC (ordered)
95    li      a0, 1                       # vBB > vCC or unordered
96    .else
97    cmp.lt.s f2, f1, f0
98    li      a0, 1
99    bc1nez  f2, 1f                      # done if vBB > vCC (ordered)
100    li      a0, -1                      # vBB < vCC or unordered
101    .endif
1021:
103    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
104    GET_INST_OPCODE v0                  # extract opcode from rINST
105    SET_VREG a0, a4                     # vAA <- a0
106    GOTO_OPCODE v0                      # jump to next instruction
107
108%def fcmpWide(gt_bias=""):
109    /*
110     * Compare two floating-point values.  Puts 0, 1, or -1 into the
111     * destination register based on the results of the comparison.
112     *
113     * For: cmpl-double, cmpg-double
114     */
115    /* op vAA, vBB, vCC */
116    srl     a4, rINST, 8                # a4 <- AA
117    lbu     a2, 2(rPC)                  # a2 <- BB
118    lbu     a3, 3(rPC)                  # a3 <- CC
119    GET_VREG_DOUBLE f0, a2              # f0 <- vBB
120    GET_VREG_DOUBLE f1, a3              # f1 <- vCC
121    cmp.eq.d f2, f0, f1
122    li      a0, 0
123    bc1nez  f2, 1f                      # done if vBB == vCC (ordered)
124    .if $gt_bias
125    cmp.lt.d f2, f0, f1
126    li      a0, -1
127    bc1nez  f2, 1f                      # done if vBB < vCC (ordered)
128    li      a0, 1                       # vBB > vCC or unordered
129    .else
130    cmp.lt.d f2, f1, f0
131    li      a0, 1
132    bc1nez  f2, 1f                      # done if vBB > vCC (ordered)
133    li      a0, -1                      # vBB < vCC or unordered
134    .endif
1351:
136    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
137    GET_INST_OPCODE v0                  # extract opcode from rINST
138    SET_VREG a0, a4                     # vAA <- a0
139    GOTO_OPCODE v0                      # jump to next instruction
140
141%def fcvtFooter(suffix="", valreg=""):
142    /*
143     * Stores a specified register containing the result of conversion
144     * from or to a floating-point type and jumps to the next instruction.
145     *
146     * Expects a1 to contain the destination Dalvik register number.
147     * a1 is set up by fcvtHeader.S.
148     *
149     * For: int-to-float, int-to-double, long-to-float, long-to-double,
150     *      float-to-int, float-to-long, float-to-double, double-to-int,
151     *      double-to-long, double-to-float, neg-float, neg-double.
152     *
153     * Note that this file can't be included after a break in other files
154     * and in those files its contents appear as a copy.
155     * See: float-to-int, float-to-long, double-to-int, double-to-long.
156     */
157    GET_INST_OPCODE v0                  # extract opcode from rINST
158    SET_VREG$suffix $valreg, a1
159    GOTO_OPCODE v0                      # jump to next instruction
160
161%def fcvtHeader(suffix="", valreg=""):
162    /*
163     * Loads a specified register from vB. Used primarily for conversions
164     * from or to a floating-point type.
165     *
166     * Sets up a1 = A and a2 = B. a2 is later used by fcvtFooter.S to
167     * store the result in vA and jump to the next instruction.
168     *
169     * For: int-to-float, int-to-double, long-to-float, long-to-double,
170     *      float-to-int, float-to-long, float-to-double, double-to-int,
171     *      double-to-long, double-to-float, neg-float, neg-double.
172     */
173    ext     a1, rINST, 8, 4             # a1 <- A
174    srl     a2, rINST, 12               # a2 <- B
175    GET_VREG$suffix $valreg, a2
176    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
177
178%def op_add_double():
179%  fbinopWide(instr="add.d f0, f0, f1")
180
181%def op_add_double_2addr():
182%  fbinopWide2addr(instr="add.d f0, f0, f1")
183
184%def op_add_float():
185%  fbinop(instr="add.s f0, f0, f1")
186
187%def op_add_float_2addr():
188%  fbinop2addr(instr="add.s f0, f0, f1")
189
190%def op_cmpg_double():
191%  fcmpWide(gt_bias="1")
192
193%def op_cmpg_float():
194%  fcmp(gt_bias="1")
195
196%def op_cmpl_double():
197%  fcmpWide(gt_bias="0")
198
199%def op_cmpl_float():
200%  fcmp(gt_bias="0")
201
202%def op_div_double():
203%  fbinopWide(instr="div.d f0, f0, f1")
204
205%def op_div_double_2addr():
206%  fbinopWide2addr(instr="div.d f0, f0, f1")
207
208%def op_div_float():
209%  fbinop(instr="div.s f0, f0, f1")
210
211%def op_div_float_2addr():
212%  fbinop2addr(instr="div.s f0, f0, f1")
213
214%def op_double_to_float():
215    /*
216     * Conversion from or to floating-point happens in a floating-point register.
217     * Therefore we load the input and store the output into or from a
218     * floating-point register irrespective of the type.
219     */
220%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
221    cvt.s.d f0, f0
222%  fcvtFooter(suffix="_FLOAT", valreg="f0")
223
224%def op_double_to_int():
225%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
226    trunc.w.d f0, f0
227%  fcvtFooter(suffix="_FLOAT", valreg="f0")
228
229%def op_double_to_long():
230%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
231    trunc.l.d f0, f0
232%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
233
234%def op_float_to_double():
235    /*
236     * Conversion from or to floating-point happens in a floating-point register.
237     * Therefore we load the input and store the output into or from a
238     * floating-point register irrespective of the type.
239     */
240%  fcvtHeader(suffix="_FLOAT", valreg="f0")
241    cvt.d.s f0, f0
242%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
243
244%def op_float_to_int():
245%  fcvtHeader(suffix="_FLOAT", valreg="f0")
246    trunc.w.s f0, f0
247%  fcvtFooter(suffix="_FLOAT", valreg="f0")
248
249%def op_float_to_long():
250%  fcvtHeader(suffix="_FLOAT", valreg="f0")
251    trunc.l.s f0, f0
252%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
253
254%def op_int_to_double():
255    /*
256     * Conversion from or to floating-point happens in a floating-point register.
257     * Therefore we load the input and store the output into or from a
258     * floating-point register irrespective of the type.
259     */
260%  fcvtHeader(suffix="_FLOAT", valreg="f0")
261    cvt.d.w f0, f0
262%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
263
264%def op_int_to_float():
265    /*
266     * Conversion from or to floating-point happens in a floating-point register.
267     * Therefore we load the input and store the output into or from a
268     * floating-point register irrespective of the type.
269     */
270%  fcvtHeader(suffix="_FLOAT", valreg="f0")
271    cvt.s.w f0, f0
272%  fcvtFooter(suffix="_FLOAT", valreg="f0")
273
274%def op_long_to_double():
275    /*
276     * Conversion from or to floating-point happens in a floating-point register.
277     * Therefore we load the input and store the output into or from a
278     * floating-point register irrespective of the type.
279     */
280%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
281    cvt.d.l f0, f0
282%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
283
284%def op_long_to_float():
285    /*
286     * Conversion from or to floating-point happens in a floating-point register.
287     * Therefore we load the input and store the output into or from a
288     * floating-point register irrespective of the type.
289     */
290%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
291    cvt.s.l f0, f0
292%  fcvtFooter(suffix="_FLOAT", valreg="f0")
293
294%def op_mul_double():
295%  fbinopWide(instr="mul.d f0, f0, f1")
296
297%def op_mul_double_2addr():
298%  fbinopWide2addr(instr="mul.d f0, f0, f1")
299
300%def op_mul_float():
301%  fbinop(instr="mul.s f0, f0, f1")
302
303%def op_mul_float_2addr():
304%  fbinop2addr(instr="mul.s f0, f0, f1")
305
306%def op_neg_double():
307%  fcvtHeader(suffix="_DOUBLE", valreg="f0")
308    neg.d   f0, f0
309%  fcvtFooter(suffix="_DOUBLE", valreg="f0")
310
311%def op_neg_float():
312%  fcvtHeader(suffix="_FLOAT", valreg="f0")
313    neg.s   f0, f0
314%  fcvtFooter(suffix="_FLOAT", valreg="f0")
315
316%def op_rem_double():
317    /* rem-double vAA, vBB, vCC */
318    .extern fmod
319    lbu     a2, 2(rPC)                  # a2 <- BB
320    lbu     a3, 3(rPC)                  # a3 <- CC
321    GET_VREG_DOUBLE f12, a2             # f12 <- vBB
322    GET_VREG_DOUBLE f13, a3             # f13 <- vCC
323    jal     fmod                        # f0 <- f12 op f13
324    srl     a4, rINST, 8                # a4 <- AA
325    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
326    GET_INST_OPCODE v0                  # extract opcode from rINST
327    SET_VREG_DOUBLE f0, a4              # vAA <- f0
328    GOTO_OPCODE v0                      # jump to next instruction
329
330%def op_rem_double_2addr():
331    /* rem-double/2addr vA, vB */
332    .extern fmod
333    ext     a2, rINST, 8, 4             # a2 <- A
334    ext     a3, rINST, 12, 4            # a3 <- B
335    GET_VREG_DOUBLE f12, a2             # f12 <- vA
336    GET_VREG_DOUBLE f13, a3             # f13 <- vB
337    jal     fmod                        # f0 <- f12 op f13
338    ext     a2, rINST, 8, 4             # a2 <- A
339    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
340    GET_INST_OPCODE v0                  # extract opcode from rINST
341    SET_VREG_DOUBLE f0, a2              # vA <- f0
342    GOTO_OPCODE v0                      # jump to next instruction
343
344%def op_rem_float():
345    /* rem-float vAA, vBB, vCC */
346    .extern fmodf
347    lbu     a2, 2(rPC)                  # a2 <- BB
348    lbu     a3, 3(rPC)                  # a3 <- CC
349    GET_VREG_FLOAT f12, a2              # f12 <- vBB
350    GET_VREG_FLOAT f13, a3              # f13 <- vCC
351    jal     fmodf                       # f0 <- f12 op f13
352    srl     a4, rINST, 8                # a4 <- AA
353    FETCH_ADVANCE_INST 2                # advance rPC, load rINST
354    GET_INST_OPCODE v0                  # extract opcode from rINST
355    SET_VREG_FLOAT f0, a4               # vAA <- f0
356    GOTO_OPCODE v0                      # jump to next instruction
357
358%def op_rem_float_2addr():
359    /* rem-float/2addr vA, vB */
360    .extern fmodf
361    ext     a2, rINST, 8, 4             # a2 <- A
362    ext     a3, rINST, 12, 4            # a3 <- B
363    GET_VREG_FLOAT f12, a2              # f12 <- vA
364    GET_VREG_FLOAT f13, a3              # f13 <- vB
365    jal     fmodf                       # f0 <- f12 op f13
366    ext     a2, rINST, 8, 4             # a2 <- A
367    FETCH_ADVANCE_INST 1                # advance rPC, load rINST
368    GET_INST_OPCODE v0                  # extract opcode from rINST
369    SET_VREG_FLOAT f0, a2               # vA <- f0
370    GOTO_OPCODE v0                      # jump to next instruction
371
372%def op_sub_double():
373%  fbinopWide(instr="sub.d f0, f0, f1")
374
375%def op_sub_double_2addr():
376%  fbinopWide2addr(instr="sub.d f0, f0, f1")
377
378%def op_sub_float():
379%  fbinop(instr="sub.s f0, f0, f1")
380
381%def op_sub_float_2addr():
382%  fbinop2addr(instr="sub.s f0, f0, f1")
383