208 lines
8.6 KiB
NASM
208 lines
8.6 KiB
NASM
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;;;
|
||
|
;;; Microsoft Research Singularity
|
||
|
;;;
|
||
|
;;; Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
;;;
|
||
|
;;; This file contains ARM-specific assembly code.
|
||
|
;;;
|
||
|
|
||
|
; __dtoi64 double precision floating point to signed 64-bit integer convert
|
||
|
;
|
||
|
; Input: r1 - Most significant word of the double to be converted
|
||
|
; r0 - Least significant word of the double to be converted
|
||
|
;
|
||
|
; Output: r1 - Most significant word of the converted double in signed
|
||
|
; 64-bit integer format
|
||
|
; r0 - Least significant word of the converted double in signed
|
||
|
; 64-bit integer format
|
||
|
;
|
||
|
|
||
|
; Local storage size and offsets
|
||
|
LOC_SIZE EQU 0x18
|
||
|
OrgOp1h EQU 0x14
|
||
|
OrgOp1l EQU 0x10
|
||
|
ExDResh EQU 0x0C
|
||
|
ExDResl EQU 0x08
|
||
|
NewResh EQU 0x14
|
||
|
NewResl EQU 0x10
|
||
|
|
||
|
|
||
|
GET fpe.asm
|
||
|
GET kxarm.inc
|
||
|
|
||
|
AREA |.text|, CODE, READONLY
|
||
|
|
||
|
Export __dtoi64
|
||
|
IMPORT FPE_Raise
|
||
|
|
||
|
NESTED_ENTRY __dtoi64
|
||
|
EnterWithLR_16
|
||
|
STMFD sp!, {lr} ; Save return address
|
||
|
SUB sp, sp, #LOC_SIZE ; Allocate local storage
|
||
|
PROLOG_END
|
||
|
|
||
|
STR r1, [sp, #OrgOp1h] ; Save off original args in case of exception
|
||
|
ORRS r12, r0, r1, LSL #1 ; Check for zero
|
||
|
STR r0, [sp, #OrgOp1l] ; ..
|
||
|
MOVEQ r1, r0 ; return if zero (r0 already zero)
|
||
|
ADDEQ sp, sp, #LOC_SIZE ; restore stack
|
||
|
IF Interworking :LOR: Thumbing
|
||
|
LDMEQFD sp!, {lr} ; ..
|
||
|
BXEQ lr
|
||
|
ELSE
|
||
|
LDMEQFD sp!, {pc} ; ..
|
||
|
ENDIF
|
||
|
|
||
|
|
||
|
MOVS r2, r1, LSL #1 ; Right justify exponent, save sign bit in C
|
||
|
MOV r1, r1, LSL #11 ; Left justify mantissa
|
||
|
ORR r1, r1, r0, LSR #21 ; ..
|
||
|
; ..
|
||
|
MOV r0, r0, LSL #11 ; ..
|
||
|
ORR r1, r1, #1 << 31 ; Insert hidden one (even for denorms)
|
||
|
|
||
|
BCS _ffix_negative ; If negative input, separate case
|
||
|
|
||
|
MOV r3, #DExp_bias+1 ; r3 = 63 + DExp_bias
|
||
|
ADD r3, r3, #62 ; ..
|
||
|
SUBS r2, r3, r2, LSR #21 ; Determine shift amount
|
||
|
BLE shift_left ; Negative shift is a shift left, NaN,
|
||
|
; or INF
|
||
|
CMP r2, #64 ; See if shifting all bits out
|
||
|
BGE shift_right_64 ; If shifting all bits out, return zero
|
||
|
|
||
|
shift_right
|
||
|
MOV r12, #0 ; Need to clear r12 for inexact check
|
||
|
CMP r2, #32 ; See if shift amount >= 32
|
||
|
BLT shift_right_31 ; If not, shift right 31 or less
|
||
|
MOV r12, r0 ; If >= 32, save lost bits in temp reg,
|
||
|
MOV r0, r1 ; shift by moving words, and
|
||
|
MOV r1, #0 ; adjust the shift amount
|
||
|
SUB r2, r2, #32 ; ..
|
||
|
|
||
|
shift_right_31
|
||
|
RSB r3, r2, #32 ; Check for inexact
|
||
|
ORRS r12, r12, r0, LSL r3 ; ..
|
||
|
MOV r0, r0, LSR r2 ; Shift the result
|
||
|
ORR r0, r0, r1, LSL r3 ; ..
|
||
|
MOV r1, r1, LSR r2 ; ..
|
||
|
MOVNE r3, #INX_bit ; Set inexact if inexact
|
||
|
MOVEQ r3, #0 ; Otherwise set to no exceptions
|
||
|
B __dtoi64_return ; Return
|
||
|
|
||
|
shift_left
|
||
|
RSB r2, r2, #0 ; Get left shift amount
|
||
|
CMP r2, #32 ; If >= 32, shift by moving words, and
|
||
|
MOVGE r1, r0 ; adjusting shift amount
|
||
|
MOVGE r0, #0 ; ..
|
||
|
SUBGE r2, r2, #32 ; ..
|
||
|
MOV r1, r1, LSL r2 ; Perform rest of shift
|
||
|
RSB r3, r2, #32 ; ..
|
||
|
ORR r1, r1, r0, LSR r3 ; ..
|
||
|
MOV r0, r0, LSL r2 ; ..
|
||
|
MOV r3, #IVO_bit ; Overflow so set invalid operation
|
||
|
B __dtoi64_return ; Return
|
||
|
|
||
|
shift_right_64 ; 0.0 < abs(Arg) < 1.0, so losing all bits
|
||
|
MOV r3, #INX_bit ; Set inexact
|
||
|
MOV r0, #0 ; Return zero
|
||
|
MOV r1, #0 ; ..
|
||
|
B __dtoi64_return ; Return
|
||
|
|
||
|
_ffix_negative
|
||
|
MOV r3, #DExp_bias+1 ; r3 = 63 + DExp_bias
|
||
|
ADD r3, r3, #62 ; ..
|
||
|
SUBS r2, r3, r2, LSR #21 ; Determine shift amount
|
||
|
BLT shift_left_neg ; Negative shift is a shift left, NaN,
|
||
|
; or INF
|
||
|
BEQ special_int64_min ; Special case of 0x8000000000000000
|
||
|
CMP r2, #64 ; See if shifting all bits out
|
||
|
BGE shift_right_64 ; If shifting all bits out, return zero
|
||
|
|
||
|
shift_right_neg
|
||
|
MOV r12, #0 ; Need to clear r12 for inexact check
|
||
|
CMP r2, #32 ; See if shift amount >= 32
|
||
|
BLT shift_right_31_neg ; If not, shift right 31 or less
|
||
|
MOV r12, r0 ; If >= 32, save lost bits in temp reg,
|
||
|
MOV r0, r1 ; shift by moving words, and
|
||
|
MOV r1, #0 ; adjust the shift amount
|
||
|
SUB r2, r2, #32 ; ..
|
||
|
|
||
|
shift_right_31_neg
|
||
|
RSB r3, r2, #32 ; Check for inexact
|
||
|
ORRS r12, r12, r0, LSL r3 ; ..
|
||
|
MOV r0, r0, LSR r2 ; Shift the result
|
||
|
ORR r0, r0, r1, LSL r3 ; ..
|
||
|
MOV r1, r1, LSR r2 ; ..
|
||
|
MOVNE r3, #INX_bit ; Set inexact if inexact
|
||
|
MOVEQ r3, #0 ; Otherwise set to no exceptions
|
||
|
RSBS r0, r0, #0 ; Negate result
|
||
|
RSC r1, r1, #0 ; ..
|
||
|
B __dtoi64_return ; Return
|
||
|
|
||
|
|
||
|
shift_left_neg
|
||
|
RSB r2, r2, #0 ; Get left shift amount
|
||
|
CMP r2, #32 ; If >= 32, shift by moving words, and
|
||
|
MOVGE r1, r0 ; adjusting shift amount
|
||
|
MOVGE r0, #0 ; ..
|
||
|
SUBGE r2, r2, #32 ; ..
|
||
|
MOV r1, r1, LSL r2 ; Perform rest of shift
|
||
|
RSB r3, r2, #32 ; ..
|
||
|
ORR r1, r1, r0, LSR r3 ; ..
|
||
|
MOV r0, r0, LSL r2 ; ..
|
||
|
RSBS r0, r0, #0 ; Negate result
|
||
|
RSC r1, r1, #0 ; ..
|
||
|
MOV r3, #IVO_bit ; Overflow so set invalid operation
|
||
|
B __dtoi64_return ; Return
|
||
|
|
||
|
|
||
|
special_int64_min
|
||
|
TEQ r1, #0x80000000 ; If shift amount zero and result is
|
||
|
TEQEQ r0, #0 ; 0x8000000000000000, just leave it
|
||
|
MOVEQ r3, #0 ; ..
|
||
|
MOVNE r3, #IVO_bit ; Otherwise it's invalid (overflow)
|
||
|
RSBS r0, r0, #0 ; Negate result
|
||
|
RSC r1, r1, #0 ; ..
|
||
|
|
||
|
__dtoi64_return
|
||
|
TST r3, #FPECause_mask ; Any exceptions?
|
||
|
ADDEQ sp, sp, #LOC_SIZE ; If not, pop off saved arg and
|
||
|
IF Interworking :LOR: Thumbing
|
||
|
LDMEQFD sp!, {lr} ; return
|
||
|
BXEQ lr
|
||
|
ELSE
|
||
|
LDMEQFD sp!, {pc} ; return
|
||
|
ENDIF
|
||
|
ORR r12, r3, #_FpDToI64 ; Save exception info
|
||
|
LDR r3, [sp, #OrgOp1h] ; Load original arg
|
||
|
LDR r2, [sp, #OrgOp1l] ; ..
|
||
|
STR r0, [sp, #ExDResl] ; Store default result
|
||
|
STR r1, [sp, #ExDResh] ; ..
|
||
|
MOV r1, r12 ; Exception information
|
||
|
ADD r0, sp, #NewResl ; Pointer to new result
|
||
|
|
||
|
CALL FPE_Raise ; Handle exception information
|
||
|
|
||
|
IF Thumbing :LAND: :LNOT: Interworking
|
||
|
CODE16
|
||
|
bx pc ; switch back to ARM mode
|
||
|
nop
|
||
|
CODE32
|
||
|
ENDIF
|
||
|
|
||
|
LDR r0, [sp, #NewResl] ; Load new result
|
||
|
LDR r1, [sp, #NewResh] ; ..
|
||
|
ADD sp, sp, #LOC_SIZE ; Pop off exception record and result
|
||
|
IF Interworking :LOR: Thumbing
|
||
|
LDMFD sp!, {lr} ; Return
|
||
|
BX lr
|
||
|
ELSE
|
||
|
LDMFD sp!, {pc} ; Return
|
||
|
ENDIF
|
||
|
|
||
|
ENTRY_END __dtoi64
|
||
|
|
||
|
END
|