| /* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */ |
| #include <linux/linkage.h> |
| #include <asm/asmmacro.h> |
| #include <asm/core.h> |
| |
| ENTRY(__udivsi3) |
| |
| abi_entry_default |
| #if XCHAL_HAVE_DIV32 |
| quou a2, a2, a3 |
| #else |
| bltui a3, 2, .Lle_one /* check if the divisor <= 1 */ |
| |
| mov a6, a2 /* keep dividend in a6 */ |
| do_nsau a5, a6, a2, a7 /* dividend_shift = nsau (dividend) */ |
| do_nsau a4, a3, a2, a7 /* divisor_shift = nsau (divisor) */ |
| bgeu a5, a4, .Lspecial |
| |
| sub a4, a4, a5 /* count = divisor_shift - dividend_shift */ |
| ssl a4 |
| sll a3, a3 /* divisor <<= count */ |
| movi a2, 0 /* quotient = 0 */ |
| |
| /* test-subtract-and-shift loop; one quotient bit on each iteration */ |
| #if XCHAL_HAVE_LOOPS |
| loopnez a4, .Lloopend |
| #endif /* XCHAL_HAVE_LOOPS */ |
| .Lloop: |
| bltu a6, a3, .Lzerobit |
| sub a6, a6, a3 |
| addi a2, a2, 1 |
| .Lzerobit: |
| slli a2, a2, 1 |
| srli a3, a3, 1 |
| #if !XCHAL_HAVE_LOOPS |
| addi a4, a4, -1 |
| bnez a4, .Lloop |
| #endif /* !XCHAL_HAVE_LOOPS */ |
| .Lloopend: |
| |
| bltu a6, a3, .Lreturn |
| addi a2, a2, 1 /* increment quotient if dividend >= divisor */ |
| .Lreturn: |
| abi_ret_default |
| |
| .Lle_one: |
| beqz a3, .Lerror /* if divisor == 1, return the dividend */ |
| abi_ret_default |
| |
| .Lspecial: |
| /* return dividend >= divisor */ |
| bltu a6, a3, .Lreturn0 |
| movi a2, 1 |
| abi_ret_default |
| |
| .Lerror: |
| /* Divide by zero: Use an illegal instruction to force an exception. |
| The subsequent "DIV0" string can be recognized by the exception |
| handler to identify the real cause of the exception. */ |
| ill |
| .ascii "DIV0" |
| |
| .Lreturn0: |
| movi a2, 0 |
| #endif /* XCHAL_HAVE_DIV32 */ |
| abi_ret_default |
| |
| ENDPROC(__udivsi3) |
| EXPORT_SYMBOL(__udivsi3) |