xref: /reactos/sdk/lib/crt/math/arm/__rt_div_worker.h (revision c2c66aff)
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