Merge branch 'for-33' of git://repo.or.cz/linux-kbuild
[linux-2.6.git] / arch / blackfin / lib / divsi3.S
1 /*
2  * Copyright 2004-2009 Analog Devices Inc.
3  *
4  * Licensed under the ADI BSD license or the GPL-2 (or later)
5  *
6  * 16 / 32 bit signed division.
7  *                 Special cases :
8  *                      1)  If(numerator == 0)
9  *                             return 0
10  *                      2)  If(denominator ==0)
11  *                             return positive max = 0x7fffffff
12  *                      3)  If(numerator == denominator)
13  *                             return 1
14  *                      4)  If(denominator ==1)
15  *                             return numerator
16  *                      5)  If(denominator == -1)
17  *                             return -numerator
18  *
19  *                 Operand         : R0 - Numerator   (i)
20  *                                   R1 - Denominator (i)
21  *                                   R0 - Quotient    (o)
22  *                 Registers Used : R2-R7,P0-P2
23  *
24  */
25
26 .global   ___divsi3;
27 .type ___divsi3, STT_FUNC;
28
29 #ifdef CONFIG_ARITHMETIC_OPS_L1
30 .section .l1.text
31 #else
32 .text
33 #endif
34
35 .align 2;
36 ___divsi3 :
37
38
39   R3 = R0 ^ R1;
40   R0 = ABS R0;
41
42   CC = V;
43
44   r3 = rot r3 by -1;
45   r1 = abs r1;      /* now both positive, r3.30 means "negate result",
46                     ** r3.31 means overflow, add one to result
47                     */
48   cc = r0 < r1;
49   if cc jump .Lret_zero;
50   r2 = r1 >> 15;
51   cc = r2;
52   if cc jump .Lidents;
53   r2 = r1 << 16;
54   cc = r2 <= r0;
55   if cc jump .Lidents;
56
57   DIVS(R0, R1);
58   DIVQ(R0, R1);
59   DIVQ(R0, R1);
60   DIVQ(R0, R1);
61   DIVQ(R0, R1);
62   DIVQ(R0, R1);
63   DIVQ(R0, R1);
64   DIVQ(R0, R1);
65   DIVQ(R0, R1);
66   DIVQ(R0, R1);
67   DIVQ(R0, R1);
68   DIVQ(R0, R1);
69   DIVQ(R0, R1);
70   DIVQ(R0, R1);
71   DIVQ(R0, R1);
72   DIVQ(R0, R1);
73   DIVQ(R0, R1);
74
75   R0 = R0.L (Z);
76   r1 = r3 >> 31;    /* add overflow issue back in */
77   r0 = r0 + r1;
78   r1 = -r0;
79   cc = bittst(r3, 30);
80   if cc r0 = r1;
81   RTS;
82
83 /* Can't use the primitives. Test common identities.
84 ** If the identity is true, return the value in R2.
85 */
86
87 .Lidents:
88   CC = R1 == 0;                   /* check for divide by zero */
89   IF CC JUMP .Lident_return;
90
91   CC = R0 == 0;                   /* check for division of zero */
92   IF CC JUMP .Lzero_return;
93
94   CC = R0 == R1;                  /* check for identical operands */
95   IF CC JUMP .Lident_return;
96
97   CC = R1 == 1;                   /* check for divide by 1 */
98   IF CC JUMP .Lident_return;
99
100   R2.L = ONES R1;
101   R2 = R2.L (Z);
102   CC = R2 == 1;
103   IF CC JUMP .Lpower_of_two;
104
105   /* Identities haven't helped either.
106   ** Perform the full division process.
107   */
108
109   P1 = 31;                        /* Set loop counter   */
110
111   [--SP] = (R7:5);                /* Push registers R5-R7 */
112   R2 = -R1;
113   [--SP] = R2;
114   R2 = R0 << 1;                   /* R2 lsw of dividend  */
115   R6 = R0 ^ R1;                   /* Get sign */
116   R5 = R6 >> 31;                  /* Shift sign to LSB */
117
118   R0 = 0 ;                        /* Clear msw partial remainder */
119   R2 = R2 | R5;                   /* Shift quotient bit */
120   R6 = R0 ^ R1;                   /* Get new quotient bit */
121
122   LSETUP(.Llst,.Llend)  LC0 = P1;   /* Setup loop */
123 .Llst:   R7 = R2 >> 31;            /* record copy of carry from R2 */
124         R2 = R2 << 1;             /* Shift 64 bit dividend up by 1 bit */
125         R0 = R0 << 1 || R5 = [SP];
126         R0 = R0 | R7;             /* and add carry */
127         CC = R6 < 0;              /* Check quotient(AQ) */
128                                   /* we might be subtracting divisor (AQ==0) */
129         IF CC R5 = R1;            /* or we might be adding divisor  (AQ==1)*/
130         R0 = R0 + R5;             /* do add or subtract, as indicated by AQ */
131         R6 = R0 ^ R1;             /* Generate next quotient bit */
132         R5 = R6 >> 31;
133                                   /* Assume AQ==1, shift in zero */
134         BITTGL(R5,0);             /* tweak AQ to be what we want to shift in */
135 .Llend:  R2 = R2 + R5;             /* and then set shifted-in value to
136                                   ** tweaked AQ.
137                                   */
138   r1 = r3 >> 31;
139   r2 = r2 + r1;
140   cc = bittst(r3,30);
141   r0 = -r2;
142   if !cc r0 = r2;
143   SP += 4;
144   (R7:5)= [SP++];                 /* Pop registers R6-R7 */
145   RTS;
146
147 .Lident_return:
148   CC = R1 == 0;                   /* check for divide by zero  => 0x7fffffff */
149   R2 = -1 (X);
150   R2 >>= 1;
151   IF CC JUMP .Ltrue_ident_return;
152
153   CC = R0 == R1;                  /* check for identical operands => 1 */
154   R2 = 1 (Z);
155   IF CC JUMP .Ltrue_ident_return;
156
157   R2 = R0;                        /* assume divide by 1 => numerator */
158   /*FALLTHRU*/
159
160 .Ltrue_ident_return:
161   R0 = R2;                        /* Return an identity value */
162   R2 = -R2;
163   CC = bittst(R3,30);
164   IF CC R0 = R2;
165 .Lzero_return:
166   RTS;                            /* ...including zero */
167
168 .Lpower_of_two:
169   /* Y has a single bit set, which means it's a power of two.
170   ** That means we can perform the division just by shifting
171   ** X to the right the appropriate number of bits
172   */
173
174   /* signbits returns the number of sign bits, minus one.
175   ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
176   ** to shift right n-signbits spaces. It also means 0x80000000
177   ** is a special case, because that *also* gives a signbits of 0
178   */
179
180   R2 = R0 >> 31;
181   CC = R1 < 0;
182   IF CC JUMP .Ltrue_ident_return;
183
184   R1.l = SIGNBITS R1;
185   R1 = R1.L (Z);
186   R1 += -30;
187   R0 = LSHIFT R0 by R1.L;
188   r1 = r3 >> 31;
189   r0 = r0 + r1;
190   R2 = -R0;                       // negate result if necessary
191   CC = bittst(R3,30);
192   IF CC R0 = R2;
193   RTS;
194
195 .Lret_zero:
196   R0 = 0;
197   RTS;
198
199 .size ___divsi3, .-___divsi3