1/* $OpenBSD: divsi3.S,v 1.2 2004/02/01 05:47:10 drahn Exp $ */ 2/* $NetBSD: divsi3.S,v 1.2 2001/11/13 20:06:40 chris Exp $ */ 3 4/* 5 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 6 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 7 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 9 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 10 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 11 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 12 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 13 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 14 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 15 * SUCH DAMAGE. 16 */ 17 18#include <machine/asm.h> 19 20/* 21 * stack is aligned as there's a possibility of branching to L_overflow 22 * which makes a C call 23 */ 24 25ENTRY(__umodsi3) 26 stmfd sp!, {lr} 27 sub sp, sp, #4 /* align stack */ 28 bl L_udivide 29 add sp, sp, #4 /* unalign stack */ 30 mov r0, r1 31#ifdef __APCS_26__ 32 ldmfd sp!, {pc}^ 33#else /* APCS-32 */ 34 ldmfd sp!, {pc} 35#endif 36 37ENTRY(__modsi3) 38 stmfd sp!, {lr} 39 sub sp, sp, #4 /* align stack */ 40 bl L_divide 41 add sp, sp, #4 /* unalign stack */ 42 mov r0, r1 43#ifdef __APCS_26__ 44 ldmfd sp!, {pc}^ 45#else 46 ldmfd sp!, {pc} 47#endif 48 49L_overflow: 50#if !defined(_KERNEL) && !defined(_STANDALONE) 51 mov r0, #8 /* SIGFPE */ 52 bl PIC_SYM(_C_LABEL(raise), PLT) /* raise it */ 53 mov r0, #0 54#else 55 /* XXX should cause a fatal error */ 56 mvn r0, #0 57#endif 58#ifdef __APCS_26__ 59 movs pc, lr 60#else 61 mov pc, lr 62#endif 63 64ENTRY(__udivsi3) 65L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */ 66 eor r0, r1, r0 67 eor r1, r0, r1 68 eor r0, r1, r0 69 /* r0 = r1 / r0; r1 = r1 % r0 */ 70 cmp r0, #1 71 bcc L_overflow 72 beq L_divide_l0 73 mov ip, #0 74 movs r1, r1 75 bpl L_divide_l1 76 orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */ 77 movs r1, r1, lsr #1 78 orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */ 79 b L_divide_l1 80 81L_divide_l0: /* r0 == 1 */ 82 mov r0, r1 83 mov r1, #0 84#ifdef __APCS_26__ 85 movs pc, lr 86#else 87 mov pc, lr 88#endif 89 90ENTRY(__divsi3) 91L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */ 92 eor r0, r1, r0 93 eor r1, r0, r1 94 eor r0, r1, r0 95 /* r0 = r1 / r0; r1 = r1 % r0 */ 96 cmp r0, #1 97 bcc L_overflow 98 beq L_divide_l0 99 ands ip, r0, #0x80000000 100 rsbmi r0, r0, #0 101 ands r2, r1, #0x80000000 102 eor ip, ip, r2 103 rsbmi r1, r1, #0 104 orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */ 105 /* ip bit 0x80000000 = -ve remainder */ 106 107L_divide_l1: 108 mov r2, #1 109 mov r3, #0 110 111 /* 112 * If the highest bit of the dividend is set, we have to be 113 * careful when shifting the divisor. Test this. 114 */ 115 movs r1,r1 116 bpl L_old_code 117 118 /* 119 * At this point, the highest bit of r1 is known to be set. 120 * We abuse this below in the tst instructions. 121 */ 122 tst r1, r0 /*, lsl #0 */ 123 bmi L_divide_b1 124 tst r1, r0, lsl #1 125 bmi L_divide_b2 126 tst r1, r0, lsl #2 127 bmi L_divide_b3 128 tst r1, r0, lsl #3 129 bmi L_divide_b4 130 tst r1, r0, lsl #4 131 bmi L_divide_b5 132 tst r1, r0, lsl #5 133 bmi L_divide_b6 134 tst r1, r0, lsl #6 135 bmi L_divide_b7 136 tst r1, r0, lsl #7 137 bmi L_divide_b8 138 tst r1, r0, lsl #8 139 bmi L_divide_b9 140 tst r1, r0, lsl #9 141 bmi L_divide_b10 142 tst r1, r0, lsl #10 143 bmi L_divide_b11 144 tst r1, r0, lsl #11 145 bmi L_divide_b12 146 tst r1, r0, lsl #12 147 bmi L_divide_b13 148 tst r1, r0, lsl #13 149 bmi L_divide_b14 150 tst r1, r0, lsl #14 151 bmi L_divide_b15 152 tst r1, r0, lsl #15 153 bmi L_divide_b16 154 tst r1, r0, lsl #16 155 bmi L_divide_b17 156 tst r1, r0, lsl #17 157 bmi L_divide_b18 158 tst r1, r0, lsl #18 159 bmi L_divide_b19 160 tst r1, r0, lsl #19 161 bmi L_divide_b20 162 tst r1, r0, lsl #20 163 bmi L_divide_b21 164 tst r1, r0, lsl #21 165 bmi L_divide_b22 166 tst r1, r0, lsl #22 167 bmi L_divide_b23 168 tst r1, r0, lsl #23 169 bmi L_divide_b24 170 tst r1, r0, lsl #24 171 bmi L_divide_b25 172 tst r1, r0, lsl #25 173 bmi L_divide_b26 174 tst r1, r0, lsl #26 175 bmi L_divide_b27 176 tst r1, r0, lsl #27 177 bmi L_divide_b28 178 tst r1, r0, lsl #28 179 bmi L_divide_b29 180 tst r1, r0, lsl #29 181 bmi L_divide_b30 182 tst r1, r0, lsl #30 183 bmi L_divide_b31 184/* 185 * instead of: 186 * tst r1, r0, lsl #31 187 * bmi L_divide_b32 188 */ 189 b L_divide_b32 190 191L_old_code: 192 cmp r1, r0 193 bcc L_divide_b0 194 cmp r1, r0, lsl #1 195 bcc L_divide_b1 196 cmp r1, r0, lsl #2 197 bcc L_divide_b2 198 cmp r1, r0, lsl #3 199 bcc L_divide_b3 200 cmp r1, r0, lsl #4 201 bcc L_divide_b4 202 cmp r1, r0, lsl #5 203 bcc L_divide_b5 204 cmp r1, r0, lsl #6 205 bcc L_divide_b6 206 cmp r1, r0, lsl #7 207 bcc L_divide_b7 208 cmp r1, r0, lsl #8 209 bcc L_divide_b8 210 cmp r1, r0, lsl #9 211 bcc L_divide_b9 212 cmp r1, r0, lsl #10 213 bcc L_divide_b10 214 cmp r1, r0, lsl #11 215 bcc L_divide_b11 216 cmp r1, r0, lsl #12 217 bcc L_divide_b12 218 cmp r1, r0, lsl #13 219 bcc L_divide_b13 220 cmp r1, r0, lsl #14 221 bcc L_divide_b14 222 cmp r1, r0, lsl #15 223 bcc L_divide_b15 224 cmp r1, r0, lsl #16 225 bcc L_divide_b16 226 cmp r1, r0, lsl #17 227 bcc L_divide_b17 228 cmp r1, r0, lsl #18 229 bcc L_divide_b18 230 cmp r1, r0, lsl #19 231 bcc L_divide_b19 232 cmp r1, r0, lsl #20 233 bcc L_divide_b20 234 cmp r1, r0, lsl #21 235 bcc L_divide_b21 236 cmp r1, r0, lsl #22 237 bcc L_divide_b22 238 cmp r1, r0, lsl #23 239 bcc L_divide_b23 240 cmp r1, r0, lsl #24 241 bcc L_divide_b24 242 cmp r1, r0, lsl #25 243 bcc L_divide_b25 244 cmp r1, r0, lsl #26 245 bcc L_divide_b26 246 cmp r1, r0, lsl #27 247 bcc L_divide_b27 248 cmp r1, r0, lsl #28 249 bcc L_divide_b28 250 cmp r1, r0, lsl #29 251 bcc L_divide_b29 252 cmp r1, r0, lsl #30 253 bcc L_divide_b30 254L_divide_b32: 255 cmp r1, r0, lsl #31 256 subhs r1, r1,r0, lsl #31 257 addhs r3, r3,r2, lsl #31 258L_divide_b31: 259 cmp r1, r0, lsl #30 260 subhs r1, r1,r0, lsl #30 261 addhs r3, r3,r2, lsl #30 262L_divide_b30: 263 cmp r1, r0, lsl #29 264 subhs r1, r1,r0, lsl #29 265 addhs r3, r3,r2, lsl #29 266L_divide_b29: 267 cmp r1, r0, lsl #28 268 subhs r1, r1,r0, lsl #28 269 addhs r3, r3,r2, lsl #28 270L_divide_b28: 271 cmp r1, r0, lsl #27 272 subhs r1, r1,r0, lsl #27 273 addhs r3, r3,r2, lsl #27 274L_divide_b27: 275 cmp r1, r0, lsl #26 276 subhs r1, r1,r0, lsl #26 277 addhs r3, r3,r2, lsl #26 278L_divide_b26: 279 cmp r1, r0, lsl #25 280 subhs r1, r1,r0, lsl #25 281 addhs r3, r3,r2, lsl #25 282L_divide_b25: 283 cmp r1, r0, lsl #24 284 subhs r1, r1,r0, lsl #24 285 addhs r3, r3,r2, lsl #24 286L_divide_b24: 287 cmp r1, r0, lsl #23 288 subhs r1, r1,r0, lsl #23 289 addhs r3, r3,r2, lsl #23 290L_divide_b23: 291 cmp r1, r0, lsl #22 292 subhs r1, r1,r0, lsl #22 293 addhs r3, r3,r2, lsl #22 294L_divide_b22: 295 cmp r1, r0, lsl #21 296 subhs r1, r1,r0, lsl #21 297 addhs r3, r3,r2, lsl #21 298L_divide_b21: 299 cmp r1, r0, lsl #20 300 subhs r1, r1,r0, lsl #20 301 addhs r3, r3,r2, lsl #20 302L_divide_b20: 303 cmp r1, r0, lsl #19 304 subhs r1, r1,r0, lsl #19 305 addhs r3, r3,r2, lsl #19 306L_divide_b19: 307 cmp r1, r0, lsl #18 308 subhs r1, r1,r0, lsl #18 309 addhs r3, r3,r2, lsl #18 310L_divide_b18: 311 cmp r1, r0, lsl #17 312 subhs r1, r1,r0, lsl #17 313 addhs r3, r3,r2, lsl #17 314L_divide_b17: 315 cmp r1, r0, lsl #16 316 subhs r1, r1,r0, lsl #16 317 addhs r3, r3,r2, lsl #16 318L_divide_b16: 319 cmp r1, r0, lsl #15 320 subhs r1, r1,r0, lsl #15 321 addhs r3, r3,r2, lsl #15 322L_divide_b15: 323 cmp r1, r0, lsl #14 324 subhs r1, r1,r0, lsl #14 325 addhs r3, r3,r2, lsl #14 326L_divide_b14: 327 cmp r1, r0, lsl #13 328 subhs r1, r1,r0, lsl #13 329 addhs r3, r3,r2, lsl #13 330L_divide_b13: 331 cmp r1, r0, lsl #12 332 subhs r1, r1,r0, lsl #12 333 addhs r3, r3,r2, lsl #12 334L_divide_b12: 335 cmp r1, r0, lsl #11 336 subhs r1, r1,r0, lsl #11 337 addhs r3, r3,r2, lsl #11 338L_divide_b11: 339 cmp r1, r0, lsl #10 340 subhs r1, r1,r0, lsl #10 341 addhs r3, r3,r2, lsl #10 342L_divide_b10: 343 cmp r1, r0, lsl #9 344 subhs r1, r1,r0, lsl #9 345 addhs r3, r3,r2, lsl #9 346L_divide_b9: 347 cmp r1, r0, lsl #8 348 subhs r1, r1,r0, lsl #8 349 addhs r3, r3,r2, lsl #8 350L_divide_b8: 351 cmp r1, r0, lsl #7 352 subhs r1, r1,r0, lsl #7 353 addhs r3, r3,r2, lsl #7 354L_divide_b7: 355 cmp r1, r0, lsl #6 356 subhs r1, r1,r0, lsl #6 357 addhs r3, r3,r2, lsl #6 358L_divide_b6: 359 cmp r1, r0, lsl #5 360 subhs r1, r1,r0, lsl #5 361 addhs r3, r3,r2, lsl #5 362L_divide_b5: 363 cmp r1, r0, lsl #4 364 subhs r1, r1,r0, lsl #4 365 addhs r3, r3,r2, lsl #4 366L_divide_b4: 367 cmp r1, r0, lsl #3 368 subhs r1, r1,r0, lsl #3 369 addhs r3, r3,r2, lsl #3 370L_divide_b3: 371 cmp r1, r0, lsl #2 372 subhs r1, r1,r0, lsl #2 373 addhs r3, r3,r2, lsl #2 374L_divide_b2: 375 cmp r1, r0, lsl #1 376 subhs r1, r1,r0, lsl #1 377 addhs r3, r3,r2, lsl #1 378L_divide_b1: 379 cmp r1, r0 380 subhs r1, r1, r0 381 addhs r3, r3, r2 382L_divide_b0: 383 384 tst ip, #0x20000000 385 bne L_udivide_l1 386 mov r0, r3 387 cmp ip, #0 388 rsbmi r1, r1, #0 389 movs ip, ip, lsl #1 390 bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */ 391 rsbmi r0, r0, #0 392#ifdef __APCS_26__ 393 movs pc, lr 394#else 395 mov pc, lr 396#endif 397 398L_udivide_l1: 399 tst ip, #0x10000000 400 mov r1, r1, lsl #1 401 orrne r1, r1, #1 402 mov r3, r3, lsl #1 403 cmp r1, r0 404 subhs r1, r1, r0 405 addhs r3, r3, r2 406 mov r0, r3 407#ifdef __APCS_26__ 408 movs pc, lr 409#else 410 mov pc, lr 411#endif 412