1%default { "naninst":"mvn     r1, #0" }
2%verify "executed"
3%verify "basic lt, gt, eq */
4%verify "left arg NaN"
5%verify "right arg NaN"
6    /*
7     * Compare two floating-point values.  Puts 0, 1, or -1 into the
8     * destination register based on the results of the comparison.
9     *
10     * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
11     * on what value we'd like to return when one of the operands is NaN.
12     *
13     * The operation we're implementing is:
14     *   if (x == y)
15     *     return 0;
16     *   else if (x < y)
17     *     return -1;
18     *   else if (x > y)
19     *     return 1;
20     *   else
21     *     return {-1,1};  // one or both operands was NaN
22     *
23     * The straightforward implementation requires 3 calls to functions
24     * that return a result in r0.  We can do it with two calls if our
25     * EABI library supports __aeabi_cfcmple (only one if we want to check
26     * for NaN directly):
27     *   check x <= y
28     *     if <, return -1
29     *     if ==, return 0
30     *   check y <= x
31     *     if <, return 1
32     *   return {-1,1}
33     *
34     * for: cmpl-float, cmpg-float
35     */
36    /* op vAA, vBB, vCC */
37    FETCH(r0, 1)                        @ r0<- CCBB
38    and     r2, r0, #255                @ r2<- BB
39    mov     r3, r0, lsr #8              @ r3<- CC
40    GET_VREG(r9, r2)                    @ r9<- vBB
41    GET_VREG(r10, r3)                   @ r10<- vCC
42    mov     r0, r9                      @ copy to arg registers
43    mov     r1, r10
44    bl      __aeabi_cfcmple             @ cmp <=: C clear if <, Z set if eq
45    bhi     .L${opcode}_gt_or_nan       @ C set and Z clear, disambiguate
46    mvncc   r1, #0                      @ (less than) r1<- -1
47    moveq   r1, #0                      @ (equal) r1<- 0, trumps less than
48.L${opcode}_finish:
49    mov     r3, rINST, lsr #8           @ r3<- AA
50    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
51    SET_VREG(r1, r3)                    @ vAA<- r1
52    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
53    GOTO_OPCODE(ip)                     @ jump to next instruction
54%break
55
56    @ Test for NaN with a second comparison.  EABI forbids testing bit
57    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
58    @ make the library call.
59.L${opcode}_gt_or_nan:
60    mov     r1, r9                      @ reverse order
61    mov     r0, r10
62    bl      __aeabi_cfcmple             @ r0<- Z set if eq, C clear if <
63    @bleq    common_abort
64    movcc   r1, #1                      @ (greater than) r1<- 1
65    bcc     .L${opcode}_finish
66    $naninst                            @ r1<- 1 or -1 for NaN
67    b       .L${opcode}_finish
68
69
70#if 0       /* "clasic" form */
71    FETCH(r0, 1)                        @ r0<- CCBB
72    and     r2, r0, #255                @ r2<- BB
73    mov     r3, r0, lsr #8              @ r3<- CC
74    GET_VREG(r9, r2)                    @ r9<- vBB
75    GET_VREG(r10, r3)                   @ r10<- vCC
76    mov     r0, r9                      @ r0<- vBB
77    mov     r1, r10                     @ r1<- vCC
78    bl      __aeabi_fcmpeq              @ r0<- (vBB == vCC)
79    cmp     r0, #0                      @ equal?
80    movne   r1, #0                      @ yes, result is 0
81    bne     ${opcode}_finish
82    mov     r0, r9                      @ r0<- vBB
83    mov     r1, r10                     @ r1<- vCC
84    bl      __aeabi_fcmplt              @ r0<- (vBB < vCC)
85    cmp     r0, #0                      @ less than?
86    b       ${opcode}_continue
87@%break
88
89${opcode}_continue:
90    mvnne   r1, #0                      @ yes, result is -1
91    bne     ${opcode}_finish
92    mov     r0, r9                      @ r0<- vBB
93    mov     r1, r10                     @ r1<- vCC
94    bl      __aeabi_fcmpgt              @ r0<- (vBB > vCC)
95    cmp     r0, #0                      @ greater than?
96    beq     ${opcode}_nan               @ no, must be NaN
97    mov     r1, #1                      @ yes, result is 1
98    @ fall through to _finish
99
100${opcode}_finish:
101    mov     r3, rINST, lsr #8           @ r3<- AA
102    FETCH_ADVANCE_INST(2)               @ advance rPC, load rINST
103    SET_VREG(r1, r3)                    @ vAA<- r1
104    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
105    GOTO_OPCODE(ip)                     @ jump to next instruction
106
107    /*
108     * This is expected to be uncommon, so we double-branch (once to here,
109     * again back to _finish).
110     */
111${opcode}_nan:
112    $naninst                            @ r1<- 1 or -1 for NaN
113    b       ${opcode}_finish
114
115#endif
116