1%def fbinop(instr=""):
2    /*
3     * Generic 32-bit binary float operation.
4     *
5     * For: add-fp, sub-fp, mul-fp, div-fp, rem-fp
6     */
7
8    /* binop vAA, vBB, vCC */
9    FETCH(a0, 1)                           #  a0 <- CCBB
10    GET_OPA(rOBJ)                          #  rOBJ <- AA
11    srl       a3, a0, 8                    #  a3 <- CC
12    and       a2, a0, 255                  #  a2 <- BB
13    GET_VREG_F(fa1, a3)                    #  a1 <- vCC
14    GET_VREG_F(fa0, a2)                    #  a0 <- vBB
15
16    FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
17    $instr                                 #  f0 = result
18    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
19    SET_VREG_F_GOTO(fv0, rOBJ, t0)         #  vAA <- fv0
20
21%def fbinop2addr(instr=""):
22    /*
23     * Generic 32-bit "/2addr" binary operation.  Provide an "instr"
24     * that specifies an instruction that performs "fv0 = fa0 op fa1".
25     * This could be an MIPS instruction or a function call.
26     *
27     * For: add-float/2addr, sub-float/2addr, mul-float/2addr,
28     *      div-float/2addr, rem-float/2addr
29     */
30    /* binop/2addr vA, vB */
31    GET_OPA4(rOBJ)                         #  rOBJ <- A+
32    GET_OPB(a3)                            #  a3 <- B
33    GET_VREG_F(fa0, rOBJ)
34    GET_VREG_F(fa1, a3)
35    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
36
37    $instr
38    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
39    SET_VREG_F_GOTO(fv0, rOBJ, t0)         #  vA <- result
40
41%def fbinopWide(instr=""):
42    /*
43     * Generic 64-bit floating-point binary operation.  Provide an "instr"
44     * line that specifies an instruction that performs "fv0 = fa0 op fa1".
45     * This could be an MIPS instruction or a function call.
46     *
47     * for: add-double, sub-double, mul-double, div-double,
48     *      rem-double
49     *
50     */
51    /* binop vAA, vBB, vCC */
52    FETCH(a0, 1)                           #  a0 <- CCBB
53    GET_OPA(rOBJ)                          #  rOBJ <- AA
54    and       a2, a0, 255                  #  a2 <- BB
55    srl       a3, a0, 8                    #  a3 <- CC
56    EAS2(a2, rFP, a2)                      #  a2 <- &fp[BB]
57    EAS2(t1, rFP, a3)                      #  a3 <- &fp[CC]
58    LOAD64_F(fa0, fa0f, a2)
59    LOAD64_F(fa1, fa1f, t1)
60
61    FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
62    $instr
63    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
64    SET_VREG64_F_GOTO(fv0, fv0f, rOBJ, t0)  #  vAA/vAA+1 <- fv0
65
66%def fbinopWide2addr(instr=""):
67    /*
68     * Generic 64-bit floating-point "/2addr" binary operation.
69     * Provide an "instr" line that specifies an instruction that
70     * performs "fv0 = fa0 op fa1".
71     * This could be an MIPS instruction or a function call.
72     *
73     * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
74     *      div-double/2addr, rem-double/2addr
75     */
76    /* binop/2addr vA, vB */
77    GET_OPA4(rOBJ)                         #  rOBJ <- A+
78    GET_OPB(a1)                            #  a1 <- B
79    EAS2(a1, rFP, a1)                      #  a1 <- &fp[B]
80    EAS2(t0, rFP, rOBJ)                    #  t0 <- &fp[A]
81    LOAD64_F(fa0, fa0f, t0)
82    LOAD64_F(fa1, fa1f, a1)
83
84    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
85    $instr
86    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
87    SET_VREG64_F_GOTO(fv0, fv0f, rOBJ, t0)  #  vA/vA+1 <- fv0
88
89%def funop(instr=""):
90    /*
91     * Generic 32-bit floating-point unary operation.  Provide an "instr"
92     * line that specifies an instruction that performs "fv0 = op fa0".
93     * This could be a MIPS instruction or a function call.
94     *
95     * for: int-to-float
96     */
97    /* unop vA, vB */
98    GET_OPB(a3)                            #  a3 <- B
99    GET_OPA4(rOBJ)                         #  rOBJ <- A+
100    GET_VREG_F(fa0, a3)
101    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
102    $instr
103    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
104    SET_VREG_F_GOTO(fv0, rOBJ, t1)         #  vA <- fv0
105
106%def funopWider(instr=""):
107    /*
108     * Generic 32bit-to-64bit floating-point unary operation.  Provide an "instr"
109     * line that specifies an instruction that performs "fv0 = op fa0".
110     *
111     * For: int-to-double, float-to-double
112     */
113    /* unop vA, vB */
114    GET_OPA4(rOBJ)                         #  rOBJ <- A+
115    GET_OPB(a3)                            #  a3 <- B
116    GET_VREG_F(fa0, a3)
117    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
118    $instr
119    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
120    SET_VREG64_F_GOTO(fv0, fv0f, rOBJ, t0) #  vA/vA+1 <- fv0
121
122%def op_add_double():
123%  fbinopWide(instr="add.d fv0, fa0, fa1")
124
125%def op_add_double_2addr():
126%  fbinopWide2addr(instr="add.d fv0, fa0, fa1")
127
128%def op_add_float():
129%  fbinop(instr="add.s fv0, fa0, fa1")
130
131%def op_add_float_2addr():
132%  fbinop2addr(instr="add.s fv0, fa0, fa1")
133
134%def op_cmpg_double():
135%  op_cmpl_double(gt_bias="1")
136
137%def op_cmpg_float():
138%  op_cmpl_float(gt_bias="1")
139
140%def op_cmpl_double(gt_bias="0"):
141    /*
142     * Compare two floating-point values. Puts 0(==), 1(>), or -1(<)
143     * into the destination register based on the comparison results.
144     *
145     * For: cmpl-double, cmpg-double
146     */
147    /* op vAA, vBB, vCC */
148
149    FETCH(a0, 1)                           #  a0 <- CCBB
150    and       rOBJ, a0, 255                #  rOBJ <- BB
151    srl       t0, a0, 8                    #  t0 <- CC
152    EAS2(rOBJ, rFP, rOBJ)                  #  rOBJ <- &fp[BB]
153    EAS2(t0, rFP, t0)                      #  t0 <- &fp[CC]
154    LOAD64_F(ft0, ft0f, rOBJ)
155    LOAD64_F(ft1, ft1f, t0)
156#ifdef MIPS32REVGE6
157    cmp.eq.d  ft2, ft0, ft1
158    li        rTEMP, 0
159    bc1nez    ft2, 1f                      # done if vBB == vCC (ordered)
160    .if $gt_bias
161    cmp.lt.d  ft2, ft0, ft1
162    li        rTEMP, -1
163    bc1nez    ft2, 1f                      # done if vBB < vCC (ordered)
164    li        rTEMP, 1                     # vBB > vCC or unordered
165    .else
166    cmp.lt.d  ft2, ft1, ft0
167    li        rTEMP, 1
168    bc1nez    ft2, 1f                      # done if vBB > vCC (ordered)
169    li        rTEMP, -1                    # vBB < vCC or unordered
170    .endif
171#else
172    c.eq.d    fcc0, ft0, ft1
173    li        rTEMP, 0
174    bc1t      fcc0, 1f                     # done if vBB == vCC (ordered)
175    .if $gt_bias
176    c.olt.d   fcc0, ft0, ft1
177    li        rTEMP, -1
178    bc1t      fcc0, 1f                     # done if vBB < vCC (ordered)
179    li        rTEMP, 1                     # vBB > vCC or unordered
180    .else
181    c.olt.d   fcc0, ft1, ft0
182    li        rTEMP, 1
183    bc1t      fcc0, 1f                     # done if vBB > vCC (ordered)
184    li        rTEMP, -1                    # vBB < vCC or unordered
185    .endif
186#endif
1871:
188    GET_OPA(rOBJ)
189    FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
190    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
191    SET_VREG_GOTO(rTEMP, rOBJ, t0)         #  vAA <- rTEMP
192
193%def op_cmpl_float(gt_bias="0"):
194    /*
195     * Compare two floating-point values. Puts 0(==), 1(>), or -1(<)
196     * into the destination register based on the comparison results.
197     *
198     * for: cmpl-float, cmpg-float
199     */
200    /* op vAA, vBB, vCC */
201
202    FETCH(a0, 1)                           #  a0 <- CCBB
203    and       a2, a0, 255                  #  a2 <- BB
204    srl       a3, a0, 8
205    GET_VREG_F(ft0, a2)
206    GET_VREG_F(ft1, a3)
207#ifdef MIPS32REVGE6
208    cmp.eq.s  ft2, ft0, ft1
209    li        rTEMP, 0
210    bc1nez    ft2, 1f                      # done if vBB == vCC (ordered)
211    .if $gt_bias
212    cmp.lt.s  ft2, ft0, ft1
213    li        rTEMP, -1
214    bc1nez    ft2, 1f                      # done if vBB < vCC (ordered)
215    li        rTEMP, 1                     # vBB > vCC or unordered
216    .else
217    cmp.lt.s  ft2, ft1, ft0
218    li        rTEMP, 1
219    bc1nez    ft2, 1f                      # done if vBB > vCC (ordered)
220    li        rTEMP, -1                    # vBB < vCC or unordered
221    .endif
222#else
223    c.eq.s    fcc0, ft0, ft1
224    li        rTEMP, 0
225    bc1t      fcc0, 1f                     # done if vBB == vCC (ordered)
226    .if $gt_bias
227    c.olt.s   fcc0, ft0, ft1
228    li        rTEMP, -1
229    bc1t      fcc0, 1f                     # done if vBB < vCC (ordered)
230    li        rTEMP, 1                     # vBB > vCC or unordered
231    .else
232    c.olt.s   fcc0, ft1, ft0
233    li        rTEMP, 1
234    bc1t      fcc0, 1f                     # done if vBB > vCC (ordered)
235    li        rTEMP, -1                    # vBB < vCC or unordered
236    .endif
237#endif
2381:
239    GET_OPA(rOBJ)
240    FETCH_ADVANCE_INST(2)                  #  advance rPC, load rINST
241    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
242    SET_VREG_GOTO(rTEMP, rOBJ, t0)         #  vAA <- rTEMP
243
244%def op_div_double():
245%  fbinopWide(instr="div.d fv0, fa0, fa1")
246
247%def op_div_double_2addr():
248%  fbinopWide2addr(instr="div.d fv0, fa0, fa1")
249
250%def op_div_float():
251%  fbinop(instr="div.s fv0, fa0, fa1")
252
253%def op_div_float_2addr():
254%  fbinop2addr(instr="div.s fv0, fa0, fa1")
255
256%def op_double_to_float():
257%  unopNarrower(instr="cvt.s.d fv0, fa0")
258
259%def op_double_to_int():
260    /*
261     * double-to-int
262     *
263     * We have to clip values to int min/max per the specification.  The
264     * expected common case is a "reasonable" value that converts directly
265     * to modest integer.  The EABI convert function isn't doing this for us
266     * for pre-R6.
267     */
268    /* unop vA, vB */
269    GET_OPB(a3)                            #  a3 <- B
270    GET_OPA4(rOBJ)                         #  rOBJ <- A+
271    EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
272    LOAD64_F(fa0, fa0f, a3)
273    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
274#ifndef MIPS32REVGE6
275    li        t0, INT_MIN_AS_DOUBLE_HIGH
276    mtc1      zero, fa1
277    MOVE_TO_FPU_HIGH(t0, fa1, fa1f)
278    c.ole.d   fcc0, fa1, fa0
279#endif
280    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
281#ifndef MIPS32REVGE6
282    bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
283    c.eq.d    fcc0, fa0, fa0
284    mtc1      zero, fa0
285    MOVE_TO_FPU_HIGH(zero, fa0, fa0f)
286    movt.d    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_DOUBLE : 0
2871:
288#endif
289    trunc.w.d fa0, fa0
290    SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
291
292%def op_double_to_long():
293    /*
294     * double-to-long
295     *
296     * We have to clip values to long min/max per the specification.  The
297     * expected common case is a "reasonable" value that converts directly
298     * to modest integer.  The EABI convert function isn't doing this for us
299     * for pre-R6.
300     */
301    /* unop vA, vB */
302    GET_OPA4(rOBJ)                         #  rOBJ <- A+
303    GET_OPB(a3)                            #  a3 <- B
304    EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
305    LOAD64_F(fa0, fa0f, a3)
306    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
307
308#ifdef MIPS32REVGE6
309    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
310    trunc.l.d fa0, fa0
311    SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
312#else
313    c.eq.d    fcc0, fa0, fa0
314    li        rRESULT0, 0
315    li        rRESULT1, 0
316    bc1f      fcc0, .L${opcode}_get_opcode
317
318    li        t0, LONG_MIN_AS_DOUBLE_HIGH
319    mtc1      zero, fa1
320    MOVE_TO_FPU_HIGH(t0, fa1, fa1f)
321    c.ole.d   fcc0, fa0, fa1
322    li        rRESULT1, LONG_MIN_HIGH
323    bc1t      fcc0, .L${opcode}_get_opcode
324
325    neg.d     fa1, fa1
326    c.ole.d   fcc0, fa1, fa0
327    nor       rRESULT0, rRESULT0, zero
328    nor       rRESULT1, rRESULT1, zero
329    bc1t      fcc0, .L${opcode}_get_opcode
330
331    JAL(__fixdfdi)
332    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
333    b         .L${opcode}_set_vreg
334#endif
335%def op_double_to_long_helper_code():
336
337#ifndef MIPS32REVGE6
338.Lop_double_to_long_get_opcode:
339    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
340.Lop_double_to_long_set_vreg:
341    SET_VREG64_GOTO(rRESULT0, rRESULT1, rOBJ, t1)   #  vA/vA+1 <- v0/v1
342#endif
343
344%def op_float_to_double():
345%  funopWider(instr="cvt.d.s fv0, fa0")
346
347%def op_float_to_int():
348    /*
349     * float-to-int
350     *
351     * We have to clip values to int min/max per the specification.  The
352     * expected common case is a "reasonable" value that converts directly
353     * to modest integer.  The EABI convert function isn't doing this for us
354     * for pre-R6.
355     */
356    /* unop vA, vB */
357    GET_OPB(a3)                            #  a3 <- B
358    GET_OPA4(rOBJ)                         #  rOBJ <- A+
359    GET_VREG_F(fa0, a3)
360    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
361
362#ifndef MIPS32REVGE6
363    li        t0, INT_MIN_AS_FLOAT
364    mtc1      t0, fa1
365    c.ole.s   fcc0, fa1, fa0
366#endif
367    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
368#ifndef MIPS32REVGE6
369    bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
370    c.eq.s    fcc0, fa0, fa0
371    mtc1      zero, fa0
372    movt.s    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_FLOAT : 0
3731:
374#endif
375    trunc.w.s fa0, fa0
376    SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
377
378%def op_float_to_long():
379    /*
380     * float-to-long
381     *
382     * We have to clip values to long min/max per the specification.  The
383     * expected common case is a "reasonable" value that converts directly
384     * to modest integer.  The EABI convert function isn't doing this for us
385     * for pre-R6.
386     */
387    /* unop vA, vB */
388    GET_OPA4(rOBJ)                         #  rOBJ <- A+
389    GET_OPB(a3)                            #  a3 <- B
390    GET_VREG_F(fa0, a3)
391    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
392
393#ifdef MIPS32REVGE6
394    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
395    trunc.l.s fa0, fa0
396    SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
397#else
398    c.eq.s    fcc0, fa0, fa0
399    li        rRESULT0, 0
400    li        rRESULT1, 0
401    bc1f      fcc0, .L${opcode}_get_opcode
402
403    li        t0, LONG_MIN_AS_FLOAT
404    mtc1      t0, fa1
405    c.ole.s   fcc0, fa0, fa1
406    li        rRESULT1, LONG_MIN_HIGH
407    bc1t      fcc0, .L${opcode}_get_opcode
408
409    neg.s     fa1, fa1
410    c.ole.s   fcc0, fa1, fa0
411    nor       rRESULT0, rRESULT0, zero
412    nor       rRESULT1, rRESULT1, zero
413    bc1t      fcc0, .L${opcode}_get_opcode
414
415    JAL(__fixsfdi)
416    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
417    b         .L${opcode}_set_vreg
418#endif
419%def op_float_to_long_helper_code():
420
421#ifndef MIPS32REVGE6
422.Lop_float_to_long_get_opcode:
423    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
424.Lop_float_to_long_set_vreg:
425    SET_VREG64_GOTO(rRESULT0, rRESULT1, rOBJ, t1)   #  vA/vA+1 <- v0/v1
426#endif
427
428%def op_int_to_double():
429%  funopWider(instr="cvt.d.w fv0, fa0")
430
431%def op_int_to_float():
432%  funop(instr="cvt.s.w fv0, fa0")
433
434%def op_long_to_double():
435    /*
436     * long-to-double
437     */
438    /* unop vA, vB */
439    GET_OPA4(rOBJ)                         #  rOBJ <- A+
440    GET_OPB(a3)                            #  a3 <- B
441    EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
442
443#ifdef MIPS32REVGE6
444    LOAD64_F(fv0, fv0f, a3)
445    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
446    cvt.d.l   fv0, fv0
447#else
448    LOAD64(rARG0, rARG1, a3)
449    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
450    JAL(__floatdidf)                       #  a0/a1 <- op, a2-a3 changed
451#endif
452
453    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
454    SET_VREG64_F_GOTO(fv0, fv0f, rOBJ, t0) #  vA/vA+1 <- result
455
456%def op_long_to_float():
457    /*
458     * long-to-float
459     */
460    /* unop vA, vB */
461    GET_OPB(a3)                            #  a3 <- B
462    GET_OPA4(rOBJ)                         #  rOBJ <- A+
463    EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
464
465#ifdef MIPS32REVGE6
466    LOAD64_F(fv0, fv0f, a3)
467    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
468    cvt.s.l   fv0, fv0
469#else
470    LOAD64(rARG0, rARG1, a3)
471    FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
472    JAL(__floatdisf)
473#endif
474
475    GET_INST_OPCODE(t0)                    #  extract opcode from rINST
476    SET_VREG_F_GOTO(fv0, rOBJ, t0)         #  vA <- fv0
477
478%def op_mul_double():
479%  fbinopWide(instr="mul.d fv0, fa0, fa1")
480
481%def op_mul_double_2addr():
482%  fbinopWide2addr(instr="mul.d fv0, fa0, fa1")
483
484%def op_mul_float():
485%  fbinop(instr="mul.s fv0, fa0, fa1")
486
487%def op_mul_float_2addr():
488%  fbinop2addr(instr="mul.s fv0, fa0, fa1")
489
490%def op_neg_double():
491%  unopWide(instr="addu a1, a1, 0x80000000")
492
493%def op_neg_float():
494%  unop(instr="addu a0, a0, 0x80000000")
495
496%def op_rem_double():
497%  fbinopWide(instr="JAL(fmod)")
498
499%def op_rem_double_2addr():
500%  fbinopWide2addr(instr="JAL(fmod)")
501
502%def op_rem_float():
503%  fbinop(instr="JAL(fmodf)")
504
505%def op_rem_float_2addr():
506%  fbinop2addr(instr="JAL(fmodf)")
507
508%def op_sub_double():
509%  fbinopWide(instr="sub.d fv0, fa0, fa1")
510
511%def op_sub_double_2addr():
512%  fbinopWide2addr(instr="sub.d fv0, fa0, fa1")
513
514%def op_sub_float():
515%  fbinop(instr="sub.s fv0, fa0, fa1")
516
517%def op_sub_float_2addr():
518%  fbinop2addr(instr="sub.s fv0, fa0, fa1")
519