| %default { "naninst":"li rTEMP, -1" } |
| /* |
| * Compare two floating-point values. Puts 0, 1, or -1 into the |
| * destination register rTEMP based on the results of the comparison. |
| * |
| * Provide a "naninst" instruction that puts 1 or -1 into rTEMP depending |
| * on what value we'd like to return when one of the operands is NaN. |
| * |
| * The operation we're implementing is: |
| * if (x == y) |
| * return 0; |
| * else if (x < y) |
| * return -1; |
| * else if (x > y) |
| * return 1; |
| * else |
| * return {-1 or 1}; // one or both operands was NaN |
| * |
| * for: cmpl-float, cmpg-float |
| */ |
| /* op vAA, vBB, vCC */ |
| |
| /* "clasic" form */ |
| FETCH(a0, 1) # a0 <- CCBB |
| and a2, a0, 255 # a2 <- BB |
| srl a3, a0, 8 |
| GET_VREG_F(ft0, a2) |
| GET_VREG_F(ft1, a3) |
| #ifdef MIPS32REVGE6 |
| cmp.ult.s ft2, ft0, ft1 # Is ft0 < ft1 |
| li rTEMP, -1 |
| bc1nez ft2, .L${opcode}_finish |
| cmp.ult.s ft2, ft1, ft0 |
| li rTEMP, 1 |
| bc1nez ft2, .L${opcode}_finish |
| cmp.eq.s ft2, ft0, ft1 |
| li rTEMP, 0 |
| bc1nez ft2, .L${opcode}_finish |
| b .L${opcode}_nan |
| #else |
| c.olt.s fcc0, ft0, ft1 # Is ft0 < ft1 |
| li rTEMP, -1 |
| bc1t fcc0, .L${opcode}_finish |
| c.olt.s fcc0, ft1, ft0 |
| li rTEMP, 1 |
| bc1t fcc0, .L${opcode}_finish |
| c.eq.s fcc0, ft0, ft1 |
| li rTEMP, 0 |
| bc1t fcc0, .L${opcode}_finish |
| b .L${opcode}_nan |
| #endif |
| %break |
| |
| .L${opcode}_nan: |
| $naninst |
| |
| .L${opcode}_finish: |
| GET_OPA(rOBJ) |
| FETCH_ADVANCE_INST(2) # advance rPC, load rINST |
| GET_INST_OPCODE(t0) # extract opcode from rINST |
| SET_VREG_GOTO(rTEMP, rOBJ, t0) # vAA <- rTEMP |