1
dnl Intel Pentium-4 mpn_submul_1 -- Multiply a limb vector with a limb and
2
dnl subtract the result from a second limb vector.
4
dnl Copyright 2001, 2002 Free Software Foundation, Inc.
6
dnl This file is part of the GNU MP Library.
8
dnl The GNU MP Library is free software; you can redistribute it and/or
9
dnl modify it under the terms of the GNU Lesser General Public License as
10
dnl published by the Free Software Foundation; either version 2.1 of the
11
dnl License, or (at your option) any later version.
13
dnl The GNU MP Library is distributed in the hope that it will be useful,
14
dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
15
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
dnl Lesser General Public License for more details.
18
dnl You should have received a copy of the GNU Lesser General Public
19
dnl License along with the GNU MP Library; see the file COPYING.LIB. If
20
dnl not, write to the Free Software Foundation, Inc., 59 Temple Place -
21
dnl Suite 330, Boston, MA 02111-1307, USA.
23
include(`../config.m4')
26
C P4: 7 cycles/limb, unstable timing, at least on early Pentium4 silicon
30
C mp_limb_t mpn_submul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
32
C mp_limb_t mpn_submul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
33
C mp_limb_t mult, mp_limb_t carry);
35
C This code is not particularly good at 7 c/l. The dependent chain is only
36
C 4 c/l and there's only 4 MMX unit instructions, so it's not clear why that
37
C speed isn't achieved.
39
C The arrangements made here to get a two instruction dependent chain are
40
C slightly subtle. In the loop the carry (or borrow rather) is a negative
41
C so that a paddq can be used to give a low limb ready to store, and a high
42
C limb ready to become the new carry after a psrlq.
44
C If the carry was a simple twos complement negative then the psrlq shift
45
C would need to bring in 0 bits or 1 bits according to whether the high was
46
C zero or non-zero, since a non-zero value would represent a negative
47
C needing sign extension. That wouldn't be particularly easy to arrange and
48
C certainly would add an instruction to the dependent chain, so instead an
49
C offset is applied so that the high limb will be 0xFFFFFFFF+c. With c in
50
C the range -0xFFFFFFFF to 0, the value 0xFFFFFFFF+c is in the range 0 to
51
C 0xFFFFFFFF and is therefore always positive and can always have 0 bits
52
C shifted in, which is what psrlq does.
54
C The extra 0xFFFFFFFF must be subtracted before c is used, but that can be
55
C done off the dependent chain. The total adjustment then is to add
56
C 0xFFFFFFFF00000000 to offset the new carry, and subtract
57
C 0x00000000FFFFFFFF to remove the offset from the current carry, for a net
58
C add of 0xFFFFFFFE00000001. In the code this is applied to the destination
61
C It's also possible to view the 0xFFFFFFFF adjustment as a ones-complement
62
C negative, which is how it's undone for the return value, but that doesn't
65
defframe(PARAM_CARRY, 20)
66
defframe(PARAM_MULTIPLIER,16)
67
defframe(PARAM_SIZE, 12)
68
defframe(PARAM_SRC, 8)
69
defframe(PARAM_DST, 4)
74
PROLOGUE(mpn_submul_1c)
76
movd PARAM_CARRY, %mm1
80
PROLOGUE(mpn_submul_1)
82
pxor %mm1, %mm1 C initial borrow
88
movd PARAM_MULTIPLIER, %mm7
92
psrlq $32, %mm0 C 0x00000000FFFFFFFF
95
psllq $32, %mm6 C 0xFFFFFFFF00000000
97
psubq %mm0, %mm6 C 0xFFFFFFFE00000001
99
psubq %mm1, %mm0 C 0xFFFFFFFF - borrow
102
C eax src, incrementing
104
C ecx loop counter, decrementing
105
C edx dst, incrementing
107
C mm0 0xFFFFFFFF - borrow
108
C mm6 0xFFFFFFFE00000001
112
movd (%eax), %mm1 C src
114
movd (%edx), %mm2 C dst
115
paddq %mm6, %mm2 C add 0xFFFFFFFE00000001
117
psubq %mm1, %mm2 C prod
118
paddq %mm2, %mm0 C borrow
120
movd %mm0, (%edx) C result