efb80e7e09
Currently we're hacking libs-y to include libgcc.a, but this has unforeseen consequences since the userspace libgcc is linked with fpregs enabled. We need the kernel to stop using fpregs in an uncontrolled manner to implement lazy fpu state saves. Signed-off-by: Kyle McMartin <kyle@mcmartin.ca>
255 lines
9.4 KiB
ArmAsm
255 lines
9.4 KiB
ArmAsm
/* 32 and 64-bit millicode, original author Hewlett-Packard
|
|
adapted for gcc by Paul Bame <bame@debian.org>
|
|
and Alan Modra <alan@linuxcare.com.au>.
|
|
|
|
Copyright 2001, 2002, 2003 Free Software Foundation, Inc.
|
|
|
|
This file is part of GCC and is released under the terms of
|
|
of the GNU General Public License as published by the Free Software
|
|
Foundation; either version 2, or (at your option) any later version.
|
|
See the file COPYING in the top-level GCC source directory for a copy
|
|
of the license. */
|
|
|
|
#include "milli.h"
|
|
|
|
#ifdef L_divI
|
|
/* ROUTINES: $$divI, $$divoI
|
|
|
|
Single precision divide for signed binary integers.
|
|
|
|
The quotient is truncated towards zero.
|
|
The sign of the quotient is the XOR of the signs of the dividend and
|
|
divisor.
|
|
Divide by zero is trapped.
|
|
Divide of -2**31 by -1 is trapped for $$divoI but not for $$divI.
|
|
|
|
INPUT REGISTERS:
|
|
. arg0 == dividend
|
|
. arg1 == divisor
|
|
. mrp == return pc
|
|
. sr0 == return space when called externally
|
|
|
|
OUTPUT REGISTERS:
|
|
. arg0 = undefined
|
|
. arg1 = undefined
|
|
. ret1 = quotient
|
|
|
|
OTHER REGISTERS AFFECTED:
|
|
. r1 = undefined
|
|
|
|
SIDE EFFECTS:
|
|
. Causes a trap under the following conditions:
|
|
. divisor is zero (traps with ADDIT,= 0,25,0)
|
|
. dividend==-2**31 and divisor==-1 and routine is $$divoI
|
|
. (traps with ADDO 26,25,0)
|
|
. Changes memory at the following places:
|
|
. NONE
|
|
|
|
PERMISSIBLE CONTEXT:
|
|
. Unwindable.
|
|
. Suitable for internal or external millicode.
|
|
. Assumes the special millicode register conventions.
|
|
|
|
DISCUSSION:
|
|
. Branchs to other millicode routines using BE
|
|
. $$div_# for # being 2,3,4,5,6,7,8,9,10,12,14,15
|
|
.
|
|
. For selected divisors, calls a divide by constant routine written by
|
|
. Karl Pettis. Eligible divisors are 1..15 excluding 11 and 13.
|
|
.
|
|
. The only overflow case is -2**31 divided by -1.
|
|
. Both routines return -2**31 but only $$divoI traps. */
|
|
|
|
RDEFINE(temp,r1)
|
|
RDEFINE(retreg,ret1) /* r29 */
|
|
RDEFINE(temp1,arg0)
|
|
SUBSPA_MILLI_DIV
|
|
ATTR_MILLI
|
|
.import $$divI_2,millicode
|
|
.import $$divI_3,millicode
|
|
.import $$divI_4,millicode
|
|
.import $$divI_5,millicode
|
|
.import $$divI_6,millicode
|
|
.import $$divI_7,millicode
|
|
.import $$divI_8,millicode
|
|
.import $$divI_9,millicode
|
|
.import $$divI_10,millicode
|
|
.import $$divI_12,millicode
|
|
.import $$divI_14,millicode
|
|
.import $$divI_15,millicode
|
|
.export $$divI,millicode
|
|
.export $$divoI,millicode
|
|
.proc
|
|
.callinfo millicode
|
|
.entry
|
|
GSYM($$divoI)
|
|
comib,=,n -1,arg1,LREF(negative1) /* when divisor == -1 */
|
|
GSYM($$divI)
|
|
ldo -1(arg1),temp /* is there at most one bit set ? */
|
|
and,<> arg1,temp,r0 /* if not, don't use power of 2 divide */
|
|
addi,> 0,arg1,r0 /* if divisor > 0, use power of 2 divide */
|
|
b,n LREF(neg_denom)
|
|
LSYM(pow2)
|
|
addi,>= 0,arg0,retreg /* if numerator is negative, add the */
|
|
add arg0,temp,retreg /* (denominaotr -1) to correct for shifts */
|
|
extru,= arg1,15,16,temp /* test denominator with 0xffff0000 */
|
|
extrs retreg,15,16,retreg /* retreg = retreg >> 16 */
|
|
or arg1,temp,arg1 /* arg1 = arg1 | (arg1 >> 16) */
|
|
ldi 0xcc,temp1 /* setup 0xcc in temp1 */
|
|
extru,= arg1,23,8,temp /* test denominator with 0xff00 */
|
|
extrs retreg,23,24,retreg /* retreg = retreg >> 8 */
|
|
or arg1,temp,arg1 /* arg1 = arg1 | (arg1 >> 8) */
|
|
ldi 0xaa,temp /* setup 0xaa in temp */
|
|
extru,= arg1,27,4,r0 /* test denominator with 0xf0 */
|
|
extrs retreg,27,28,retreg /* retreg = retreg >> 4 */
|
|
and,= arg1,temp1,r0 /* test denominator with 0xcc */
|
|
extrs retreg,29,30,retreg /* retreg = retreg >> 2 */
|
|
and,= arg1,temp,r0 /* test denominator with 0xaa */
|
|
extrs retreg,30,31,retreg /* retreg = retreg >> 1 */
|
|
MILLIRETN
|
|
LSYM(neg_denom)
|
|
addi,< 0,arg1,r0 /* if arg1 >= 0, it's not power of 2 */
|
|
b,n LREF(regular_seq)
|
|
sub r0,arg1,temp /* make denominator positive */
|
|
comb,=,n arg1,temp,LREF(regular_seq) /* test against 0x80000000 and 0 */
|
|
ldo -1(temp),retreg /* is there at most one bit set ? */
|
|
and,= temp,retreg,r0 /* if so, the denominator is power of 2 */
|
|
b,n LREF(regular_seq)
|
|
sub r0,arg0,retreg /* negate numerator */
|
|
comb,=,n arg0,retreg,LREF(regular_seq) /* test against 0x80000000 */
|
|
copy retreg,arg0 /* set up arg0, arg1 and temp */
|
|
copy temp,arg1 /* before branching to pow2 */
|
|
b LREF(pow2)
|
|
ldo -1(arg1),temp
|
|
LSYM(regular_seq)
|
|
comib,>>=,n 15,arg1,LREF(small_divisor)
|
|
add,>= 0,arg0,retreg /* move dividend, if retreg < 0, */
|
|
LSYM(normal)
|
|
subi 0,retreg,retreg /* make it positive */
|
|
sub 0,arg1,temp /* clear carry, */
|
|
/* negate the divisor */
|
|
ds 0,temp,0 /* set V-bit to the comple- */
|
|
/* ment of the divisor sign */
|
|
add retreg,retreg,retreg /* shift msb bit into carry */
|
|
ds r0,arg1,temp /* 1st divide step, if no carry */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 2nd divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 3rd divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 4th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 5th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 6th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 7th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 8th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 9th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 10th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 11th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 12th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 13th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 14th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 15th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 16th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 17th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 18th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 19th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 20th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 21st divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 22nd divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 23rd divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 24th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 25th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 26th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 27th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 28th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 29th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 30th divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 31st divide step */
|
|
addc retreg,retreg,retreg /* shift retreg with/into carry */
|
|
ds temp,arg1,temp /* 32nd divide step, */
|
|
addc retreg,retreg,retreg /* shift last retreg bit into retreg */
|
|
xor,>= arg0,arg1,0 /* get correct sign of quotient */
|
|
sub 0,retreg,retreg /* based on operand signs */
|
|
MILLIRETN
|
|
nop
|
|
|
|
LSYM(small_divisor)
|
|
|
|
#if defined(CONFIG_64BIT)
|
|
/* Clear the upper 32 bits of the arg1 register. We are working with */
|
|
/* small divisors (and 32-bit integers) We must not be mislead */
|
|
/* by "1" bits left in the upper 32 bits. */
|
|
depd %r0,31,32,%r25
|
|
#endif
|
|
blr,n arg1,r0
|
|
nop
|
|
/* table for divisor == 0,1, ... ,15 */
|
|
addit,= 0,arg1,r0 /* trap if divisor == 0 */
|
|
nop
|
|
MILLIRET /* divisor == 1 */
|
|
copy arg0,retreg
|
|
MILLI_BEN($$divI_2) /* divisor == 2 */
|
|
nop
|
|
MILLI_BEN($$divI_3) /* divisor == 3 */
|
|
nop
|
|
MILLI_BEN($$divI_4) /* divisor == 4 */
|
|
nop
|
|
MILLI_BEN($$divI_5) /* divisor == 5 */
|
|
nop
|
|
MILLI_BEN($$divI_6) /* divisor == 6 */
|
|
nop
|
|
MILLI_BEN($$divI_7) /* divisor == 7 */
|
|
nop
|
|
MILLI_BEN($$divI_8) /* divisor == 8 */
|
|
nop
|
|
MILLI_BEN($$divI_9) /* divisor == 9 */
|
|
nop
|
|
MILLI_BEN($$divI_10) /* divisor == 10 */
|
|
nop
|
|
b LREF(normal) /* divisor == 11 */
|
|
add,>= 0,arg0,retreg
|
|
MILLI_BEN($$divI_12) /* divisor == 12 */
|
|
nop
|
|
b LREF(normal) /* divisor == 13 */
|
|
add,>= 0,arg0,retreg
|
|
MILLI_BEN($$divI_14) /* divisor == 14 */
|
|
nop
|
|
MILLI_BEN($$divI_15) /* divisor == 15 */
|
|
nop
|
|
|
|
LSYM(negative1)
|
|
sub 0,arg0,retreg /* result is negation of dividend */
|
|
MILLIRET
|
|
addo arg0,arg1,r0 /* trap iff dividend==0x80000000 && divisor==-1 */
|
|
.exit
|
|
.procend
|
|
.end
|
|
#endif
|