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> s0, s0, s1
7     */
8    /* floatop vAA, vBB, vCC */
9    FETCH w0, 1                         // r0<- CCBB
10    lsr     w1, w0, #8                  // r2<- CC
11    and     w0, w0, #255                // r1<- BB
12    GET_VREG  s1, w1
13    GET_VREG  s0, w0
14    $instr                              // s0<- op
15    lsr     w1, wINST, #8               // r1<- AA
16    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
17    GET_INST_OPCODE ip                  // extract opcode from rINST
18    SET_VREG_FLOAT s0, w1
19    GOTO_OPCODE ip                      // jump to next instruction
20
21%def fbinopWide(instr="fadd d0, d1, d2", result="d0", r1="d1", r2="d2"):
22    /*
23     * Generic 64-bit floating-point operation.
24     */
25    /* binop vAA, vBB, vCC */
26    FETCH w0, 1                         // w0<- CCBB
27    lsr     w4, wINST, #8               // w4<- AA
28    lsr     w2, w0, #8                  // w2<- CC
29    and     w1, w0, #255                // w1<- BB
30    GET_VREG_DOUBLE $r2, w2             // w2<- vCC
31    GET_VREG_DOUBLE $r1, w1             // w1<- vBB
32    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
33    $instr                              // $result<- op, w0-w4 changed
34    GET_INST_OPCODE ip                  // extract opcode from rINST
35    SET_VREG_DOUBLE $result, w4         // vAA<- $result
36    GOTO_OPCODE ip                      // jump to next instruction
37
38%def fbinop2addr(instr=""):
39    /*
40     * Generic 32-bit floating point "/2addr" binary operation.  Provide
41     * an "instr" line that specifies an instruction that performs
42     * "s2 = s0 op s1".
43     *
44     * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
45     */
46    /* binop/2addr vA, vB */
47    lsr     w3, wINST, #12              // w3<- B
48    ubfx    w9, wINST, #8, #4           // w9<- A
49    GET_VREG s1, w3
50    GET_VREG s0, w9
51    $instr                              // s2<- op
52    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
53    GET_INST_OPCODE ip                  // extract opcode from rINST
54    SET_VREG_FLOAT s2, w9
55    GOTO_OPCODE ip                      // jump to next instruction
56
57%def fbinopWide2addr(instr="fadd d0, d0, d1", r0="d0", r1="d1"):
58    /*
59     * Generic 64-bit floating point "/2addr" binary operation.
60     */
61    /* binop/2addr vA, vB */
62    lsr     w1, wINST, #12              // w1<- B
63    ubfx    w2, wINST, #8, #4           // w2<- A
64    GET_VREG_DOUBLE $r1, w1             // x1<- vB
65    GET_VREG_DOUBLE $r0, w2             // x0<- vA
66    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
67    $instr                              // result<- op
68    GET_INST_OPCODE ip                  // extract opcode from rINST
69    SET_VREG_DOUBLE $r0, w2             // vAA<- result
70    GOTO_OPCODE ip                      // jump to next instruction
71
72%def fcmp(r1="s1", r2="s2", cond="lt"):
73    /*
74     * Compare two floating-point values.  Puts 0, 1, or -1 into the
75     * destination register based on the results of the comparison.
76     */
77    /* op vAA, vBB, vCC */
78    FETCH w0, 1                         // w0<- CCBB
79%  if r1.startswith("d"):
80    LOAD_SCALED_VREG_MASK w5, 0xff      // w4<- ff * sizeof(vreg)
81    lsr     w4, wINST, #8               // w4<- AA
82    EXTRACT_SCALED_VREG w2, w5, w0, 0   // w2<- BB * sizeof(vreg)
83    EXTRACT_SCALED_VREG w3, w5, w0, 8   // w3<- CC * sizeof(vreg)
84    GET_VREG_DOUBLE_PRESCALED $r1, w2
85    GET_VREG_DOUBLE_PRESCALED $r2, w3
86%  else:
87    lsr     w4, wINST, #8               // w4<- AA
88    and     w2, w0, #255                // w2<- BB
89    lsr     w3, w0, #8                  // w3<- CC
90    GET_VREG $r1, w2
91    GET_VREG $r2, w3
92%  #endif
93    fcmp $r1, $r2
94    cset w0, ne
95    cneg w0, w0, $cond
96    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
97    GET_INST_OPCODE ip                  // extract opcode from rINST
98    SET_VREG w0, w4                     // vAA<- w0
99    GOTO_OPCODE ip                      // jump to next instruction
100
101%def funopNarrow(srcreg="s0", tgtreg="d0", instr=""):
102    /*
103     * Generic 32bit-to-32bit floating point unary operation.  Provide an
104     * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg".
105     *
106     * For: int-to-float, float-to-int
107     * TODO: refactor all of the conversions - parameterize width and use same template.
108     */
109    /* unop vA, vB */
110    lsr     w3, wINST, #12              // w3<- B
111    ubfx    w4, wINST, #8, #4           // w4<- A
112    GET_VREG $srcreg, w3
113    FETCH_ADVANCE_INST 1                // advance rPC, load wINST
114    $instr                              // d0<- op
115    GET_INST_OPCODE ip                  // extract opcode from wINST
116    SET_VREG_FLOAT $tgtreg, w4          // vA<- d0
117    GOTO_OPCODE ip                      // jump to next instruction
118
119%def funopNarrower(srcreg="s0", tgtreg="d0", instr=""):
120    /*
121     * Generic 64bit-to-32bit floating point unary operation.  Provide an
122     * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg".
123     *
124     * For: int-to-double, float-to-double, float-to-long
125     */
126    /* unop vA, vB */
127    lsr     w3, wINST, #12              // w3<- B
128    ubfx    w4, wINST, #8, #4           // w4<- A
129%  if srcreg.startswith("d"):
130    GET_VREG_DOUBLE $srcreg, w3
131%  else:
132    GET_VREG_WIDE $srcreg, w3
133%  #endif
134    FETCH_ADVANCE_INST 1                // advance rPC, load wINST
135    $instr                              // d0<- op
136    GET_INST_OPCODE ip                  // extract opcode from wINST
137    SET_VREG_FLOAT $tgtreg, w4          // vA<- d0
138    GOTO_OPCODE ip                      // jump to next instruction
139
140%def funopWide(srcreg="s0", tgtreg="d0", instr=""):
141    /*
142     * Generic 64bit-to-64bit floating point unary operation.  Provide an
143     * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg".
144     *
145     * For: long-to-double, double-to-long
146     */
147    /* unop vA, vB */
148    lsr     w3, wINST, #12              // w3<- B
149    ubfx    w4, wINST, #8, #4           // w4<- A
150%  if srcreg.startswith("d"):
151    GET_VREG_DOUBLE $srcreg, w3
152%  else:
153    GET_VREG_WIDE $srcreg, w3
154%  #endif
155    FETCH_ADVANCE_INST 1                // advance rPC, load wINST
156    $instr                              // d0<- op
157    GET_INST_OPCODE ip                  // extract opcode from wINST
158%  if tgtreg.startswith("d"):
159    SET_VREG_DOUBLE $tgtreg, w4         // vA<- d0
160%  else:
161    SET_VREG_WIDE $tgtreg, w4           // vA<- d0
162%  #endif
163    GOTO_OPCODE ip                      // jump to next instruction
164
165%def funopWider(srcreg="s0", tgtreg="d0", instr=""):
166    /*
167     * Generic 32bit-to-64bit floating point unary operation.  Provide an
168     * "instr" line that specifies an instruction that performs "$tgtreg = op $srcreg".
169     *
170     * For: int-to-double, float-to-double, float-to-long
171     */
172    /* unop vA, vB */
173    lsr     w3, wINST, #12              // w3<- B
174    ubfx    w4, wINST, #8, #4           // w4<- A
175    GET_VREG $srcreg, w3
176    FETCH_ADVANCE_INST 1                // advance rPC, load wINST
177    $instr                              // d0<- op
178    GET_INST_OPCODE ip                  // extract opcode from wINST
179    SET_VREG_WIDE $tgtreg, w4           // vA<- d0
180    GOTO_OPCODE ip                      // jump to next instruction
181
182%def op_add_double():
183%  fbinopWide(instr="fadd d0, d1, d2", result="d0", r1="d1", r2="d2")
184
185%def op_add_double_2addr():
186%  fbinopWide2addr(instr="fadd     d0, d0, d1", r0="d0", r1="d1")
187
188%def op_add_float():
189%  fbinop(instr="fadd   s0, s0, s1")
190
191%def op_add_float_2addr():
192%  fbinop2addr(instr="fadd   s2, s0, s1")
193
194%def op_cmpg_double():
195%  fcmp(r1="d1", r2="d2", cond="cc")
196
197%def op_cmpg_float():
198%  fcmp(r1="s1", r2="s2", cond="cc")
199
200%def op_cmpl_double():
201%  fcmp(r1="d1", r2="d2", cond="lt")
202
203%def op_cmpl_float():
204%  fcmp(r1="s1", r2="s2", cond="lt")
205
206%def op_div_double():
207%  fbinopWide(instr="fdiv d0, d1, d2", result="d0", r1="d1", r2="d2")
208
209%def op_div_double_2addr():
210%  fbinopWide2addr(instr="fdiv     d0, d0, d1", r0="d0", r1="d1")
211
212%def op_div_float():
213%  fbinop(instr="fdiv   s0, s0, s1")
214
215%def op_div_float_2addr():
216%  fbinop2addr(instr="fdiv   s2, s0, s1")
217
218%def op_double_to_float():
219%  funopNarrower(instr="fcvt s0, d0", srcreg="d0", tgtreg="s0")
220
221%def op_double_to_int():
222%  funopNarrower(instr="fcvtzs w0, d0", srcreg="d0", tgtreg="w0")
223
224%def op_double_to_long():
225%  funopWide(instr="fcvtzs x0, d0", srcreg="d0", tgtreg="x0")
226
227%def op_float_to_double():
228%  funopWider(instr="fcvt  d0, s0", srcreg="s0", tgtreg="d0")
229
230%def op_float_to_int():
231%  funopNarrow(instr="fcvtzs w0, s0", srcreg="s0", tgtreg="w0")
232
233%def op_float_to_long():
234%  funopWider(instr="fcvtzs x0, s0", srcreg="s0", tgtreg="x0")
235
236%def op_int_to_double():
237%  funopWider(instr="scvtf d0, w0", srcreg="w0", tgtreg="d0")
238
239%def op_int_to_float():
240%  funopNarrow(instr="scvtf s0, w0", srcreg="w0", tgtreg="s0")
241
242%def op_long_to_double():
243%  funopWide(instr="scvtf d0, x0", srcreg="x0", tgtreg="d0")
244
245%def op_long_to_float():
246%  funopNarrower(instr="scvtf s0, x0", srcreg="x0", tgtreg="s0")
247
248%def op_mul_double():
249%  fbinopWide(instr="fmul d0, d1, d2", result="d0", r1="d1", r2="d2")
250
251%def op_mul_double_2addr():
252%  fbinopWide2addr(instr="fmul     d0, d0, d1", r0="d0", r1="d1")
253
254%def op_mul_float():
255%  fbinop(instr="fmul   s0, s0, s1")
256
257%def op_mul_float_2addr():
258%  fbinop2addr(instr="fmul   s2, s0, s1")
259
260%def op_neg_double():
261%  unopWide(instr="eor     x0, x0, #0x8000000000000000")
262
263%def op_neg_float():
264%  unop(instr="eor     w0, w0, #0x80000000")
265
266%def op_rem_double():
267    /* rem vAA, vBB, vCC */
268    FETCH w0, 1                         // w0<- CCBB
269    lsr     w2, w0, #8                  // w2<- CC
270    and     w1, w0, #255                // w1<- BB
271    GET_VREG_DOUBLE d1, w2              // d1<- vCC
272    GET_VREG_DOUBLE d0, w1              // d0<- vBB
273    bl  fmod
274    lsr     w4, wINST, #8               // w4<- AA
275    FETCH_ADVANCE_INST 2                // advance rPC, load rINST
276    GET_INST_OPCODE ip                  // extract opcode from rINST
277    SET_VREG_WIDE d0, w4                // vAA<- result
278    GOTO_OPCODE ip                      // jump to next instruction
279    /* 11-14 instructions */
280
281%def op_rem_double_2addr():
282    /* rem vA, vB */
283    lsr     w1, wINST, #12              // w1<- B
284    ubfx    w2, wINST, #8, #4           // w2<- A
285    GET_VREG_DOUBLE d1, w1              // d1<- vB
286    GET_VREG_DOUBLE d0, w2              // d0<- vA
287    bl fmod
288    ubfx    w2, wINST, #8, #4           // w2<- A (need to reload - killed across call)
289    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
290    GET_INST_OPCODE ip                  // extract opcode from rINST
291    SET_VREG_WIDE d0, w2                // vAA<- result
292    GOTO_OPCODE ip                      // jump to next instruction
293    /* 10-13 instructions */
294
295%def op_rem_float():
296/* EABI doesn't define a float remainder function, but libm does */
297%  fbinop(instr="bl      fmodf")
298
299%def op_rem_float_2addr():
300    /* rem vA, vB */
301    lsr     w3, wINST, #12              // w3<- B
302    ubfx    w9, wINST, #8, #4           // w9<- A
303    GET_VREG s1, w3
304    GET_VREG s0, w9
305    bl  fmodf
306    ubfx    w9, wINST, #8, #4           // w9<- A
307    FETCH_ADVANCE_INST 1                // advance rPC, load rINST
308    GET_INST_OPCODE ip                  // extract opcode from rINST
309    SET_VREG_FLOAT s0, w9
310    GOTO_OPCODE ip                      // jump to next instruction
311
312%def op_sub_double():
313%  fbinopWide(instr="fsub d0, d1, d2", result="d0", r1="d1", r2="d2")
314
315%def op_sub_double_2addr():
316%  fbinopWide2addr(instr="fsub     d0, d0, d1", r0="d0", r1="d1")
317
318%def op_sub_float():
319%  fbinop(instr="fsub   s0, s0, s1")
320
321%def op_sub_float_2addr():
322%  fbinop2addr(instr="fsub   s2, s0, s1")
323