Upload Tizen:Base source
[external/gmp.git] / mpn / x86 / pentium4 / sse2 / submul_1.asm
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.
3
4 dnl  Copyright 2001, 2002 Free Software Foundation, Inc.
5 dnl
6 dnl  This file is part of the GNU MP Library.
7 dnl
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 3 of the
11 dnl  License, or (at your option) any later version.
12 dnl
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.
17 dnl
18 dnl  You should have received a copy of the GNU Lesser General Public License
19 dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
20
21 include(`../config.m4')
22
23
24 C P4: 7 cycles/limb, unstable timing, at least on early Pentium4 silicon
25 C     (stepping 10).
26
27
28 C mp_limb_t mpn_submul_1 (mp_ptr dst, mp_srcptr src, mp_size_t size,
29 C                         mp_limb_t mult);
30 C mp_limb_t mpn_submul_1c (mp_ptr dst, mp_srcptr src, mp_size_t size,
31 C                          mp_limb_t mult, mp_limb_t carry);
32 C
33 C This code is not particularly good at 7 c/l.  The dependent chain is only
34 C 4 c/l and there's only 4 MMX unit instructions, so it's not clear why that
35 C speed isn't achieved.
36 C
37 C The arrangements made here to get a two instruction dependent chain are
38 C slightly subtle.  In the loop the carry (or borrow rather) is a negative
39 C so that a paddq can be used to give a low limb ready to store, and a high
40 C limb ready to become the new carry after a psrlq.
41 C
42 C If the carry was a simple twos complement negative then the psrlq shift
43 C would need to bring in 0 bits or 1 bits according to whether the high was
44 C zero or non-zero, since a non-zero value would represent a negative
45 C needing sign extension.  That wouldn't be particularly easy to arrange and
46 C certainly would add an instruction to the dependent chain, so instead an
47 C offset is applied so that the high limb will be 0xFFFFFFFF+c.  With c in
48 C the range -0xFFFFFFFF to 0, the value 0xFFFFFFFF+c is in the range 0 to
49 C 0xFFFFFFFF and is therefore always positive and can always have 0 bits
50 C shifted in, which is what psrlq does.
51 C
52 C The extra 0xFFFFFFFF must be subtracted before c is used, but that can be
53 C done off the dependent chain.  The total adjustment then is to add
54 C 0xFFFFFFFF00000000 to offset the new carry, and subtract
55 C 0x00000000FFFFFFFF to remove the offset from the current carry, for a net
56 C add of 0xFFFFFFFE00000001.  In the code this is applied to the destination
57 C limb when fetched.
58 C
59 C It's also possible to view the 0xFFFFFFFF adjustment as a ones-complement
60 C negative, which is how it's undone for the return value, but that doesn't
61 C seem as clear.
62
63 defframe(PARAM_CARRY,     20)
64 defframe(PARAM_MULTIPLIER,16)
65 defframe(PARAM_SIZE,      12)
66 defframe(PARAM_SRC,       8)
67 defframe(PARAM_DST,       4)
68
69         TEXT
70         ALIGN(16)
71
72 PROLOGUE(mpn_submul_1c)
73 deflit(`FRAME',0)
74         movd    PARAM_CARRY, %mm1
75         jmp     L(start_1c)
76 EPILOGUE()
77
78 PROLOGUE(mpn_submul_1)
79 deflit(`FRAME',0)
80         pxor    %mm1, %mm1              C initial borrow
81
82 L(start_1c):
83         movl    PARAM_SRC, %eax
84         pcmpeqd %mm0, %mm0
85
86         movd    PARAM_MULTIPLIER, %mm7
87         pcmpeqd %mm6, %mm6
88
89         movl    PARAM_DST, %edx
90         psrlq   $32, %mm0               C 0x00000000FFFFFFFF
91
92         movl    PARAM_SIZE, %ecx
93         psllq   $32, %mm6               C 0xFFFFFFFF00000000
94
95         psubq   %mm0, %mm6              C 0xFFFFFFFE00000001
96
97         psubq   %mm1, %mm0              C 0xFFFFFFFF - borrow
98
99
100         C eax   src, incrementing
101         C ebx
102         C ecx   loop counter, decrementing
103         C edx   dst, incrementing
104         C
105         C mm0   0xFFFFFFFF - borrow
106         C mm6   0xFFFFFFFE00000001
107         C mm7   multiplier
108
109 L(loop):
110         movd    (%eax), %mm1            C src
111         leal    4(%eax), %eax
112         movd    (%edx), %mm2            C dst
113         paddq   %mm6, %mm2              C add 0xFFFFFFFE00000001
114         pmuludq %mm7, %mm1
115         psubq   %mm1, %mm2              C prod
116         paddq   %mm2, %mm0              C borrow
117         subl    $1, %ecx
118         movd    %mm0, (%edx)            C result
119         psrlq   $32, %mm0
120         leal    4(%edx), %edx
121         jnz     L(loop)
122
123         movd    %mm0, %eax
124         notl    %eax
125         emms
126         ret
127
128 EPILOGUE()