Mercurial > projects > ldc
comparison druntime/src/compiler/dmd/llmath.d @ 759:d3eb054172f9
Added copy of druntime from DMD 2.020 modified for LDC.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:52:37 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
758:f04dde6e882c | 759:d3eb054172f9 |
---|---|
1 // llmath.d | |
2 // Copyright (C) 1993-2003 by Digital Mars, www.digitalmars.com | |
3 // All Rights Reserved | |
4 // Written by Walter Bright | |
5 | |
6 module rt.llmath; | |
7 | |
8 // Compiler runtime support for 64 bit longs | |
9 | |
10 extern (C): | |
11 | |
12 | |
13 /*************************************** | |
14 * Unsigned long divide. | |
15 * Input: | |
16 * [EDX,EAX],[ECX,EBX] | |
17 * Output: | |
18 * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] | |
19 * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] | |
20 * ESI,EDI destroyed | |
21 */ | |
22 | |
23 void __ULDIV__() | |
24 { | |
25 asm | |
26 { | |
27 naked ; | |
28 test ECX,ECX ; | |
29 jz uldiv ; | |
30 | |
31 push EBP ; | |
32 | |
33 // left justify [ECX,EBX] and leave count of shifts + 1 in EBP | |
34 | |
35 mov EBP,1 ; // at least 1 shift | |
36 test ECX,ECX ; // left justified? | |
37 js L1 ; // yes | |
38 jnz L2 ; | |
39 add EBP,8 ; | |
40 mov CH,CL ; | |
41 mov CL,BH ; | |
42 mov BH,BL ; | |
43 xor BL,BL ; // [ECX,EBX] <<= 8 | |
44 test ECX,ECX ; | |
45 js L1 ; | |
46 even ; | |
47 L2: inc EBP ; // another shift | |
48 shl EBX,1 ; | |
49 rcl ECX,1 ; // [ECX,EBX] <<= 1 | |
50 jno L2 ; // not left justified yet | |
51 | |
52 L1: mov ESI,ECX ; | |
53 mov EDI,EBX ; // [ESI,EDI] = divisor | |
54 | |
55 mov ECX,EDX ; | |
56 mov EBX,EAX ; // [ECX,EBX] = [EDX,EAX] | |
57 xor EAX,EAX ; | |
58 cdq ; // [EDX,EAX] = 0 | |
59 even ; | |
60 L4: cmp ESI,ECX ; // is [ECX,EBX] > [ESI,EDI]? | |
61 ja L3 ; // yes | |
62 jb L5 ; // definitely less than | |
63 cmp EDI,EBX ; // check low order word | |
64 ja L3 ; | |
65 L5: sub EBX,EDI ; | |
66 sbb ECX,ESI ; // [ECX,EBX] -= [ESI,EDI] | |
67 stc ; // rotate in a 1 | |
68 L3: rcl EAX,1 ; | |
69 rcl EDX,1 ; // [EDX,EAX] = ([EDX,EAX] << 1) + C | |
70 shr ESI,1 ; | |
71 rcr EDI,1 ; // [ESI,EDI] >>= 1 | |
72 dec EBP ; // control count | |
73 jne L4 ; | |
74 pop EBP ; | |
75 ret ; | |
76 | |
77 div0: mov EAX,-1 ; | |
78 cwd ; // quotient is -1 | |
79 // xor ECX,ECX ; | |
80 // mov EBX,ECX ; // remainder is 0 (ECX and EBX already 0) | |
81 pop EBP ; | |
82 ret ; | |
83 | |
84 uldiv: test EDX,EDX ; | |
85 jnz D3 ; | |
86 // Both high words are 0, we can use the DIV instruction | |
87 div EBX ; | |
88 mov EBX,EDX ; | |
89 mov EDX,ECX ; // EDX = ECX = 0 | |
90 ret ; | |
91 | |
92 even ; | |
93 D3: // Divide [EDX,EAX] by EBX | |
94 mov ECX,EAX ; | |
95 mov EAX,EDX ; | |
96 xor EDX,EDX ; | |
97 div EBX ; | |
98 xchg ECX,EAX ; | |
99 div EBX ; | |
100 // ECX,EAX = result | |
101 // EDX = remainder | |
102 mov EBX,EDX ; | |
103 mov EDX,ECX ; | |
104 xor ECX,ECX ; | |
105 ret ; | |
106 } | |
107 } | |
108 | |
109 | |
110 /*************************************** | |
111 * Signed long divide. | |
112 * Input: | |
113 * [EDX,EAX],[ECX,EBX] | |
114 * Output: | |
115 * [EDX,EAX] = [EDX,EAX] / [ECX,EBX] | |
116 * [ECX,EBX] = [EDX,EAX] % [ECX,EBX] | |
117 * ESI,EDI destroyed | |
118 */ | |
119 | |
120 void __LDIV__() | |
121 { | |
122 asm | |
123 { | |
124 naked ; | |
125 test EDX,EDX ; // [EDX,EAX] negative? | |
126 jns L10 ; // no | |
127 //neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX] | |
128 neg EDX ; | |
129 neg EAX ; | |
130 sbb EDX,0 ; | |
131 test ECX,ECX ; // [ECX,EBX] negative? | |
132 jns L11 ; // no | |
133 //neg64 ECX,EBX ; | |
134 neg ECX ; | |
135 neg EBX ; | |
136 sbb ECX,0 ; | |
137 call __ULDIV__ ; | |
138 //neg64 ECX,EBX ; // remainder same sign as dividend | |
139 neg ECX ; | |
140 neg EBX ; | |
141 sbb ECX,0 ; | |
142 ret ; | |
143 | |
144 L11: call __ULDIV__ ; | |
145 //neg64 ECX,EBX ; // remainder same sign as dividend | |
146 neg ECX ; | |
147 neg EBX ; | |
148 sbb ECX,0 ; | |
149 //neg64 EDX,EAX ; // quotient is negative | |
150 neg EDX ; | |
151 neg EAX ; | |
152 sbb EDX,0 ; | |
153 ret ; | |
154 | |
155 L10: test ECX,ECX ; // [ECX,EBX] negative? | |
156 jns L12 ; // no (all is positive) | |
157 //neg64 ECX,EBX ; | |
158 neg ECX ; | |
159 neg EBX ; | |
160 sbb ECX,0 ; | |
161 call __ULDIV__ ; | |
162 //neg64 EDX,EAX ; // quotient is negative | |
163 neg EDX ; | |
164 neg EAX ; | |
165 sbb EDX,0 ; | |
166 ret ; | |
167 | |
168 L12: jmp __ULDIV__ ; | |
169 } | |
170 } | |
171 | |
172 | |
173 /*************************************** | |
174 * Compare [EDX,EAX] with [ECX,EBX] | |
175 * Signed | |
176 * Returns result in flags | |
177 */ | |
178 | |
179 void __LCMP__() | |
180 { | |
181 asm | |
182 { | |
183 naked ; | |
184 cmp EDX,ECX ; | |
185 jne C1 ; | |
186 push EDX ; | |
187 xor EDX,EDX ; | |
188 cmp EAX,EBX ; | |
189 jz C2 ; | |
190 ja C3 ; | |
191 dec EDX ; | |
192 pop EDX ; | |
193 ret ; | |
194 | |
195 C3: inc EDX ; | |
196 C2: pop EDX ; | |
197 C1: ret ; | |
198 } | |
199 } | |
200 | |
201 | |
202 | |
203 | |
204 // Convert ulong to real | |
205 | |
206 private real adjust = cast(real)0x800_0000_0000_0000 * 0x10; | |
207 | |
208 real __U64_LDBL() | |
209 { | |
210 asm | |
211 { naked ; | |
212 push EDX ; | |
213 push EAX ; | |
214 and dword ptr 4[ESP], 0x7FFFFFFF ; | |
215 fild qword ptr [ESP] ; | |
216 test EDX,EDX ; | |
217 jns L1 ; | |
218 fld real ptr adjust ; | |
219 faddp ST(1), ST ; | |
220 L1: ; | |
221 add ESP, 8 ; | |
222 ret ; | |
223 } | |
224 } | |
225 | |
226 // Same as __U64_LDBL, but return result as double in [EDX,EAX] | |
227 ulong __ULLNGDBL() | |
228 { | |
229 asm | |
230 { naked ; | |
231 call __U64_LDBL ; | |
232 sub ESP,8 ; | |
233 fstp double ptr [ESP] ; | |
234 pop EAX ; | |
235 pop EDX ; | |
236 ret ; | |
237 } | |
238 } | |
239 | |
240 // Convert double to ulong | |
241 | |
242 private short roundTo0 = 0xFBF; | |
243 | |
244 ulong __DBLULLNG() | |
245 { | |
246 // BUG: should handle NAN's and overflows | |
247 asm | |
248 { naked ; | |
249 push EDX ; | |
250 push EAX ; | |
251 fld double ptr [ESP] ; | |
252 sub ESP,8 ; | |
253 fld real ptr adjust ; | |
254 fcomp ; | |
255 fstsw AX ; | |
256 fstcw 8[ESP] ; | |
257 fldcw roundTo0 ; | |
258 sahf ; | |
259 jae L1 ; | |
260 fld real ptr adjust ; | |
261 fsubp ST(1), ST ; | |
262 fistp qword ptr [ESP] ; | |
263 pop EAX ; | |
264 pop EDX ; | |
265 fldcw [ESP] ; | |
266 add ESP,8 ; | |
267 add EDX,0x8000_0000 ; | |
268 ret ; | |
269 L1: ; | |
270 fistp qword ptr [ESP] ; | |
271 pop EAX ; | |
272 pop EDX ; | |
273 fldcw [ESP] ; | |
274 add ESP,8 ; | |
275 ret ; | |
276 } | |
277 } | |
278 | |
279 // Convert double in ST0 to uint | |
280 | |
281 uint __DBLULNG() | |
282 { | |
283 // BUG: should handle NAN's and overflows | |
284 asm | |
285 { naked ; | |
286 sub ESP,16 ; | |
287 fstcw 8[ESP] ; | |
288 fldcw roundTo0 ; | |
289 fistp qword ptr [ESP] ; | |
290 fldcw 8[ESP] ; | |
291 pop EAX ; | |
292 add ESP,12 ; | |
293 ret ; | |
294 } | |
295 } |