singrdk/base/Kernel/Native/arm/Crt/r_stoi64.asm

173 lines
6.8 KiB
NASM
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;
;;; Microsoft Research Singularity
;;;
;;; Copyright (c) Microsoft Corporation. All rights reserved.
;;;
;;; This file contains ARM-specific assembly code.
;;;
; __stoi64 single precision floating point to signed 64-bit integer convert
;
; Input: r0 - float to be converted
; Output: r1 - most significant word of converted float in
; 64-bit integer format
; r0 - least significant word of converted float in
; 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 __stoi64
IMPORT FPE_Raise
NESTED_ENTRY __stoi64
EnterWithLR_16
STMFD sp!, {lr} ; Save return address
SUB sp, sp, #LOC_SIZE ; Allocate local storage
PROLOG_END
MOVS r12, r0 ; Save original arg in case of exception
MOVS r2, r0, ASR #SFrc_len ; Right justify exponent, save sign bit
MOV r0, r0, LSL #SExp_len ; Left justify mantissa and
ORR r1, r0, #1 << 31 ; insert hidden one (even for denorms)
MOV r0, #0 ; clear low 32 bits of result
BMI _ffix_negative ; If negative input, separate case
RSBS r2, r2, #63 + SExp_bias ; Determine shift amount
BLE shift_left ; Negative shift is a shift left,
; NaN or INF; all are invalid op
CMP r2, #64 ; See if shifting all bits out
BGE shift_right_64 ; If shifting all bits out, return zero
shift_right
; r2 contains the right shift amount. It is on the range of 1..63.
CMP r2, #32 ; Check if we are shifting >= 32
SUBGE r2, r2, #32 ; If so, do a 32 bit shift by moving
MOVGE r0, r1 ; words and adjusting the shift
MOVGE r1, #0 ; amount
RSB r2, r2, #32 ; 32 - right shift amount
MOVS r3, r0, LSL r2 ; Check for inexact
RSB r3, r2, #32 ; Right shift amount
MOV r0, r0, LSR r3 ; Shift the result
ORR r0, r0, r1, LSL r2 ; ..
MOV r1, r1, LSR r3 ; ..
MOVNE r3, #INX_bit ; If inexact, set inexact
MOVEQ r3, #0 ; Otherwise set no exceptions
B __stoi64_return ; Return
shift_left
RSB r2, r2, #0 ; Get positive left shift amount
MOV r3, #IVO_bit ; Set invalid
MOV r1, r1, LSL r2 ; Shift result
B __stoi64_return ; Return
shift_right_64 ; abs(Arg) < 1.0, so losing all bits
MOV r0, #0 ; Return zero
MOV r1, #0 ; Return zero
MOVS r2, r12, LSL #1 ; Check for inexact
MOVNE r3, #INX_bit ; If bits being lost, set inexact
MOVEQ r3, #0
B __stoi64_return ; Return
_ffix_negative
AND r2, r2, #0xFF ; Mask off exponent field
RSBS r2, r2, #63 + SExp_bias ; Determine shift amount
BLT shift_left_neg ; Negative shift is a shift left, NaN
; or INF
BEQ special_min_int64 ; INT_MIN special case
CMP r2, #64 ; See if shifting all bits out
BGE shift_right_64 ; If shifting all bits out, return zero
shift_right_neg
; r2 contains the right shift amount. It is on the range of 1..63.
CMP r2, #32 ; Check if we are shifting >= 32
SUBGE r2, r2, #32 ; If so, do a 32 bit shift by moving
MOVGE r0, r1 ; words and adjusting the shift
MOVGE r1, #0 ; amount
RSB r2, r2, #32 ; 32 - right shift amount
MOVS r3, r0, LSL r2 ; Check for inexact
RSB r3, r2, #32 ; Right shift amount
MOV r0, r0, LSR r3 ; Shift the result
ORR r0, r0, r1, LSL r2 ; ..
MOV r1, r1, LSR r3 ; ..
MOVNE r3, #INX_bit ; If inexact, set inexact
MOVEQ r3, #0 ; Otherwise set no exceptions
RSBS r0, r0, #0 ; Negate result
RSC r1, r1, #0 ; ..
B __stoi64_return ; Return
shift_left_neg
RSB r2, r2, #0 ; Get positive left shift amount
MOV r3, #IVO_bit ; Set invalid
MOV r1, r1, LSL r2 ; Shift result
RSBS r0, r0, #0 ; Negate result
RSC r1, r1, #0 ; ..
B __stoi64_return ; Return
special_min_int64
TEQ r1, #0x80000000 ; Special case of INT64_MIN
MOVNE r3, #IVO_bit ; Set invalid if not special case
MOVEQ r3, #0
RSBS r0, r0, #0 ; Negate result
RSC r1, r1, #0 ; ..
__stoi64_return
TST r3, #FPECause_mask ; Any exceptions?
ADDEQ sp, sp, #LOC_SIZE ; If not, restore stack
IF Interworking :LOR: Thumbing
LDMEQFD sp!, {lr} ; and return
BXEQ lr
ELSE
LDMEQFD sp!, {pc} ; and return
ENDIF
STR r0, [sp, #ExDResl] ; Store default result
STR r1, [sp, #ExDResh] ; ..
ADD r0, sp, #NewResl ; Pointer to new result
ORR r1, r3, #_FpSToI64 ; Exception information
MOV r2, r12 ; Original arg
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
IF Interworking :LOR: Thumbing
LDMFD sp!, {lr} ; Return
BX lr
ELSE
LDMFD sp!, {pc} ; Return
ENDIF
ENTRY_END __stoi64
END