1 /* 2 * COPYRIGHT: BSD - See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS CRT library 4 * FILE: lib/sdk/crt/math/arm/__rt_div_worker.h 5 * PURPOSE: Implementation of __rt_udiv 6 * PROGRAMMER: Timo Kreuzer 7 * REFERENCE: http://research.microsoft.com/pubs/70645/tr-2008-141.pdf 8 * http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/arm/_div10.s.htm 9 * http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/arm/_udiv.c.htm 10 */ 11 12 #ifdef _USE_64_BITS_ 13 typedef unsigned long long UINT3264; 14 typedef long long INT3264; 15 #define _CountLeadingZeros _CountLeadingZeros64 16 #else 17 typedef unsigned int UINT3264; 18 typedef int INT3264; 19 #endif 20 21 __forceinline 22 void 23 __brkdiv0(void) 24 { 25 __emit(0xDEF9); 26 } 27 28 typedef struct _ARM_DIVRESULT 29 { 30 UINT3264 quotient; /* to be returned in R0 */ 31 UINT3264 modulus; /* to be returned in R1 */ 32 } ARM_DIVRESULT; 33 34 #ifndef _USE_64_BITS_ 35 __forceinline 36 #endif 37 void 38 __rt_div_worker( 39 ARM_DIVRESULT *result, 40 UINT3264 divisor, 41 UINT3264 dividend) 42 { 43 UINT3264 shift; 44 UINT3264 mask; 45 UINT3264 quotient; 46 #ifdef _SIGNED_DIV_ 47 int dividend_sign; 48 int divisor_sign; 49 #endif // _SIGNED_DIV_ 50 51 if (divisor == 0) 52 { 53 /* Raise divide by zero error */ 54 __brkdiv0(); 55 } 56 57 #ifdef _SIGNED_DIV_ 58 if ((INT3264)dividend < 0) 59 { 60 dividend_sign = 1; 61 dividend = -(INT3264)dividend; 62 } 63 64 if ((INT3264)divisor < 0) 65 { 66 divisor_sign = 1; 67 divisor = -(INT3264)divisor; 68 } 69 #endif // _SIGNED_DIV_ 70 71 if (divisor > dividend) 72 { 73 result->quotient = 0; 74 result->modulus = divisor; 75 return; 76 } 77 78 /* Get the difference in count of leading zeros between dividend and divisor */ 79 shift = _CountLeadingZeros(divisor); 80 shift -= _CountLeadingZeros(dividend); 81 82 /* Shift the divisor to the left, so that it's highest bit is the same 83 as the highest bit of the dividend */ 84 divisor <<= shift; 85 86 mask = (UINT3264)1 << shift; 87 88 quotient = 0; 89 do 90 { 91 if (dividend >= divisor) 92 { 93 quotient |= mask; 94 dividend -= divisor; 95 } 96 divisor >>= 1; 97 mask >>= 1; 98 } 99 while (mask); 100 101 #ifdef _SIGNED_DIV_ 102 if (dividend_sign ^ divisor_sign) 103 { 104 quotient = -(INT3264)quotient; 105 } 106 107 if (dividend_sign) 108 { 109 dividend = -(INT3264)dividend; 110 } 111 #endif // _SIGNED_DIV_ 112 113 result->quotient = quotient; 114 result->modulus = dividend; 115 return; 116 } 117