1 1.1 jakllsch /* $NetBSD: math.c,v 1.1.1.2 2018/08/16 18:17:47 jmcneill Exp $ */ 2 1.1 jakllsch 3 1.1 jakllsch /*++ 4 1.1 jakllsch 5 1.1 jakllsch Copyright (c) 1998 Intel Corporation 6 1.1 jakllsch 7 1.1 jakllsch Module Name: 8 1.1 jakllsch 9 1.1 jakllsch math.c 10 1.1 jakllsch 11 1.1 jakllsch Abstract: 12 1.1 jakllsch 13 1.1 jakllsch 14 1.1 jakllsch 15 1.1 jakllsch 16 1.1 jakllsch Revision History 17 1.1 jakllsch 18 1.1 jakllsch --*/ 19 1.1 jakllsch 20 1.1 jakllsch #include "lib.h" 21 1.1 jakllsch 22 1.1 jakllsch 23 1.1 jakllsch // 24 1.1 jakllsch // Declare runtime functions 25 1.1 jakllsch // 26 1.1 jakllsch 27 1.1 jakllsch #ifdef RUNTIME_CODE 28 1.1 jakllsch #ifndef __GNUC__ 29 1.1 jakllsch #pragma RUNTIME_CODE(LShiftU64) 30 1.1 jakllsch #pragma RUNTIME_CODE(RShiftU64) 31 1.1 jakllsch #pragma RUNTIME_CODE(MultU64x32) 32 1.1 jakllsch #pragma RUNTIME_CODE(DivU64x32) 33 1.1 jakllsch #endif 34 1.1 jakllsch #endif 35 1.1 jakllsch 36 1.1 jakllsch // 37 1.1 jakllsch // 38 1.1 jakllsch // 39 1.1 jakllsch 40 1.1 jakllsch UINT64 41 1.1 jakllsch LShiftU64 ( 42 1.1 jakllsch IN UINT64 Operand, 43 1.1 jakllsch IN UINTN Count 44 1.1 jakllsch ) 45 1.1 jakllsch // Left shift 64bit by 32bit and get a 64bit result 46 1.1 jakllsch { 47 1.1 jakllsch #ifdef __GNUC__ 48 1.1 jakllsch return Operand << Count; 49 1.1 jakllsch #else 50 1.1 jakllsch UINT64 Result; 51 1.1 jakllsch _asm { 52 1.1 jakllsch mov eax, dword ptr Operand[0] 53 1.1 jakllsch mov edx, dword ptr Operand[4] 54 1.1 jakllsch mov ecx, Count 55 1.1 jakllsch and ecx, 63 56 1.1 jakllsch 57 1.1 jakllsch shld edx, eax, cl 58 1.1 jakllsch shl eax, cl 59 1.1 jakllsch 60 1.1 jakllsch cmp ecx, 32 61 1.1 jakllsch jc short ls10 62 1.1 jakllsch 63 1.1 jakllsch mov edx, eax 64 1.1 jakllsch xor eax, eax 65 1.1 jakllsch 66 1.1 jakllsch ls10: 67 1.1 jakllsch mov dword ptr Result[0], eax 68 1.1 jakllsch mov dword ptr Result[4], edx 69 1.1 jakllsch } 70 1.1 jakllsch 71 1.1 jakllsch return Result; 72 1.1 jakllsch #endif 73 1.1 jakllsch } 74 1.1 jakllsch 75 1.1 jakllsch UINT64 76 1.1 jakllsch RShiftU64 ( 77 1.1 jakllsch IN UINT64 Operand, 78 1.1 jakllsch IN UINTN Count 79 1.1 jakllsch ) 80 1.1 jakllsch // Right shift 64bit by 32bit and get a 64bit result 81 1.1 jakllsch { 82 1.1 jakllsch #ifdef __GNUC__ 83 1.1 jakllsch return Operand >> Count; 84 1.1 jakllsch #else 85 1.1 jakllsch UINT64 Result; 86 1.1 jakllsch _asm { 87 1.1 jakllsch mov eax, dword ptr Operand[0] 88 1.1 jakllsch mov edx, dword ptr Operand[4] 89 1.1 jakllsch mov ecx, Count 90 1.1 jakllsch and ecx, 63 91 1.1 jakllsch 92 1.1 jakllsch shrd eax, edx, cl 93 1.1 jakllsch shr edx, cl 94 1.1 jakllsch 95 1.1 jakllsch cmp ecx, 32 96 1.1 jakllsch jc short rs10 97 1.1 jakllsch 98 1.1 jakllsch mov eax, edx 99 1.1 jakllsch xor edx, edx 100 1.1 jakllsch 101 1.1 jakllsch rs10: 102 1.1 jakllsch mov dword ptr Result[0], eax 103 1.1 jakllsch mov dword ptr Result[4], edx 104 1.1 jakllsch } 105 1.1 jakllsch 106 1.1 jakllsch return Result; 107 1.1 jakllsch #endif 108 1.1 jakllsch } 109 1.1 jakllsch 110 1.1 jakllsch 111 1.1 jakllsch UINT64 112 1.1 jakllsch MultU64x32 ( 113 1.1 jakllsch IN UINT64 Multiplicand, 114 1.1 jakllsch IN UINTN Multiplier 115 1.1 jakllsch ) 116 1.1 jakllsch // Multiple 64bit by 32bit and get a 64bit result 117 1.1 jakllsch { 118 1.1 jakllsch #ifdef __GNUC__ 119 1.1 jakllsch return Multiplicand * Multiplier; 120 1.1 jakllsch #else 121 1.1 jakllsch UINT64 Result; 122 1.1 jakllsch _asm { 123 1.1 jakllsch mov eax, dword ptr Multiplicand[0] 124 1.1 jakllsch mul Multiplier 125 1.1 jakllsch mov dword ptr Result[0], eax 126 1.1 jakllsch mov dword ptr Result[4], edx 127 1.1 jakllsch mov eax, dword ptr Multiplicand[4] 128 1.1 jakllsch mul Multiplier 129 1.1 jakllsch add dword ptr Result[4], eax 130 1.1 jakllsch } 131 1.1 jakllsch 132 1.1 jakllsch return Result; 133 1.1 jakllsch #endif 134 1.1 jakllsch } 135 1.1 jakllsch 136 1.1 jakllsch UINT64 137 1.1 jakllsch DivU64x32 ( 138 1.1 jakllsch IN UINT64 Dividend, 139 1.1 jakllsch IN UINTN Divisor, 140 1.1 jakllsch OUT UINTN *Remainder OPTIONAL 141 1.1 jakllsch ) 142 1.1 jakllsch // divide 64bit by 32bit and get a 64bit result 143 1.1 jakllsch // N.B. only works for 31bit divisors!! 144 1.1 jakllsch { 145 1.1.1.2 jmcneill #if 0 && defined(__GNUC__) && !defined(__MINGW32__) 146 1.1 jakllsch if (Remainder) 147 1.1.1.2 jmcneill *Remainder = Dividend % Divisor; 148 1.1 jakllsch return Dividend / Divisor; 149 1.1 jakllsch #else 150 1.1 jakllsch UINT32 Rem; 151 1.1.1.2 jmcneill UINT32 bit; 152 1.1 jakllsch 153 1.1 jakllsch ASSERT (Divisor != 0); 154 1.1 jakllsch ASSERT ((Divisor >> 31) == 0); 155 1.1 jakllsch 156 1.1 jakllsch // 157 1.1 jakllsch // For each bit in the dividend 158 1.1 jakllsch // 159 1.1 jakllsch 160 1.1 jakllsch Rem = 0; 161 1.1 jakllsch for (bit=0; bit < 64; bit++) { 162 1.1.1.2 jmcneill #if defined(__GNUC__) || defined(__MINGW32__) 163 1.1.1.2 jmcneill asm ( 164 1.1.1.2 jmcneill "shll $1, %0\n\t" 165 1.1.1.2 jmcneill "rcll $1, 4%0\n\t" 166 1.1.1.2 jmcneill "rcll $1, %2\n\t" 167 1.1.1.2 jmcneill "mov %2, %%eax\n\t" 168 1.1.1.2 jmcneill "cmp %1, %%eax\n\t" 169 1.1.1.2 jmcneill "cmc\n\t" 170 1.1.1.2 jmcneill "sbb %%eax, %%eax\n\t" 171 1.1.1.2 jmcneill "sub %%eax, %0\n\t" 172 1.1.1.2 jmcneill "and %1, %%eax\n\t" 173 1.1.1.2 jmcneill "sub %%eax, %2" 174 1.1.1.2 jmcneill : /* no outputs */ 175 1.1.1.2 jmcneill : "m"(Dividend), "m"(Divisor), "m"(Rem) 176 1.1.1.2 jmcneill : "cc","memory","%eax" 177 1.1.1.2 jmcneill ); 178 1.1.1.2 jmcneill #else 179 1.1 jakllsch _asm { 180 1.1 jakllsch shl dword ptr Dividend[0], 1 ; shift rem:dividend left one 181 1.1.1.2 jmcneill rcl dword ptr Dividend[4], 1 182 1.1.1.2 jmcneill rcl dword ptr Rem, 1 183 1.1 jakllsch 184 1.1 jakllsch mov eax, Rem 185 1.1 jakllsch cmp eax, Divisor ; Is Rem >= Divisor? 186 1.1 jakllsch cmc ; No - do nothing 187 1.1.1.2 jmcneill sbb eax, eax ; Else, 188 1.1 jakllsch sub dword ptr Dividend[0], eax ; set low bit in dividen 189 1.1 jakllsch and eax, Divisor ; and 190 1.1.1.2 jmcneill sub Rem, eax ; subtract divisor 191 1.1 jakllsch } 192 1.1.1.2 jmcneill #endif 193 1.1 jakllsch } 194 1.1 jakllsch 195 1.1 jakllsch if (Remainder) { 196 1.1 jakllsch *Remainder = Rem; 197 1.1 jakllsch } 198 1.1 jakllsch 199 1.1 jakllsch return Dividend; 200 1.1 jakllsch #endif 201 1.1 jakllsch } 202