Coverage Report

Created: 2025-07-23 06:43

/src/gmp/mpn/submul_1.c
Line
Count
Source
1
/* mpn_submul_1 -- multiply the N long limb vector pointed to by UP by VL,
2
   subtract the N least significant limbs of the product from the limb
3
   vector pointed to by RP.  Return the most significant limb of the
4
   product, adjusted for carry-out from the subtraction.
5
6
Copyright 1992-1994, 1996, 2000, 2002, 2004 Free Software Foundation, Inc.
7
8
This file is part of the GNU MP Library.
9
10
The GNU MP Library is free software; you can redistribute it and/or modify
11
it under the terms of either:
12
13
  * the GNU Lesser General Public License as published by the Free
14
    Software Foundation; either version 3 of the License, or (at your
15
    option) any later version.
16
17
or
18
19
  * the GNU General Public License as published by the Free Software
20
    Foundation; either version 2 of the License, or (at your option) any
21
    later version.
22
23
or both in parallel, as here.
24
25
The GNU MP Library is distributed in the hope that it will be useful, but
26
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
27
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
28
for more details.
29
30
You should have received copies of the GNU General Public License and the
31
GNU Lesser General Public License along with the GNU MP Library.  If not,
32
see https://www.gnu.org/licenses/.  */
33
34
#include "gmp-impl.h"
35
#include "longlong.h"
36
37
38
#if GMP_NAIL_BITS == 0
39
40
mp_limb_t
41
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
42
53.5M
{
43
53.5M
  mp_limb_t u0, crec, c, p1, p0, r0;
44
45
53.5M
  ASSERT (n >= 1);
46
53.5M
  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
47
48
53.5M
  crec = 0;
49
53.5M
  do
50
721M
    {
51
721M
      u0 = *up++;
52
721M
      umul_ppmm (p1, p0, u0, v0);
53
54
721M
      r0 = *rp;
55
56
721M
      p0 = r0 - p0;
57
721M
      c = r0 < p0;
58
59
721M
      p1 = p1 + c;
60
61
721M
      r0 = p0 - crec;   /* cycle 0, 3, ... */
62
721M
      c = p0 < r0;    /* cycle 1, 4, ... */
63
64
721M
      crec = p1 + c;    /* cycle 2, 5, ... */
65
66
721M
      *rp++ = r0;
67
721M
    }
68
721M
  while (--n != 0);
69
70
53.5M
  return crec;
71
53.5M
}
72
73
#endif
74
75
#if GMP_NAIL_BITS == 1
76
77
mp_limb_t
78
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
79
{
80
  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, cl, xl, c1, c2, c3;
81
82
  ASSERT (n >= 1);
83
  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
84
  ASSERT_MPN (rp, n);
85
  ASSERT_MPN (up, n);
86
  ASSERT_LIMB (v0);
87
88
  shifted_v0 = v0 << GMP_NAIL_BITS;
89
  cl = 0;
90
  prev_p1 = 0;
91
  do
92
    {
93
      u0 = *up++;
94
      r0 = *rp;
95
      umul_ppmm (p1, p0, u0, shifted_v0);
96
      p0 >>= GMP_NAIL_BITS;
97
      SUBC_LIMB (c1, xl, r0, prev_p1);
98
      SUBC_LIMB (c2, xl, xl, p0);
99
      SUBC_LIMB (c3, xl, xl, cl);
100
      cl = c1 + c2 + c3;
101
      *rp++ = xl;
102
      prev_p1 = p1;
103
    }
104
  while (--n != 0);
105
106
  return prev_p1 + cl;
107
}
108
109
#endif
110
111
#if GMP_NAIL_BITS >= 2
112
113
mp_limb_t
114
mpn_submul_1 (mp_ptr rp, mp_srcptr up, mp_size_t n, mp_limb_t v0)
115
{
116
  mp_limb_t shifted_v0, u0, r0, p0, p1, prev_p1, xw, cl, xl;
117
118
  ASSERT (n >= 1);
119
  ASSERT (MPN_SAME_OR_SEPARATE_P (rp, up, n));
120
  ASSERT_MPN (rp, n);
121
  ASSERT_MPN (up, n);
122
  ASSERT_LIMB (v0);
123
124
  shifted_v0 = v0 << GMP_NAIL_BITS;
125
  cl = 0;
126
  prev_p1 = 0;
127
  do
128
    {
129
      u0 = *up++;
130
      r0 = *rp;
131
      umul_ppmm (p1, p0, u0, shifted_v0);
132
      p0 >>= GMP_NAIL_BITS;
133
      xw = r0 - (prev_p1 + p0) + cl;
134
      cl = (mp_limb_signed_t) xw >> GMP_NUMB_BITS; /* FIXME: non-portable */
135
      xl = xw & GMP_NUMB_MASK;
136
      *rp++ = xl;
137
      prev_p1 = p1;
138
    }
139
  while (--n != 0);
140
141
  return prev_p1 - cl;
142
}
143
144
#endif