mirror of https://gitee.com/openkylin/linux.git
236 lines
8.4 KiB
ArmAsm
236 lines
8.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_divU
|
|
/* ROUTINE: $$divU
|
|
.
|
|
. Single precision divide for unsigned integers.
|
|
.
|
|
. Quotient is truncated towards zero.
|
|
. Traps on divide by zero.
|
|
|
|
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
|
|
. Changes memory at the following places:
|
|
. NONE
|
|
|
|
PERMISSIBLE CONTEXT:
|
|
. Unwindable.
|
|
. Does not create a stack frame.
|
|
. Suitable for internal or external millicode.
|
|
. Assumes the special millicode register conventions.
|
|
|
|
DISCUSSION:
|
|
. Branchs to other millicode routines using BE:
|
|
. $$divU_# for 3,5,6,7,9,10,12,14,15
|
|
.
|
|
. For selected small divisors calls the special divide by constant
|
|
. routines written by Karl Pettis. These are: 3,5,6,7,9,10,12,14,15. */
|
|
|
|
RDEFINE(temp,r1)
|
|
RDEFINE(retreg,ret1) /* r29 */
|
|
RDEFINE(temp1,arg0)
|
|
SUBSPA_MILLI_DIV
|
|
ATTR_MILLI
|
|
.export $$divU,millicode
|
|
.import $$divU_3,millicode
|
|
.import $$divU_5,millicode
|
|
.import $$divU_6,millicode
|
|
.import $$divU_7,millicode
|
|
.import $$divU_9,millicode
|
|
.import $$divU_10,millicode
|
|
.import $$divU_12,millicode
|
|
.import $$divU_14,millicode
|
|
.import $$divU_15,millicode
|
|
.proc
|
|
.callinfo millicode
|
|
.entry
|
|
GSYM($$divU)
|
|
/* The subtract is not nullified since it does no harm and can be used
|
|
by the two cases that branch back to "normal". */
|
|
ldo -1(arg1),temp /* is there at most one bit set ? */
|
|
and,= arg1,temp,r0 /* if so, denominator is power of 2 */
|
|
b LREF(regular_seq)
|
|
addit,= 0,arg1,0 /* trap for zero dvr */
|
|
copy arg0,retreg
|
|
extru,= arg1,15,16,temp /* test denominator with 0xffff0000 */
|
|
extru 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 */
|
|
extru 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 */
|
|
extru retreg,27,28,retreg /* retreg = retreg >> 4 */
|
|
and,= arg1,temp1,r0 /* test denominator with 0xcc */
|
|
extru retreg,29,30,retreg /* retreg = retreg >> 2 */
|
|
and,= arg1,temp,r0 /* test denominator with 0xaa */
|
|
extru retreg,30,31,retreg /* retreg = retreg >> 1 */
|
|
MILLIRETN
|
|
nop
|
|
LSYM(regular_seq)
|
|
comib,>= 15,arg1,LREF(special_divisor)
|
|
subi 0,arg1,temp /* clear carry, negate the divisor */
|
|
ds r0,temp,r0 /* set V-bit to 1 */
|
|
LSYM(normal)
|
|
add arg0,arg0,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, */
|
|
MILLIRET
|
|
addc retreg,retreg,retreg /* shift last retreg bit into retreg */
|
|
|
|
/* Handle the cases where divisor is a small constant or has high bit on. */
|
|
LSYM(special_divisor)
|
|
/* blr arg1,r0 */
|
|
/* comib,>,n 0,arg1,LREF(big_divisor) ; nullify previous instruction */
|
|
|
|
/* Pratap 8/13/90. The 815 Stirling chip set has a bug that prevents us from
|
|
generating such a blr, comib sequence. A problem in nullification. So I
|
|
rewrote this code. */
|
|
|
|
#if defined(CONFIG_64BIT)
|
|
/* Clear the upper 32 bits of the arg1 register. We are working with
|
|
small divisors (and 32-bit unsigned integers) We must not be mislead
|
|
by "1" bits left in the upper 32 bits. */
|
|
depd %r0,31,32,%r25
|
|
#endif
|
|
comib,> 0,arg1,LREF(big_divisor)
|
|
nop
|
|
blr arg1,r0
|
|
nop
|
|
|
|
LSYM(zero_divisor) /* this label is here to provide external visibility */
|
|
addit,= 0,arg1,0 /* trap for zero dvr */
|
|
nop
|
|
MILLIRET /* divisor == 1 */
|
|
copy arg0,retreg
|
|
MILLIRET /* divisor == 2 */
|
|
extru arg0,30,31,retreg
|
|
MILLI_BEN($$divU_3) /* divisor == 3 */
|
|
nop
|
|
MILLIRET /* divisor == 4 */
|
|
extru arg0,29,30,retreg
|
|
MILLI_BEN($$divU_5) /* divisor == 5 */
|
|
nop
|
|
MILLI_BEN($$divU_6) /* divisor == 6 */
|
|
nop
|
|
MILLI_BEN($$divU_7) /* divisor == 7 */
|
|
nop
|
|
MILLIRET /* divisor == 8 */
|
|
extru arg0,28,29,retreg
|
|
MILLI_BEN($$divU_9) /* divisor == 9 */
|
|
nop
|
|
MILLI_BEN($$divU_10) /* divisor == 10 */
|
|
nop
|
|
b LREF(normal) /* divisor == 11 */
|
|
ds r0,temp,r0 /* set V-bit to 1 */
|
|
MILLI_BEN($$divU_12) /* divisor == 12 */
|
|
nop
|
|
b LREF(normal) /* divisor == 13 */
|
|
ds r0,temp,r0 /* set V-bit to 1 */
|
|
MILLI_BEN($$divU_14) /* divisor == 14 */
|
|
nop
|
|
MILLI_BEN($$divU_15) /* divisor == 15 */
|
|
nop
|
|
|
|
/* Handle the case where the high bit is on in the divisor.
|
|
Compute: if( dividend>=divisor) quotient=1; else quotient=0;
|
|
Note: dividend>==divisor iff dividend-divisor does not borrow
|
|
and not borrow iff carry. */
|
|
LSYM(big_divisor)
|
|
sub arg0,arg1,r0
|
|
MILLIRET
|
|
addc r0,r0,retreg
|
|
.exit
|
|
.procend
|
|
.end
|
|
#endif
|