mpir/mpn/x86/longlong_inc.h
2011-08-30 23:57:26 +00:00

168 lines
5.6 KiB
C

/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
Copyright 1991, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, 2002, 2003,
2004, 2005 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version.
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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this file; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
#if defined (__GNUC__) || defined(INTEL_COMPILER)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addl %5,%k1\n\tadcl %3,%k0" \
: "=r" (sh), "=&r" (sl) \
: "0" ((USItype)(ah)), "g" ((USItype)(bh)), \
"%1" ((USItype)(al)), "g" ((USItype)(bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%k1\n\tsbbl %3,%k0" \
: "=r" (sh), "=&r" (sl) \
: "0" ((USItype)(ah)), "g" ((USItype)(bh)), \
"1" ((USItype)(al)), "g" ((USItype)(bl)))
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mull %3" \
: "=a" (w0), "=d" (w1) \
: "%0" ((USItype)(u)), "rm" ((USItype)(v)))
#define udiv_qrnnd(q, r, n1, n0, dx) /* d renamed to dx avoiding "=d" */\
__asm__ ("divl %4" /* stringification in K&R C */ \
: "=a" (q), "=d" (r) \
: "0" ((USItype)(n0)), "1" ((USItype)(n1)), "rm" ((USItype)(dx)))
#if __GMP_GNUC_PREREQ (3,4) /* using bsrl */
#define count_leading_zeros(count,x) count_leading_zeros_gcc_clz(count,x)
#endif /* gcc clz */
#ifndef count_leading_zeros
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
ASSERT ((x) != 0); \
__asm__ ("bsrl %1,%0" : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#endif /* asm bsrl */
#if __GMP_GNUC_PREREQ (3,4) /* using bsfl */
#define count_trailing_zeros(count,x) count_trailing_zeros_gcc_ctz(count,x)
#endif /* gcc ctz */
#ifndef count_trailing_zeros
#define count_trailing_zeros(count, x) \
do { \
ASSERT ((x) != 0); \
__asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))); \
} while (0)
#endif /* asm bsfl */
/* ASM_L gives a local label for a gcc asm block, for use when temporary
local labels like "1:" might not be available, which is the case for
instance on the x86s (the SCO assembler doesn't support them).
The label generated is made unique by including "%=" which is a unique
number for each insn. This ensures the same name can be used in multiple
asm blocks, perhaps via a macro. Since jumps between asm blocks are not
allowed there's no need for a label to be usable outside a single
block. */
#define ASM_L(name) LSYM_PREFIX "asm_%=_" #name
#if ! WANT_ASSERT
/* Better flags handling than the generic C gives on i386, saving a few
bytes of code and maybe a cycle or two. */
#define MPN_IORD_U(ptr, incr, aors) \
do { \
mp_ptr __ptr_dummy; \
if (__builtin_constant_p (incr) && (incr) == 1) \
{ \
__asm__ __volatile__ \
("\n" ASM_L(top) ":\n" \
"\t" aors " $1, (%0)\n" \
"\tleal 4(%0),%0\n" \
"\tjc " ASM_L(top) \
: "=r" (__ptr_dummy) \
: "0" (ptr) \
: "memory"); \
} \
else \
{ \
__asm__ __volatile__ \
( aors " %2,(%0)\n" \
"\tjnc " ASM_L(done) "\n" \
ASM_L(top) ":\n" \
"\t" aors " $1,4(%0)\n" \
"\tleal 4(%0),%0\n" \
"\tjc " ASM_L(top) "\n" \
ASM_L(done) ":\n" \
: "=r" (__ptr_dummy) \
: "0" (ptr), \
"ri" (incr) \
: "memory"); \
} \
} while (0)
#ifndef MPN_INCR_U
#define MPN_INCR_U(ptr, size, incr) MPN_IORD_U (ptr, incr, "addl")
#endif
#ifndef MPN_DECR_U
#define MPN_DECR_U(ptr, size, incr) MPN_IORD_U (ptr, incr, "subl")
#endif
#ifndef mpn_incr_u
#define mpn_incr_u(ptr, incr) MPN_INCR_U (ptr, 0, incr)
#endif
#ifndef mpn_decr_u
#define mpn_decr_u(ptr, incr) MPN_DECR_U (ptr, 0, incr)
#endif
#endif
#endif
#if defined (__GNUC__)
#if __GMP_GNUC_PREREQ (3,1)
#define __GMP_qm "=Qm"
#define __GMP_q "=Q"
#else
#define __GMP_qm "=qm"
#define __GMP_q "=q"
#endif
#ifndef ULONG_PARITY
#define ULONG_PARITY(p, n) \
do { \
char __p; \
unsigned long __n = (n); \
__n ^= (__n >> 16); \
__asm__ ("xorb %h1, %b1\n\t" \
"setpo %0" \
: __GMP_qm (__p), __GMP_q (__n) \
: "1" (__n)); \
(p) = __p; \
} while (0)
#endif
#endif
/* bswap is available on i486 and up and is fast. A combination rorw $8 /
roll $16 / rorw $8 is used in glibc for plain i386 (and in the linux
kernel with xchgb instead of rorw), but this is not done here, because
i386 means generic x86 and mixing word and dword operations will cause
partial register stalls on P6 chips. */
/* Either drop support for i386 or comment this out
#if !defined(BSWAP_LIMB) && defined (__GNUC__) && ! HAVE_HOST_CPU_i386
#define BSWAP_LIMB(dst, src) \
do { \
__asm__ ("bswap %0" : "=r" (dst) : "0" (src)); \
} while (0)
#endif
*/