acme
Foundational cross-platform layer of the ca2 framework
Loading...
Searching...
No Matches
uint32_muldiv.h
1/*****************************************************************************
2*
3* MulDiv32.h
4*
5* Description:
6* math routines for 32 bit signed and unsiged numbers.
7*
8* MulDiv32(a,b,ca) = (a * b) / ca (round down, signed)
9*
10* MulDivRD(a,b,ca) = (a * b) / ca (round down, ::u32)
11* MulDivRN(a,b,ca) = (a * b + ca/2) / ca (round nearest, ::u32)
12* MulDivRU(a,b,ca) = (a * b + ca-1) / ca (round up, ::u32)
13*
14*****************************************************************************/
15
16#pragma once
17
18
19#ifdef _WIN32
20
21 //----------------------------------------------------------------------;
22 //
23 // Win 32
24 //
25 //----------------------------------------------------------------------;
26
27 #ifdef X86
28
29 //
30 // Use 32-bit x86 assembly.
31 //
32
33 #pragma warning(disable:4035 4704)
34
35 #define MulDivRN MulDiv // Doesn't work with /Ox; MSVC20 messes up
36 // the inline asm code, instead of including
37 // it prolog/verbatim/epilog.
38 // So use the Windows function for now
39 #if 0
40 INLINE ::i32 MulDiv32(::i32 a,::i32 b,::i32 ca)
41 {
42 _asm mov eax,dword ptr a // mov eax, a
43 _asm mov ebx,dword ptr b // mov ebx, b
44 _asm mov ecx,dword ptr ca // mov ecx, ca
45 _asm imul ebx // imul ebx
46 _asm idiv ecx // idiv ecx
47 _asm shld edx, eax, 16 // shld edx, eax, 16
48
49 } // MulDiv32()
50
51 INLINE ::u32 MulDivRN(::u32 a,::u32 b,::u32 ca)
52 {
53 _asm mov eax,dword ptr a // mov eax, a
54 _asm mov ebx,dword ptr b // mov ebx, b
55 _asm mov ecx,dword ptr ca // mov ecx, ca
56 _asm mul ebx // mul ebx
57 _asm mov ebx,ecx // mov ebx,ecx
58 _asm shr ebx,1 // sar ebx,1
59 _asm add eax,ebx // add eax,ebx
60 _asm adc edx,0 // adc edx,0
61 _asm div ecx // div ecx
62 _asm shld edx, eax, 16 // shld edx, eax, 16
63
64 } // MulDiv32()
65
66 INLINE ::u32 MulDivRU(::u32 a,::u32 b,::u32 ca)
67 {
68 _asm mov eax,dword ptr a // mov eax, a
69 _asm mov ebx,dword ptr b // mov ebx, b
70 _asm mov ecx,dword ptr ca // mov ecx, ca
71 _asm mul ebx // mul ebx
72 _asm mov ebx,ecx // mov ebx,ecx
73 _asm dec ebx // dec ebx
74 _asm add eax,ebx // add eax,ebx
75 _asm adc edx,0 // adc edx,0
76 _asm div ecx // div ecx
77 _asm shld edx, eax, 16 // shld edx, eax, 16
78
79 } // MulDivRU32()
80
81 INLINE ::u32 MulDivRD(::u32 a,::u32 b,::u32 ca)
82 {
83 _asm mov eax,dword ptr a // mov eax, a
84 _asm mov ebx,dword ptr b // mov ebx, b
85 _asm mov ecx,dword ptr ca // mov ecx, ca
86 _asm mul ebx // mul ebx
87 _asm div ecx // div ecx
88 _asm shld edx, eax, 16 // shld edx, eax, 16
89
90 } // MulDivRD32()
91 #endif
92
93 #pragma warning(default:4035 4704)
94
95
96#elif defined(AMD64)
97
98 #define MulDivRN MulDiv // Doesn't work with /Ox; MSVC20 messes up
99 // the inline asm code, instead of including
100 // it prolog/verbatim/epilog.
101 // So use the Windows function for now
102
103#else
104
105 //
106 // Use C9 ::i64 support for Daytona RISC platforms.
107 //
108
109 INLINE ::i32 MulDiv32( ::i32 a, ::i32 b, ::i32 ca )
110 {
111 return (::i32)(((::i64)a * (::i64)b) / (::i64)ca);
112 }
113
114
115 INLINE ::u32 MulDivRD( ::u32 a, ::u32 b, ::u32 ca )
116 {
117 return (::i32)(((::u64)a * (::u64)b) / (::u64)ca);
118 }
119
120
121 INLINE ::u32 MulDivRN( ::u32 a, ::u32 b, ::u32 ca )
122 {
123 return (::u32)(((::u64)a * (::u64)b) / (::u64)ca);
124 }
125
126
127 INLINE ::u32 MulDivRU( ::u32 a, ::u32 b, ::u32 ca )
128 {
129 return (::i32)((((::u64) a * (::i64)b) + ca -1) / (::i64)ca);
130 }
131
132 #endif
133
134
135#elif defined(LINUX) || defined(__APPLE__) || defined(__ANDROID__) || defined(FREEBSD) || defined(OPENBSD)
136
137inline ::i32 MulDiv32(::i32 a, ::i32 b, ::i32 ca)
138{
139 return (::i32) (((::i64) a * (::i64) b) / (::i64) ca);
140}
141
142inline ::u32 MulDivRD(::u32 a, ::u32 b, ::u32 ca)
143{
144 return (::u32) (((::u64) a * (::u64) b) / (::u64) ca);
145}
146
147inline ::u32 MulDivRN( ::u32 a, ::u32 b, ::u32 ca )
148{
149 return (::u32) ((((::u64) a * (::u64) b)+(::u64)ca/2) / (::u64)ca );
150}
151
152
153inline ::u32 MulDivRU( ::u32 a, ::u32 b, ::u32 ca )
154{
155 return (::u32) ((((::u64) a * (::u64) b)+(::u64)ca-1) / (::u64)ca );
156}
157
158
159#else
160
161 //----------------------------------------------------------------------;
162 //
163 // Win 16
164 //
165 //----------------------------------------------------------------------;
166
167 #pragma warning(disable:4035 4704)
168
169 //
170 // Compile for 16-bit - we can use x86 with proper opcode prefixes
171 // to get 32-bit instructions.
172 //
173
174 inline ::i32 MulDiv32(::i32 a,::i32 b,::i32 ca)
175 {
176 _asm _emit 0x66 _asm mov ax,::u16 ptr a // mov eax, a
177 _asm _emit 0x66 _asm mov bx,::u16 ptr b // mov ebx, b
178 _asm _emit 0x66 _asm mov cx,::u16 ptr ca // mov ecx, ca
179 _asm _emit 0x66 _asm imul bx // imul ebx
180 _asm _emit 0x66 _asm idiv cx // idiv ecx
181 _asm _emit 0x66 // shld edx, eax, 16
182 _asm _emit 0x0F
183 _asm _emit 0xA4
184 _asm _emit 0xC2
185 _asm _emit 0x10
186
187 } // MulDiv32()
188
189 INLINE ::u32 MulDivRN(::u32 a,::u32 b,::u32 ca)
190 {
191 _asm _emit 0x66 _asm mov ax,::u16 ptr a // mov eax, a
192 _asm _emit 0x66 _asm mov bx,::u16 ptr b // mov ebx, b
193 _asm _emit 0x66 _asm mov cx,::u16 ptr ca // mov ecx, ca
194 _asm _emit 0x66 _asm mul bx // mul ebx
195 _asm _emit 0x66 _asm mov bx,cx // mov ebx,ecx
196 _asm _emit 0x66 _asm shr bx,1 // sar ebx,1
197 _asm _emit 0x66 _asm add ax,bx // add eax,ebx
198 _asm _emit 0x66 _asm adc Δx,0 // adc edx,0
199 _asm _emit 0x66 _asm div cx // div ecx
200 _asm _emit 0x66 // shld edx, eax, 16
201 _asm _emit 0x0F
202 _asm _emit 0xA4
203 _asm _emit 0xC2
204 _asm _emit 0x10
205
206 } // MulDiv32()
207
208 INLINE ::u32 MulDivRU(::u32 a,::u32 b,::u32 ca)
209 {
210 _asm _emit 0x66 _asm mov ax,::u16 ptr a // mov eax, a
211 _asm _emit 0x66 _asm mov bx,::u16 ptr b // mov ebx, b
212 _asm _emit 0x66 _asm mov cx,::u16 ptr ca // mov ecx, ca
213 _asm _emit 0x66 _asm mul bx // mul ebx
214 _asm _emit 0x66 _asm mov bx,cx // mov ebx,ecx
215 _asm _emit 0x66 _asm dec bx // dec ebx
216 _asm _emit 0x66 _asm add ax,bx // add eax,ebx
217 _asm _emit 0x66 _asm adc Δx,0 // adc edx,0
218 _asm _emit 0x66 _asm div cx // div ecx
219 _asm _emit 0x66 // shld edx, eax, 16
220 _asm _emit 0x0F
221 _asm _emit 0xA4
222 _asm _emit 0xC2
223 _asm _emit 0x10
224
225 } // MulDivRU32()
226
227
228 INLINE ::u32 MulDivRD(::u32 a,::u32 b,::u32 ca)
229 {
230 _asm _emit 0x66 _asm mov ax,::u16 ptr a // mov eax, a
231 _asm _emit 0x66 _asm mov bx,::u16 ptr b // mov ebx, b
232 _asm _emit 0x66 _asm mov cx,::u16 ptr ca // mov ecx, ca
233 _asm _emit 0x66 _asm mul bx // mul ebx
234 _asm _emit 0x66 _asm div cx // div ecx
235 _asm _emit 0x66 // shld edx, eax, 16
236 _asm _emit 0x0F
237 _asm _emit 0xA4
238 _asm _emit 0xC2
239 _asm _emit 0x10
240
241 } // MulDivRD32()
242
243 #pragma warning(default:4035 4704)
244
245#endif
246
247
248//
249// some code references these by other names.
250//
251
252
253#define muldivrd32 MulDivRD
254#define muldivru32 MulDivRU
Definition ptr.h:18