blob: 33199c4b179cb801802294c544eb7770c5aee8b1 [file] [log] [blame]
%verify "executed"
%include "mips/unopNarrower.S" {"instr":"b d2i_doconv", "instr_f":"b d2i_doconv"}
/*
* Convert the double in a0/a1 to an int in a0.
*
* We have to clip values to int min/max per the specification. The
* expected common case is a "reasonable" value that converts directly
* to modest integer. The EABI convert function isn't doing this for us.
* Use rBIX / rTEMP as global to hold arguments (they are not bound to a global var)
*/
%break
d2i_doconv:
#ifdef SOFT_FLOAT
la t0, .LDOUBLE_TO_INT_max
LOAD64(rARG2, rARG3, t0)
move rBIX, rARG0 # save a0
move rTEMP, rARG1 # and a1
JAL(__gedf2) # is arg >= maxint?
move t0, v0
li v0, ~0x80000000 # return maxint (7fffffff)
bgez t0, .L${opcode}_set_vreg # nonzero == yes
move rARG0, rBIX # recover arg
move rARG1, rTEMP
la t0, .LDOUBLE_TO_INT_min
LOAD64(rARG2, rARG3, t0)
JAL(__ledf2) # is arg <= minint?
move t0, v0
li v0, 0x80000000 # return minint (80000000)
blez t0, .L${opcode}_set_vreg # nonzero == yes
move rARG0, rBIX # recover arg
move rARG1, rTEMP
move rARG2, rBIX # compare against self
move rARG3, rTEMP
JAL(__nedf2) # is arg == self?
move t0, v0 # zero == no
li v0, 0
bnez t0, .L${opcode}_set_vreg # return zero for NaN
move rARG0, rBIX # recover arg
move rARG1, rTEMP
JAL(__fixdfsi) # convert double to int
b .L${opcode}_set_vreg
#else
la t0, .LDOUBLE_TO_INT_max
LOAD64_F(fa1, fa1f, t0)
c.ole.d fcc0, fa1, fa0
l.s fv0, .LDOUBLE_TO_INT_maxret
bc1t .L${opcode}_set_vreg_f
la t0, .LDOUBLE_TO_INT_min
LOAD64_F(fa1, fa1f, t0)
c.ole.d fcc0, fa0, fa1
l.s fv0, .LDOUBLE_TO_INT_minret
bc1t .L${opcode}_set_vreg_f
mov.d fa1, fa0
c.un.d fcc0, fa0, fa1
li.s fv0, 0
bc1t .L${opcode}_set_vreg_f
trunc.w.d fv0, fa0
b .L${opcode}_set_vreg_f
#endif
.LDOUBLE_TO_INT_max:
.dword 0x41dfffffffc00000
.LDOUBLE_TO_INT_min:
.dword 0xc1e0000000000000 # minint, as a double (high word)
.LDOUBLE_TO_INT_maxret:
.word 0x7fffffff
.LDOUBLE_TO_INT_minret:
.word 0x80000000