dnl Intel Pentium-4 mpn_submul_1 -- Multiply a limb vector with a limb and dnl subtract the result from a second limb vector. dnl Copyright 2001, 2002, 2008, 2010 Free Software Foundation, Inc. dnl This file is part of the GNU MP Library. dnl dnl The GNU MP Library is free software; you can redistribute it and/or modify dnl it under the terms of either: dnl dnl * the GNU Lesser General Public License as published by the Free dnl Software Foundation; either version 3 of the License, or (at your dnl option) any later version. dnl dnl or dnl dnl * the GNU General Public License as published by the Free Software dnl Foundation; either version 2 of the License, or (at your option) any dnl later version. dnl dnl or both in parallel, as here. dnl dnl The GNU MP Library is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License dnl for more details. dnl dnl You should have received copies of the GNU General Public License and the dnl GNU Lesser General Public License along with the GNU MP Library. If not, dnl see https://www.gnu.org/licenses/. include(`../config.m4') C cycles/limb C P6 model 0-8,10-12 - C P6 model 9 (Banias) 6.8 C P6 model 13 (Dothan) 6.9 C P4 model 0-1 (Willamette) ? C P4 model 2 (Northwood) 5.87 C P4 model 3-4 (Prescott) 6.5 C This code represents a step forwards compared to the code available before C GMP 5.1, but it is not carefully tuned for either P6 or P4. In fact, it is C not good for P6. For P4 it saved a bit over 1 c/l for both Northwood and C Prescott compared to the old code. C C The arrangements made here to get a two instruction dependent chain are C slightly subtle. In the loop the carry (or borrow rather) is a negative so C that a paddq can be used to give a low limb ready to store, and a high limb C ready to become the new carry after a psrlq. C C If the carry was a simple twos complement negative then the psrlq shift would C need to bring in 0 bits or 1 bits according to whether the high was zero or C non-zero, since a non-zero value would represent a negative needing sign C extension. That wouldn't be particularly easy to arrange and certainly would C add an instruction to the dependent chain, so instead an offset is applied so C that the high limb will be 0xFFFFFFFF+c. With c in the range -0xFFFFFFFF to C 0, the value 0xFFFFFFFF+c is in the range 0 to 0xFFFFFFFF and is therefore C always positive and can always have 0 bits shifted in, which is what psrlq C does. C C The extra 0xFFFFFFFF must be subtracted before c is used, but that can be C done off the dependent chain. The total adjustment then is to add C 0xFFFFFFFF00000000 to offset the new carry, and subtract 0x00000000FFFFFFFF C to remove the offset from the current carry, for a net add of C 0xFFFFFFFE00000001. In the code this is applied to the destination limb when C fetched. C C It's also possible to view the 0xFFFFFFFF adjustment as a ones-complement C negative, which is how it's undone for the return value, but that doesn't C seem as clear. defframe(PARAM_CARRY, 20) defframe(PARAM_MULTIPLIER,16) defframe(PARAM_SIZE, 12) defframe(PARAM_SRC, 8) defframe(PARAM_DST, 4) TEXT ALIGN(16) PROLOGUE(mpn_submul_1c) deflit(`FRAME',0) movd PARAM_CARRY, %mm1 jmp L(start_1c) EPILOGUE() PROLOGUE(mpn_submul_1) deflit(`FRAME',0) pxor %mm1, %mm1 C initial borrow L(start_1c): mov PARAM_SRC, %eax pcmpeqd %mm0, %mm0 movd PARAM_MULTIPLIER, %mm7 pcmpeqd %mm6, %mm6 mov PARAM_DST, %edx psrlq $32, %mm0 C 0x00000000FFFFFFFF mov PARAM_SIZE, %ecx psllq $32, %mm6 C 0xFFFFFFFF00000000 psubq %mm0, %mm6 C 0xFFFFFFFE00000001 psubq %mm1, %mm0 C 0xFFFFFFFF - borrow movd (%eax), %mm3 C up movd (%edx), %mm4 C rp add $-1, %ecx paddq %mm6, %mm4 C add 0xFFFFFFFE00000001 pmuludq %mm7, %mm3 jnz L(gt1) psubq %mm3, %mm4 C prod paddq %mm4, %mm0 C borrow movd %mm0, (%edx) C result jmp L(rt) L(gt1): movd 4(%eax), %mm1 C up movd 4(%edx), %mm2 C rp add $-1, %ecx jz L(eev) ALIGN(16) L(top): paddq %mm6, %mm2 C add 0xFFFFFFFE00000001 pmuludq %mm7, %mm1 psubq %mm3, %mm4 C prod movd 8(%eax), %mm3 C up paddq %mm4, %mm0 C borrow movd 8(%edx), %mm4 C rp movd %mm0, (%edx) C result psrlq $32, %mm0 add $-1, %ecx jz L(eod) paddq %mm6, %mm4 C add 0xFFFFFFFE00000001 pmuludq %mm7, %mm3 psubq %mm1, %mm2 C prod movd 12(%eax), %mm1 C up paddq %mm2, %mm0 C borrow movd 12(%edx), %mm2 C rp movd %mm0, 4(%edx) C result psrlq $32, %mm0 lea 8(%eax), %eax lea 8(%edx), %edx add $-1, %ecx jnz L(top) L(eev): paddq %mm6, %mm2 C add 0xFFFFFFFE00000001 pmuludq %mm7, %mm1 psubq %mm3, %mm4 C prod paddq %mm4, %mm0 C borrow movd %mm0, (%edx) C result psrlq $32, %mm0 psubq %mm1, %mm2 C prod paddq %mm2, %mm0 C borrow movd %mm0, 4(%edx) C result L(rt): psrlq $32, %mm0 movd %mm0, %eax not %eax emms ret L(eod): paddq %mm6, %mm4 C add 0xFFFFFFFE00000001 pmuludq %mm7, %mm3 psubq %mm1, %mm2 C prod paddq %mm2, %mm0 C borrow movd %mm0, 4(%edx) C result psrlq $32, %mm0 psubq %mm3, %mm4 C prod paddq %mm4, %mm0 C borrow movd %mm0, 8(%edx) C result jmp L(rt) EPILOGUE()