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 }