/* $OpenBSD: divsi3.S,v 1.5 2017/10/26 15:23:59 jsg Exp $ */ /* $NetBSD: divsi3.S,v 1.2 2001/11/13 20:06:40 chris Exp $ */ /* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include /* * stack is aligned as there's a possibility of branching to L_overflow * which makes a C call */ ENTRY(__umodsi3) stmfd sp!, {lr} sub sp, sp, #4 /* align stack */ bl L_udivide add sp, sp, #4 /* unalign stack */ mov r0, r1 ldmfd sp!, {pc} ENTRY(__modsi3) stmfd sp!, {lr} sub sp, sp, #4 /* align stack */ bl L_divide add sp, sp, #4 /* unalign stack */ mov r0, r1 ldmfd sp!, {pc} L_overflow: #if !defined(_KERNEL) && !defined(_STANDALONE) mov r0, #8 /* SIGFPE */ bl PIC_SYM(_C_LABEL(raise), PLT) /* raise it */ mov r0, #0 #else /* XXX should cause a fatal error */ mvn r0, #0 #endif mov pc, lr ENTRY(__udivsi3) L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */ eor r0, r1, r0 eor r1, r0, r1 eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */ cmp r0, #1 bcc L_overflow beq L_divide_l0 mov ip, #0 movs r1, r1 bpl L_divide_l1 orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */ movs r1, r1, lsr #1 orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */ b L_divide_l1 L_divide_l0: /* r0 == 1 */ mov r0, r1 mov r1, #0 mov pc, lr ENTRY(__divsi3) L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */ eor r0, r1, r0 eor r1, r0, r1 eor r0, r1, r0 /* r0 = r1 / r0; r1 = r1 % r0 */ cmp r0, #1 bcc L_overflow beq L_divide_l0 ands ip, r0, #0x80000000 rsbmi r0, r0, #0 ands r2, r1, #0x80000000 eor ip, ip, r2 rsbmi r1, r1, #0 orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */ /* ip bit 0x80000000 = -ve remainder */ L_divide_l1: mov r2, #1 mov r3, #0 /* * If the highest bit of the dividend is set, we have to be * careful when shifting the divisor. Test this. */ movs r1,r1 bpl L_old_code /* * At this point, the highest bit of r1 is known to be set. * We abuse this below in the tst instructions. */ tst r1, r0 /*, lsl #0 */ bmi L_divide_b1 tst r1, r0, lsl #1 bmi L_divide_b2 tst r1, r0, lsl #2 bmi L_divide_b3 tst r1, r0, lsl #3 bmi L_divide_b4 tst r1, r0, lsl #4 bmi L_divide_b5 tst r1, r0, lsl #5 bmi L_divide_b6 tst r1, r0, lsl #6 bmi L_divide_b7 tst r1, r0, lsl #7 bmi L_divide_b8 tst r1, r0, lsl #8 bmi L_divide_b9 tst r1, r0, lsl #9 bmi L_divide_b10 tst r1, r0, lsl #10 bmi L_divide_b11 tst r1, r0, lsl #11 bmi L_divide_b12 tst r1, r0, lsl #12 bmi L_divide_b13 tst r1, r0, lsl #13 bmi L_divide_b14 tst r1, r0, lsl #14 bmi L_divide_b15 tst r1, r0, lsl #15 bmi L_divide_b16 tst r1, r0, lsl #16 bmi L_divide_b17 tst r1, r0, lsl #17 bmi L_divide_b18 tst r1, r0, lsl #18 bmi L_divide_b19 tst r1, r0, lsl #19 bmi L_divide_b20 tst r1, r0, lsl #20 bmi L_divide_b21 tst r1, r0, lsl #21 bmi L_divide_b22 tst r1, r0, lsl #22 bmi L_divide_b23 tst r1, r0, lsl #23 bmi L_divide_b24 tst r1, r0, lsl #24 bmi L_divide_b25 tst r1, r0, lsl #25 bmi L_divide_b26 tst r1, r0, lsl #26 bmi L_divide_b27 tst r1, r0, lsl #27 bmi L_divide_b28 tst r1, r0, lsl #28 bmi L_divide_b29 tst r1, r0, lsl #29 bmi L_divide_b30 tst r1, r0, lsl #30 bmi L_divide_b31 /* * instead of: * tst r1, r0, lsl #31 * bmi L_divide_b32 */ b L_divide_b32 L_old_code: cmp r1, r0 bcc L_divide_b0 cmp r1, r0, lsl #1 bcc L_divide_b1 cmp r1, r0, lsl #2 bcc L_divide_b2 cmp r1, r0, lsl #3 bcc L_divide_b3 cmp r1, r0, lsl #4 bcc L_divide_b4 cmp r1, r0, lsl #5 bcc L_divide_b5 cmp r1, r0, lsl #6 bcc L_divide_b6 cmp r1, r0, lsl #7 bcc L_divide_b7 cmp r1, r0, lsl #8 bcc L_divide_b8 cmp r1, r0, lsl #9 bcc L_divide_b9 cmp r1, r0, lsl #10 bcc L_divide_b10 cmp r1, r0, lsl #11 bcc L_divide_b11 cmp r1, r0, lsl #12 bcc L_divide_b12 cmp r1, r0, lsl #13 bcc L_divide_b13 cmp r1, r0, lsl #14 bcc L_divide_b14 cmp r1, r0, lsl #15 bcc L_divide_b15 cmp r1, r0, lsl #16 bcc L_divide_b16 cmp r1, r0, lsl #17 bcc L_divide_b17 cmp r1, r0, lsl #18 bcc L_divide_b18 cmp r1, r0, lsl #19 bcc L_divide_b19 cmp r1, r0, lsl #20 bcc L_divide_b20 cmp r1, r0, lsl #21 bcc L_divide_b21 cmp r1, r0, lsl #22 bcc L_divide_b22 cmp r1, r0, lsl #23 bcc L_divide_b23 cmp r1, r0, lsl #24 bcc L_divide_b24 cmp r1, r0, lsl #25 bcc L_divide_b25 cmp r1, r0, lsl #26 bcc L_divide_b26 cmp r1, r0, lsl #27 bcc L_divide_b27 cmp r1, r0, lsl #28 bcc L_divide_b28 cmp r1, r0, lsl #29 bcc L_divide_b29 cmp r1, r0, lsl #30 bcc L_divide_b30 L_divide_b32: cmp r1, r0, lsl #31 subhs r1, r1,r0, lsl #31 addhs r3, r3,r2, lsl #31 L_divide_b31: cmp r1, r0, lsl #30 subhs r1, r1,r0, lsl #30 addhs r3, r3,r2, lsl #30 L_divide_b30: cmp r1, r0, lsl #29 subhs r1, r1,r0, lsl #29 addhs r3, r3,r2, lsl #29 L_divide_b29: cmp r1, r0, lsl #28 subhs r1, r1,r0, lsl #28 addhs r3, r3,r2, lsl #28 L_divide_b28: cmp r1, r0, lsl #27 subhs r1, r1,r0, lsl #27 addhs r3, r3,r2, lsl #27 L_divide_b27: cmp r1, r0, lsl #26 subhs r1, r1,r0, lsl #26 addhs r3, r3,r2, lsl #26 L_divide_b26: cmp r1, r0, lsl #25 subhs r1, r1,r0, lsl #25 addhs r3, r3,r2, lsl #25 L_divide_b25: cmp r1, r0, lsl #24 subhs r1, r1,r0, lsl #24 addhs r3, r3,r2, lsl #24 L_divide_b24: cmp r1, r0, lsl #23 subhs r1, r1,r0, lsl #23 addhs r3, r3,r2, lsl #23 L_divide_b23: cmp r1, r0, lsl #22 subhs r1, r1,r0, lsl #22 addhs r3, r3,r2, lsl #22 L_divide_b22: cmp r1, r0, lsl #21 subhs r1, r1,r0, lsl #21 addhs r3, r3,r2, lsl #21 L_divide_b21: cmp r1, r0, lsl #20 subhs r1, r1,r0, lsl #20 addhs r3, r3,r2, lsl #20 L_divide_b20: cmp r1, r0, lsl #19 subhs r1, r1,r0, lsl #19 addhs r3, r3,r2, lsl #19 L_divide_b19: cmp r1, r0, lsl #18 subhs r1, r1,r0, lsl #18 addhs r3, r3,r2, lsl #18 L_divide_b18: cmp r1, r0, lsl #17 subhs r1, r1,r0, lsl #17 addhs r3, r3,r2, lsl #17 L_divide_b17: cmp r1, r0, lsl #16 subhs r1, r1,r0, lsl #16 addhs r3, r3,r2, lsl #16 L_divide_b16: cmp r1, r0, lsl #15 subhs r1, r1,r0, lsl #15 addhs r3, r3,r2, lsl #15 L_divide_b15: cmp r1, r0, lsl #14 subhs r1, r1,r0, lsl #14 addhs r3, r3,r2, lsl #14 L_divide_b14: cmp r1, r0, lsl #13 subhs r1, r1,r0, lsl #13 addhs r3, r3,r2, lsl #13 L_divide_b13: cmp r1, r0, lsl #12 subhs r1, r1,r0, lsl #12 addhs r3, r3,r2, lsl #12 L_divide_b12: cmp r1, r0, lsl #11 subhs r1, r1,r0, lsl #11 addhs r3, r3,r2, lsl #11 L_divide_b11: cmp r1, r0, lsl #10 subhs r1, r1,r0, lsl #10 addhs r3, r3,r2, lsl #10 L_divide_b10: cmp r1, r0, lsl #9 subhs r1, r1,r0, lsl #9 addhs r3, r3,r2, lsl #9 L_divide_b9: cmp r1, r0, lsl #8 subhs r1, r1,r0, lsl #8 addhs r3, r3,r2, lsl #8 L_divide_b8: cmp r1, r0, lsl #7 subhs r1, r1,r0, lsl #7 addhs r3, r3,r2, lsl #7 L_divide_b7: cmp r1, r0, lsl #6 subhs r1, r1,r0, lsl #6 addhs r3, r3,r2, lsl #6 L_divide_b6: cmp r1, r0, lsl #5 subhs r1, r1,r0, lsl #5 addhs r3, r3,r2, lsl #5 L_divide_b5: cmp r1, r0, lsl #4 subhs r1, r1,r0, lsl #4 addhs r3, r3,r2, lsl #4 L_divide_b4: cmp r1, r0, lsl #3 subhs r1, r1,r0, lsl #3 addhs r3, r3,r2, lsl #3 L_divide_b3: cmp r1, r0, lsl #2 subhs r1, r1,r0, lsl #2 addhs r3, r3,r2, lsl #2 L_divide_b2: cmp r1, r0, lsl #1 subhs r1, r1,r0, lsl #1 addhs r3, r3,r2, lsl #1 L_divide_b1: cmp r1, r0 subhs r1, r1, r0 addhs r3, r3, r2 L_divide_b0: tst ip, #0x20000000 bne L_udivide_l1 mov r0, r3 cmp ip, #0 rsbmi r1, r1, #0 movs ip, ip, lsl #1 bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */ rsbmi r0, r0, #0 mov pc, lr L_udivide_l1: tst ip, #0x10000000 mov r1, r1, lsl #1 orrne r1, r1, #1 mov r3, r3, lsl #1 cmp r1, r0 subhs r1, r1, r0 addhs r3, r3, r2 mov r0, r3 mov pc, lr STRONG_ALIAS(__aeabi_idiv, __divsi3) STRONG_ALIAS(__aeabi_idivmod, __divsi3) STRONG_ALIAS(__aeabi_uidiv, __udivsi3) STRONG_ALIAS(__aeabi_uidivmod, __udivsi3)