/* $OpenBSD: divrem.m4,v 1.5 2015/06/01 19:02:11 miod Exp $ */
/* $NetBSD: divrem.m4,v 1.7 1996/10/17 03:08:04 cgd Exp $ */
/*
* Copyright (c) 1994, 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*
* Division and remainder.
*
* The use of m4 is modeled after the sparc code, but the algorithm is
* simple binary long division.
*
* Note that the loops could probably benefit from unrolling.
*/
/*
* M4 Parameters
* NAME name of function to generate
* OP OP=div: t10 / t11 -> t12; OP=rem: t10 % t11 -> t12
* S S=true: signed; S=false: unsigned
* WORDSIZE total number of bits
*/
define(A, `t10')
define(B, `t11')
define(RESULT, `t12')
define(BIT, `t0')
define(I, `t1')
define(CC, `t2')
define(T_0, `t3')
ifelse(S, `true', `define(NEG, `t4')')
#include
/*
* These functions use t11 as an input, which makes them incompatible with
* the secureplt calling sequence. The compiler knows about this, and will
* ask for a call through a got relocation. But this can only work if the
* linker omits creating a plt entry for the symbol. In order to achieve
* this, we need to declare it as `notype' instead of `function', which
* means that LEAF(NAME, 0) can't be used as it uses .ent which forces the
* `function' type.
*/
.globl NAME
.type NAME, @notype
.usepv NAME, no
.cfi_startproc
.cfi_return_column ra
NAME:
MCOUNT
lda sp, -64(sp)
.cfi_def_cfa_offset 64
stq BIT, 0(sp)
.cfi_rel_offset BIT, 0
stq I, 8(sp)
.cfi_rel_offset I, 8
stq CC, 16(sp)
.cfi_rel_offset CC, 16
stq T_0, 24(sp)
.cfi_rel_offset T_0, 24
ifelse(S, `true',`dnl
stq NEG, 32(sp)
.cfi_rel_offset NEG, 32
')dnl
stq A, 40(sp)
.cfi_rel_offset A, 40
stq B, 48(sp)
.cfi_rel_offset B, 48
mov zero, RESULT /* Initialize result to zero */
ifelse(S, `true',
`
/* Compute sign of result. If either is negative, this is easy. */
or A, B, NEG /* not the sign, but... */
srl NEG, WORDSIZE - 1, NEG /* rather, or of high bits */
blbc NEG, Ldoit /* neither negative? do it! */
ifelse(OP, `div',
` xor A, B, NEG /* THIS is the sign! */
', ` mov A, NEG /* sign follows A. */
')
srl NEG, WORDSIZE - 1, NEG /* make negation the low bit. */
srl A, WORDSIZE - 1, I /* is A negative? */
blbc I, LnegB /* no. */
/* A is negative; flip it. */
ifelse(WORDSIZE, `32', `
/* top 32 bits may be random junk */
zap A, 0xf0, A
')
subq zero, A, A
srl B, WORDSIZE - 1, I /* is B negative? */
blbc I, Ldoit /* no. */
LnegB:
/* B is definitely negative, no matter how we got here. */
ifelse(WORDSIZE, `32', `
/* top 32 bits may be random junk */
zap B, 0xf0, B
')
subq zero, B, B
Ldoit:
')
ifelse(WORDSIZE, `32', `
/*
* Clear the top 32 bits of each operand, as they may
* sign extension (if negated above), or random junk.
*/
zap A, 0xf0, A
zap B, 0xf0, B
')
/* kill the special cases. */
beq B, Ldotrap /* division by zero! */
cmpult A, B, CC /* A < B? */
/* RESULT is already zero, from above. A is untouched. */
bne CC, Lret_result
cmpeq A, B, CC /* A == B? */
cmovne CC, 1, RESULT
cmovne CC, zero, A
bne CC, Lret_result
/*
* Find out how many bits of zeros are at the beginning of the divisor.
*/
LBbits:
ldiq T_0, 1 /* I = 0; BIT = 1<