linux / linux / kernel / git / mellanox / linux / 96cd5b0856a25e2ec366702e1923070ffca53dae / . / arch / arm26 / lib / lib1funcs.S

@ libgcc1 routines for ARM cpu. | |

@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) | |

/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. | |

This file is free software; you can redistribute it and/or modify it | |

under the terms of the GNU General Public License as published by the | |

Free Software Foundation; either version 2, or (at your option) any | |

later version. | |

In addition to the permissions in the GNU General Public License, the | |

Free Software Foundation gives you unlimited permission to link the | |

compiled version of this file with other programs, and to distribute | |

those programs without any restriction coming from the use of this | |

file. (The General Public License restrictions do apply in other | |

respects; for example, they cover modification of the file, and | |

distribution when not linked into another program.) | |

This file is distributed in the hope that it will be useful, but | |

WITHOUT ANY WARRANTY; without even the implied warranty of | |

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |

General Public License for more details. | |

You should have received a copy of the GNU General Public License | |

along with this program; see the file COPYING. If not, write to | |

the Free Software Foundation, 59 Temple Place - Suite 330, | |

Boston, MA 02111-1307, USA. */ | |

/* As a special exception, if you link this library with other files, | |

some of which are compiled with GCC, to produce an executable, | |

this library does not by itself cause the resulting executable | |

to be covered by the GNU General Public License. | |

This exception does not however invalidate any other reasons why | |

the executable file might be covered by the GNU General Public License. | |

*/ | |

/* This code is derived from gcc 2.95.3 */ | |

/* I Molton 29/07/01 */ | |

#include <linux/linkage.h> | |

#include <asm/assembler.h> | |

#include <asm/hardware.h> | |

#include <linux/config.h> | |

#define RET movs | |

#define RETc(x) mov##x##s | |

#define RETCOND ^ | |

dividend .req r0 | |

divisor .req r1 | |

result .req r2 | |

overdone .req r2 | |

curbit .req r3 | |

ip .req r12 | |

sp .req r13 | |

lr .req r14 | |

pc .req r15 | |

ENTRY(__udivsi3) | |

cmp divisor, #0 | |

beq Ldiv0 | |

mov curbit, #1 | |

mov result, #0 | |

cmp dividend, divisor | |

bcc Lgot_result_udivsi3 | |

1: | |

@ Unless the divisor is very big, shift it up in multiples of | |

@ four bits, since this is the amount of unwinding in the main | |

@ division loop. Continue shifting until the divisor is | |

@ larger than the dividend. | |

cmp divisor, #0x10000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #4 | |

movcc curbit, curbit, lsl #4 | |

bcc 1b | |

2: | |

@ For very big divisors, we must shift it a bit at a time, or | |

@ we will be in danger of overflowing. | |

cmp divisor, #0x80000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #1 | |

movcc curbit, curbit, lsl #1 | |

bcc 2b | |

3: | |

@ Test for possible subtractions, and note which bits | |

@ are done in the result. On the final pass, this may subtract | |

@ too much from the dividend, but the result will be ok, since the | |

@ "bit" will have been shifted out at the bottom. | |

cmp dividend, divisor | |

subcs dividend, dividend, divisor | |

orrcs result, result, curbit | |

cmp dividend, divisor, lsr #1 | |

subcs dividend, dividend, divisor, lsr #1 | |

orrcs result, result, curbit, lsr #1 | |

cmp dividend, divisor, lsr #2 | |

subcs dividend, dividend, divisor, lsr #2 | |

orrcs result, result, curbit, lsr #2 | |

cmp dividend, divisor, lsr #3 | |

subcs dividend, dividend, divisor, lsr #3 | |

orrcs result, result, curbit, lsr #3 | |

cmp dividend, #0 @ Early termination? | |

movnes curbit, curbit, lsr #4 @ No, any more bits to do? | |

movne divisor, divisor, lsr #4 | |

bne 3b | |

Lgot_result_udivsi3: | |

mov r0, result | |

RET pc, lr | |

Ldiv0: | |

str lr, [sp, #-4]! | |

bl __div0 | |

mov r0, #0 @ about as wrong as it could be | |

ldmia sp!, {pc}RETCOND | |

/* __umodsi3 ----------------------- */ | |

ENTRY(__umodsi3) | |

cmp divisor, #0 | |

beq Ldiv0 | |

mov curbit, #1 | |

cmp dividend, divisor | |

RETc(cc) pc, lr | |

1: | |

@ Unless the divisor is very big, shift it up in multiples of | |

@ four bits, since this is the amount of unwinding in the main | |

@ division loop. Continue shifting until the divisor is | |

@ larger than the dividend. | |

cmp divisor, #0x10000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #4 | |

movcc curbit, curbit, lsl #4 | |

bcc 1b | |

2: | |

@ For very big divisors, we must shift it a bit at a time, or | |

@ we will be in danger of overflowing. | |

cmp divisor, #0x80000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #1 | |

movcc curbit, curbit, lsl #1 | |

bcc 2b | |

3: | |

@ Test for possible subtractions. On the final pass, this may | |

@ subtract too much from the dividend, so keep track of which | |

@ subtractions are done, we can fix them up afterwards... | |

mov overdone, #0 | |

cmp dividend, divisor | |

subcs dividend, dividend, divisor | |

cmp dividend, divisor, lsr #1 | |

subcs dividend, dividend, divisor, lsr #1 | |

orrcs overdone, overdone, curbit, ror #1 | |

cmp dividend, divisor, lsr #2 | |

subcs dividend, dividend, divisor, lsr #2 | |

orrcs overdone, overdone, curbit, ror #2 | |

cmp dividend, divisor, lsr #3 | |

subcs dividend, dividend, divisor, lsr #3 | |

orrcs overdone, overdone, curbit, ror #3 | |

mov ip, curbit | |

cmp dividend, #0 @ Early termination? | |

movnes curbit, curbit, lsr #4 @ No, any more bits to do? | |

movne divisor, divisor, lsr #4 | |

bne 3b | |

@ Any subtractions that we should not have done will be recorded in | |

@ the top three bits of "overdone". Exactly which were not needed | |

@ are governed by the position of the bit, stored in ip. | |

@ If we terminated early, because dividend became zero, | |

@ then none of the below will match, since the bit in ip will not be | |

@ in the bottom nibble. | |

ands overdone, overdone, #0xe0000000 | |

RETc(eq) pc, lr @ No fixups needed | |

tst overdone, ip, ror #3 | |

addne dividend, dividend, divisor, lsr #3 | |

tst overdone, ip, ror #2 | |

addne dividend, dividend, divisor, lsr #2 | |

tst overdone, ip, ror #1 | |

addne dividend, dividend, divisor, lsr #1 | |

RET pc, lr | |

ENTRY(__divsi3) | |

eor ip, dividend, divisor @ Save the sign of the result. | |

mov curbit, #1 | |

mov result, #0 | |

cmp divisor, #0 | |

rsbmi divisor, divisor, #0 @ Loops below use unsigned. | |

beq Ldiv0 | |

cmp dividend, #0 | |

rsbmi dividend, dividend, #0 | |

cmp dividend, divisor | |

bcc Lgot_result_divsi3 | |

1: | |

@ Unless the divisor is very big, shift it up in multiples of | |

@ four bits, since this is the amount of unwinding in the main | |

@ division loop. Continue shifting until the divisor is | |

@ larger than the dividend. | |

cmp divisor, #0x10000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #4 | |

movcc curbit, curbit, lsl #4 | |

bcc 1b | |

2: | |

@ For very big divisors, we must shift it a bit at a time, or | |

@ we will be in danger of overflowing. | |

cmp divisor, #0x80000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #1 | |

movcc curbit, curbit, lsl #1 | |

bcc 2b | |

3: | |

@ Test for possible subtractions, and note which bits | |

@ are done in the result. On the final pass, this may subtract | |

@ too much from the dividend, but the result will be ok, since the | |

@ "bit" will have been shifted out at the bottom. | |

cmp dividend, divisor | |

subcs dividend, dividend, divisor | |

orrcs result, result, curbit | |

cmp dividend, divisor, lsr #1 | |

subcs dividend, dividend, divisor, lsr #1 | |

orrcs result, result, curbit, lsr #1 | |

cmp dividend, divisor, lsr #2 | |

subcs dividend, dividend, divisor, lsr #2 | |

orrcs result, result, curbit, lsr #2 | |

cmp dividend, divisor, lsr #3 | |

subcs dividend, dividend, divisor, lsr #3 | |

orrcs result, result, curbit, lsr #3 | |

cmp dividend, #0 @ Early termination? | |

movnes curbit, curbit, lsr #4 @ No, any more bits to do? | |

movne divisor, divisor, lsr #4 | |

bne 3b | |

Lgot_result_divsi3: | |

mov r0, result | |

cmp ip, #0 | |

rsbmi r0, r0, #0 | |

RET pc, lr | |

ENTRY(__modsi3) | |

mov curbit, #1 | |

cmp divisor, #0 | |

rsbmi divisor, divisor, #0 @ Loops below use unsigned. | |

beq Ldiv0 | |

@ Need to save the sign of the dividend, unfortunately, we need | |

@ ip later on; this is faster than pushing lr and using that. | |

str dividend, [sp, #-4]! | |

cmp dividend, #0 | |

rsbmi dividend, dividend, #0 | |

cmp dividend, divisor | |

bcc Lgot_result_modsi3 | |

1: | |

@ Unless the divisor is very big, shift it up in multiples of | |

@ four bits, since this is the amount of unwinding in the main | |

@ division loop. Continue shifting until the divisor is | |

@ larger than the dividend. | |

cmp divisor, #0x10000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #4 | |

movcc curbit, curbit, lsl #4 | |

bcc 1b | |

2: | |

@ For very big divisors, we must shift it a bit at a time, or | |

@ we will be in danger of overflowing. | |

cmp divisor, #0x80000000 | |

cmpcc divisor, dividend | |

movcc divisor, divisor, lsl #1 | |

movcc curbit, curbit, lsl #1 | |

bcc 2b | |

3: | |

@ Test for possible subtractions. On the final pass, this may | |

@ subtract too much from the dividend, so keep track of which | |

@ subtractions are done, we can fix them up afterwards... | |

mov overdone, #0 | |

cmp dividend, divisor | |

subcs dividend, dividend, divisor | |

cmp dividend, divisor, lsr #1 | |

subcs dividend, dividend, divisor, lsr #1 | |

orrcs overdone, overdone, curbit, ror #1 | |

cmp dividend, divisor, lsr #2 | |

subcs dividend, dividend, divisor, lsr #2 | |

orrcs overdone, overdone, curbit, ror #2 | |

cmp dividend, divisor, lsr #3 | |

subcs dividend, dividend, divisor, lsr #3 | |

orrcs overdone, overdone, curbit, ror #3 | |

mov ip, curbit | |

cmp dividend, #0 @ Early termination? | |

movnes curbit, curbit, lsr #4 @ No, any more bits to do? | |

movne divisor, divisor, lsr #4 | |

bne 3b | |

@ Any subtractions that we should not have done will be recorded in | |

@ the top three bits of "overdone". Exactly which were not needed | |

@ are governed by the position of the bit, stored in ip. | |

@ If we terminated early, because dividend became zero, | |

@ then none of the below will match, since the bit in ip will not be | |

@ in the bottom nibble. | |

ands overdone, overdone, #0xe0000000 | |

beq Lgot_result_modsi3 | |

tst overdone, ip, ror #3 | |

addne dividend, dividend, divisor, lsr #3 | |

tst overdone, ip, ror #2 | |

addne dividend, dividend, divisor, lsr #2 | |

tst overdone, ip, ror #1 | |

addne dividend, dividend, divisor, lsr #1 | |

Lgot_result_modsi3: | |

ldr ip, [sp], #4 | |

cmp ip, #0 | |

rsbmi dividend, dividend, #0 | |

RET pc, lr |