;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; Microsoft Research Singularity ;;; ;;; Copyright (c) Microsoft Corporation. All rights reserved. ;;; ;;; This file contains ARM-specific assembly code. ;;; ; __stou64 single precision floating point to unsigned 64-bit integer convert ; ; Input: r0 - float to be converted ; Output: r1 - most significant word of converted float in ; unsigned 64-bit integer format ; r0 - least significant word of converted float in ; unsigned 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 __stou64 IMPORT FPE_Raise NESTED_ENTRY __stou64 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 BLT 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 __stou64_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 __stou64_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 __stou64_return ; Return _ffix_negative AND r2, r2, #0xFF ; Mask off exponent field RSBS r2, r2, #63 + SExp_bias ; Determine shift amount BLE shift_left_neg ; 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_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 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 ; .. RSBS r0, r0, #0 ; Negate result RSC r1, r1, #0 ; .. MOV r3, #IVO_bit ; Set invalid B __stou64_return ; Return shift_left_neg MOV r3, #IVO_bit ; Set invalid RSB r2, r2, #0 ; Get positive left shift amount MOV r1, r1, LSL r2 ; Shift result RSBS r0, r0, #0 ; Negate result RSC r1, r1, #0 ; .. B __stou64_return ; Return __stou64_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, #_FpSToU64 ; 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 __stou64 END