xref: /reactos/sdk/lib/crt/math/i386/allrem_asm.s (revision 9393fc32)
1*c2c66affSColin Finck/*
2*c2c66affSColin Finck * COPYRIGHT:         See COPYING in the top level directory
3*c2c66affSColin Finck * PROJECT:           ReactOS kernel
4*c2c66affSColin Finck * PURPOSE:           Run-Time Library
5*c2c66affSColin Finck * FILE:              lib/sdk/crt/math/i386/allrem_asm.s
6*c2c66affSColin Finck * PROGRAMER:         Alex Ionescu (alex@relsoft.net)
7*c2c66affSColin Finck *
8*c2c66affSColin Finck * Copyright (C) 2002 Michael Ringgaard.
9*c2c66affSColin Finck * All rights reserved.
10*c2c66affSColin Finck *
11*c2c66affSColin Finck * Redistribution and use in source and binary forms, with or without
12*c2c66affSColin Finck * modification, are permitted provided that the following conditions
13*c2c66affSColin Finck * are met:
14*c2c66affSColin Finck *
15*c2c66affSColin Finck * 1. Redistributions of source code must retain the above copyright
16*c2c66affSColin Finck *    notice, this list of conditions and the following disclaimer.
17*c2c66affSColin Finck * 2. Redistributions in binary form must reproduce the above copyright
18*c2c66affSColin Finck *    notice, this list of conditions and the following disclaimer in the
19*c2c66affSColin Finck *    documentation and/or other materials provided with the distribution.
20*c2c66affSColin Finck * 3. Neither the name of the project nor the names of its contributors
21*c2c66affSColin Finck *    may be used to endorse or promote products derived from this software
22*c2c66affSColin Finck *    without specific prior written permission.
23*c2c66affSColin Finck
24*c2c66affSColin Finck * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25*c2c66affSColin Finck * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*c2c66affSColin Finck * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*c2c66affSColin Finck * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
28*c2c66affSColin Finck * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*c2c66affSColin Finck * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*c2c66affSColin Finck * OR SERVICES// LOSS OF USE, DATA, OR PROFITS// OR BUSINESS INTERRUPTION)
31*c2c66affSColin Finck * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*c2c66affSColin Finck * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*c2c66affSColin Finck * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*c2c66affSColin Finck * SUCH DAMAGE.
35*c2c66affSColin Finck */
36*c2c66affSColin Finck
37*c2c66affSColin Finck#include <asm.inc>
38*c2c66affSColin Finck
39*c2c66affSColin FinckPUBLIC __allrem
40*c2c66affSColin Finck
41*c2c66affSColin Finck/* FUNCTIONS ***************************************************************/
42*c2c66affSColin Finck.code
43*c2c66affSColin Finck
44*c2c66affSColin Finck//
45*c2c66affSColin Finck// llrem - signed long remainder
46*c2c66affSColin Finck//
47*c2c66affSColin Finck// Purpose:
48*c2c66affSColin Finck//       Does a signed long remainder of the arguments.  Arguments are
49*c2c66affSColin Finck//       not changed.
50*c2c66affSColin Finck//
51*c2c66affSColin Finck// Entry:
52*c2c66affSColin Finck//       Arguments are passed on the stack:
53*c2c66affSColin Finck//               1st pushed: divisor (QWORD)
54*c2c66affSColin Finck//               2nd pushed: dividend (QWORD)
55*c2c66affSColin Finck//
56*c2c66affSColin Finck// Exit:
57*c2c66affSColin Finck//       EDX:EAX contains the remainder (dividend%divisor)
58*c2c66affSColin Finck//       NOTE: this routine removes the parameters from the stack.
59*c2c66affSColin Finck//
60*c2c66affSColin Finck// Uses:
61*c2c66affSColin Finck//       ECX
62*c2c66affSColin Finck//
63*c2c66affSColin Finck
64*c2c66affSColin Finck__allrem :
65*c2c66affSColin Finck
66*c2c66affSColin Finck        push    ebx
67*c2c66affSColin Finck        push    edi
68*c2c66affSColin Finck
69*c2c66affSColin Finck// Set up the local stack and save the index registers.  When this is done
70*c2c66affSColin Finck// the stack frame will look as follows (assuming that the expression a%b will
71*c2c66affSColin Finck// generate a call to lrem(a, b)):
72*c2c66affSColin Finck//
73*c2c66affSColin Finck//               -----------------
74*c2c66affSColin Finck//               |               |
75*c2c66affSColin Finck//               |---------------|
76*c2c66affSColin Finck//               |               |
77*c2c66affSColin Finck//               |--divisor (b)--|
78*c2c66affSColin Finck//               |               |
79*c2c66affSColin Finck//               |---------------|
80*c2c66affSColin Finck//               |               |
81*c2c66affSColin Finck//               |--dividend (a)-|
82*c2c66affSColin Finck//               |               |
83*c2c66affSColin Finck//               |---------------|
84*c2c66affSColin Finck//               | return addr** |
85*c2c66affSColin Finck//               |---------------|
86*c2c66affSColin Finck//               |       EBX     |
87*c2c66affSColin Finck//               |---------------|
88*c2c66affSColin Finck//       ESP---->|       EDI     |
89*c2c66affSColin Finck//               -----------------
90*c2c66affSColin Finck//
91*c2c66affSColin Finck
92*c2c66affSColin Finck#undef DVNDLO
93*c2c66affSColin Finck#undef DVNDHI
94*c2c66affSColin Finck#undef DVSRLO
95*c2c66affSColin Finck#undef DVSRHI
96*c2c66affSColin Finck#define DVNDLO  [esp + 12]       // stack address of dividend (a)
97*c2c66affSColin Finck#define DVNDHI  [esp + 16]       // stack address of dividend (a)
98*c2c66affSColin Finck#define DVSRLO  [esp + 20]      // stack address of divisor (b)
99*c2c66affSColin Finck#define DVSRHI  [esp + 24]      // stack address of divisor (b)
100*c2c66affSColin Finck
101*c2c66affSColin Finck// Determine sign of the result (edi = 0 if result is positive, non-zero
102*c2c66affSColin Finck// otherwise) and make operands positive.
103*c2c66affSColin Finck
104*c2c66affSColin Finck        xor     edi,edi         // result sign assumed positive
105*c2c66affSColin Finck
106*c2c66affSColin Finck        mov     eax,DVNDHI // hi word of a
107*c2c66affSColin Finck        or      eax,eax         // test to see if signed
108*c2c66affSColin Finck        jge     short .L1        // skip rest if a is already positive
109*c2c66affSColin Finck        inc     edi             // complement result sign flag bit
110*c2c66affSColin Finck        mov     edx,DVNDLO // lo word of a
111*c2c66affSColin Finck        neg     eax             // make a positive
112*c2c66affSColin Finck        neg     edx
113*c2c66affSColin Finck        sbb     eax,0
114*c2c66affSColin Finck        mov     DVNDHI,eax // save positive value
115*c2c66affSColin Finck        mov     DVNDLO,edx
116*c2c66affSColin Finck.L1:
117*c2c66affSColin Finck        mov     eax,DVSRHI // hi word of b
118*c2c66affSColin Finck        or      eax,eax         // test to see if signed
119*c2c66affSColin Finck        jge     short .L2        // skip rest if b is already positive
120*c2c66affSColin Finck        mov     edx,DVSRLO // lo word of b
121*c2c66affSColin Finck        neg     eax             // make b positive
122*c2c66affSColin Finck        neg     edx
123*c2c66affSColin Finck        sbb     eax,0
124*c2c66affSColin Finck        mov     DVSRHI,eax // save positive value
125*c2c66affSColin Finck        mov     DVSRLO,edx
126*c2c66affSColin Finck.L2:
127*c2c66affSColin Finck
128*c2c66affSColin Finck//
129*c2c66affSColin Finck// Now do the divide.  First look to see if the divisor is less than 4194304K.
130*c2c66affSColin Finck// If so, then we can use a simple algorithm with word divides, otherwise
131*c2c66affSColin Finck// things get a little more complex.
132*c2c66affSColin Finck//
133*c2c66affSColin Finck// NOTE - eax currently contains the high order word of DVSR
134*c2c66affSColin Finck//
135*c2c66affSColin Finck
136*c2c66affSColin Finck        or      eax,eax         // check to see if divisor < 4194304K
137*c2c66affSColin Finck        jnz     short .L3        // nope, gotta do this the hard way
138*c2c66affSColin Finck        mov     ecx,DVSRLO // load divisor
139*c2c66affSColin Finck        mov     eax,DVNDHI // load high word of dividend
140*c2c66affSColin Finck        xor     edx,edx
141*c2c66affSColin Finck        div     ecx             // edx <- remainder
142*c2c66affSColin Finck        mov     eax,DVNDLO // edx:eax <- remainder:lo word of dividend
143*c2c66affSColin Finck        div     ecx             // edx <- final remainder
144*c2c66affSColin Finck        mov     eax,edx         // edx:eax <- remainder
145*c2c66affSColin Finck        xor     edx,edx
146*c2c66affSColin Finck        dec     edi             // check result sign flag
147*c2c66affSColin Finck        jns     short .L4        // negate result, restore stack and return
148*c2c66affSColin Finck        jmp     short .L8        // result sign ok, restore stack and return
149*c2c66affSColin Finck
150*c2c66affSColin Finck//
151*c2c66affSColin Finck// Here we do it the hard way.  Remember, eax contains the high word of DVSR
152*c2c66affSColin Finck//
153*c2c66affSColin Finck
154*c2c66affSColin Finck.L3:
155*c2c66affSColin Finck        mov     ebx,eax         // ebx:ecx <- divisor
156*c2c66affSColin Finck        mov     ecx,DVSRLO
157*c2c66affSColin Finck        mov     edx,DVNDHI // edx:eax <- dividend
158*c2c66affSColin Finck        mov     eax,DVNDLO
159*c2c66affSColin Finck.L5:
160*c2c66affSColin Finck        shr     ebx,1           // shift divisor right one bit
161*c2c66affSColin Finck        rcr     ecx,1
162*c2c66affSColin Finck        shr     edx,1           // shift dividend right one bit
163*c2c66affSColin Finck        rcr     eax,1
164*c2c66affSColin Finck        or      ebx,ebx
165*c2c66affSColin Finck        jnz     short .L5        // loop until divisor < 4194304K
166*c2c66affSColin Finck        div     ecx             // now divide, ignore remainder
167*c2c66affSColin Finck
168*c2c66affSColin Finck//
169*c2c66affSColin Finck// We may be off by one, so to check, we will multiply the quotient
170*c2c66affSColin Finck// by the divisor and check the result against the orignal dividend
171*c2c66affSColin Finck// Note that we must also check for overflow, which can occur if the
172*c2c66affSColin Finck// dividend is close to 2**64 and the quotient is off by 1.
173*c2c66affSColin Finck//
174*c2c66affSColin Finck
175*c2c66affSColin Finck        mov     ecx,eax         // save a copy of quotient in ECX
176*c2c66affSColin Finck        mul     dword ptr DVSRHI
177*c2c66affSColin Finck        xchg    ecx,eax         // save product, get quotient in EAX
178*c2c66affSColin Finck        mul     dword ptr DVSRLO
179*c2c66affSColin Finck        add     edx,ecx         // EDX:EAX = QUOT * DVSR
180*c2c66affSColin Finck        jc      short .L6        // carry means Quotient is off by 1
181*c2c66affSColin Finck
182*c2c66affSColin Finck//
183*c2c66affSColin Finck// do long compare here between original dividend and the result of the
184*c2c66affSColin Finck// multiply in edx:eax.  If original is larger or equal, we are ok, otherwise
185*c2c66affSColin Finck// subtract the original divisor from the result.
186*c2c66affSColin Finck//
187*c2c66affSColin Finck
188*c2c66affSColin Finck        cmp     edx,DVNDHI // compare hi words of result and original
189*c2c66affSColin Finck        ja      short .L6        // if result > original, do subtract
190*c2c66affSColin Finck        jb      short .L7        // if result < original, we are ok
191*c2c66affSColin Finck        cmp     eax,DVNDLO // hi words are equal, compare lo words
192*c2c66affSColin Finck        jbe     short .L7        // if less or equal we are ok, else subtract
193*c2c66affSColin Finck.L6:
194*c2c66affSColin Finck        sub     eax,DVSRLO // subtract divisor from result
195*c2c66affSColin Finck        sbb     edx,DVSRHI
196*c2c66affSColin Finck.L7:
197*c2c66affSColin Finck
198*c2c66affSColin Finck//
199*c2c66affSColin Finck// Calculate remainder by subtracting the result from the original dividend.
200*c2c66affSColin Finck// Since the result is already in a register, we will do the subtract in the
201*c2c66affSColin Finck// opposite direction and negate the result if necessary.
202*c2c66affSColin Finck//
203*c2c66affSColin Finck
204*c2c66affSColin Finck        sub     eax,DVNDLO // subtract dividend from result
205*c2c66affSColin Finck        sbb     edx,DVNDHI
206*c2c66affSColin Finck
207*c2c66affSColin Finck//
208*c2c66affSColin Finck// Now check the result sign flag to see if the result is supposed to be positive
209*c2c66affSColin Finck// or negative.  It is currently negated (because we subtracted in the 'wrong'
210*c2c66affSColin Finck// direction), so if the sign flag is set we are done, otherwise we must negate
211*c2c66affSColin Finck// the result to make it positive again.
212*c2c66affSColin Finck//
213*c2c66affSColin Finck
214*c2c66affSColin Finck        dec     edi             // check result sign flag
215*c2c66affSColin Finck        jns     short .L8        // result is ok, restore stack and return
216*c2c66affSColin Finck.L4:
217*c2c66affSColin Finck        neg     edx             // otherwise, negate the result
218*c2c66affSColin Finck        neg     eax
219*c2c66affSColin Finck        sbb     edx,0
220*c2c66affSColin Finck
221*c2c66affSColin Finck//
222*c2c66affSColin Finck// Just the cleanup left to do.  edx:eax contains the quotient.
223*c2c66affSColin Finck// Restore the saved registers and return.
224*c2c66affSColin Finck//
225*c2c66affSColin Finck
226*c2c66affSColin Finck.L8:
227*c2c66affSColin Finck        pop     edi
228*c2c66affSColin Finck        pop     ebx
229*c2c66affSColin Finck
230*c2c66affSColin Finck        ret     16
231*c2c66affSColin Finck
232*c2c66affSColin FinckEND
233