1/* Test mpn_add_1 and mpn_sub_1.
2
3Copyright 2001, 2002 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the GNU MP Library test suite.  If not, see https://www.gnu.org/licenses/.  */
19
20#include <stdio.h>
21#include <stdlib.h>
22
23#include "gmp-impl.h"
24#include "tests.h"
25
26
27#define M      GMP_NUMB_MAX
28#define ASIZE  10
29#define MAGIC  0x1234
30
31#define SETUP()                         \
32  do {                                  \
33    refmpn_random (got, data[i].size);  \
34    got[data[i].size] = MAGIC;          \
35  } while (0)
36
37#define SETUP_INPLACE()                                 \
38  do {                                                  \
39    refmpn_copyi (got, data[i].src, data[i].size);      \
40    got[data[i].size] = MAGIC;                          \
41  } while (0)
42
43#define VERIFY(name)                            \
44  do {                                          \
45    verify (name, i, data[i].src, data[i].n,    \
46            got_c, data[i].want_c,              \
47            got, data[i].want, data[i].size);   \
48  } while (0)
49
50typedef mp_limb_t (*mpn_aors_1_t) (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
51mpn_aors_1_t fudge (mpn_aors_1_t);
52
53
54void
55verify (const char *name, int i,
56        mp_srcptr src, mp_limb_t n,
57        mp_limb_t got_c, mp_limb_t want_c,
58        mp_srcptr got, mp_srcptr want, mp_size_t size)
59{
60  if (got[size] != MAGIC)
61    {
62      printf ("Overwrite at %s i=%d\n", name, i);
63      abort ();
64    }
65
66  if (got_c != want_c || ! refmpn_equal_anynail (got, want, size))
67    {
68      printf ("Wrong at %s i=%d size=%ld\n", name, i, size);
69      mpn_trace ("   src", src,  size);
70      mpn_trace ("     n", &n,   (mp_size_t) 1);
71      mpn_trace ("   got", got,  size);
72      mpn_trace ("  want", want, size);
73      mpn_trace (" got c", &got_c,  (mp_size_t) 1);
74      mpn_trace ("want c", &want_c, (mp_size_t) 1);
75      abort ();
76    }
77}
78
79
80void
81check_add_1 (void)
82{
83  static const struct {
84    mp_size_t        size;
85    mp_limb_t        n;
86    const mp_limb_t  src[ASIZE];
87    mp_limb_t        want_c;
88    const mp_limb_t  want[ASIZE];
89  } data[] = {
90    { 1, 0, { 0 },  0, { 0 } },
91    { 1, 0, { 1 },  0, { 1 } },
92    { 1, 1, { 0 },  0, { 1 } },
93    { 1, 0, { M },  0, { M } },
94    { 1, M, { 0 },  0, { M } },
95    { 1, 1, { 123 }, 0, { 124 } },
96
97    { 1, 1, { M },  1, { 0 } },
98    { 1, M, { 1 },  1, { 0 } },
99    { 1, M, { M },  1, { M-1 } },
100
101    { 2, 0, { 0, 0 },  0, { 0, 0 } },
102    { 2, 0, { 1, 0 },  0, { 1, 0 } },
103    { 2, 1, { 0, 0 },  0, { 1, 0 } },
104    { 2, 0, { M, 0 },  0, { M, 0 } },
105    { 2, M, { 0, 0 },  0, { M, 0 } },
106    { 2, 1, { M, 0 },  0, { 0, 1 } },
107    { 2, M, { 1, 0 },  0, { 0, 1 } },
108    { 2, M, { M, 0 },  0, { M-1, 1 } },
109    { 2, M, { M, 0 },  0, { M-1, 1 } },
110
111    { 2, 1, { M, M },  1, { 0, 0 } },
112    { 2, M, { 1, M },  1, { 0, 0 } },
113    { 2, M, { M, M },  1, { M-1, 0 } },
114    { 2, M, { M, M },  1, { M-1, 0 } },
115
116    { 3, 1, { M, M, M },  1, { 0, 0, 0 } },
117    { 3, M, { 1, M, M },  1, { 0, 0, 0 } },
118    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
119    { 3, M, { M, M, M },  1, { M-1, 0, 0 } },
120
121    { 4, 1, { M, M, M, M },  1, { 0, 0, 0, 0 } },
122    { 4, M, { 1, M, M, M },  1, { 0, 0, 0, 0 } },
123    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
124    { 4, M, { M, M, M, M },  1, { M-1, 0, 0, 0 } },
125
126    { 4, M, { M, 0,   M, M },  0, { M-1, 1, M, M } },
127    { 4, M, { M, M-1, M, M },  0, { M-1, M, M, M } },
128
129    { 4, M, { M, M, 0,   M },  0, { M-1, 0, 1, M } },
130    { 4, M, { M, M, M-1, M },  0, { M-1, 0, M, M } },
131  };
132
133  mp_limb_t  got[ASIZE];
134  mp_limb_t  got_c;
135  /* mpn_sec_add_a_itch(n) <= n */
136  mp_limb_t  scratch[ASIZE];
137  int        i;
138
139  for (i = 0; i < numberof (data); i++)
140    {
141      SETUP ();
142      got_c = mpn_add_1 (got, data[i].src, data[i].size, data[i].n);
143      VERIFY ("check_add_1 (separate)");
144
145      SETUP_INPLACE ();
146      got_c = mpn_add_1 (got, got, data[i].size, data[i].n);
147      VERIFY ("check_add_1 (in-place)");
148
149      SETUP ();
150      scratch [mpn_sec_add_1_itch(data[i].size)] = MAGIC;
151      got_c = mpn_sec_add_1 (got, data[i].src, data[i].size, data[i].n, scratch);
152      got_c ^= scratch [mpn_sec_add_1_itch(data[i].size)] ^ MAGIC;
153      VERIFY ("check_sec_add_1 (separate)");
154
155      SETUP_INPLACE ();
156      got_c = mpn_sec_add_1 (got, got, data[i].size, data[i].n, scratch);
157      VERIFY ("check_sec_add_1 (in-place)");
158
159      if (data[i].n == 1)
160        {
161          SETUP ();
162          got_c = mpn_add_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
163          VERIFY ("check_add_1 (separate, const 1)");
164
165          SETUP_INPLACE ();
166          got_c = mpn_add_1 (got, got, data[i].size, CNST_LIMB(1));
167          VERIFY ("check_add_1 (in-place, const 1)");
168
169          SETUP ();
170          got_c = mpn_sec_add_1 (got, data[i].src, data[i].size,
171				 CNST_LIMB(1), scratch);
172          VERIFY ("check_sec_add_1 (separate, const 1)");
173
174          SETUP_INPLACE ();
175          got_c = mpn_sec_add_1 (got, got, data[i].size,
176				 CNST_LIMB(1), scratch);
177          VERIFY ("check_sec_add_1 (in-place, const 1)");
178        }
179
180      /* Same again on functions, not inlines. */
181      SETUP ();
182      got_c = (*fudge(mpn_add_1)) (got, data[i].src, data[i].size, data[i].n);
183      VERIFY ("check_add_1 (function, separate)");
184
185      SETUP_INPLACE ();
186      got_c = (*fudge(mpn_add_1)) (got, got, data[i].size, data[i].n);
187      VERIFY ("check_add_1 (function, in-place)");
188    }
189}
190
191void
192check_sub_1 (void)
193{
194  static const struct {
195    mp_size_t        size;
196    mp_limb_t        n;
197    const mp_limb_t  src[ASIZE];
198    mp_limb_t        want_c;
199    const mp_limb_t  want[ASIZE];
200  } data[] = {
201    { 1, 0, { 0 },  0, { 0 } },
202    { 1, 0, { 1 },  0, { 1 } },
203    { 1, 1, { 1 },  0, { 0 } },
204    { 1, 0, { M },  0, { M } },
205    { 1, 1, { M },  0, { M-1 } },
206    { 1, 1, { 123 }, 0, { 122 } },
207
208    { 1, 1, { 0 },  1, { M } },
209    { 1, M, { 0 },  1, { 1 } },
210
211    { 2, 0, { 0, 0 },  0, { 0, 0 } },
212    { 2, 0, { 1, 0 },  0, { 1, 0 } },
213    { 2, 1, { 1, 0 },  0, { 0, 0 } },
214    { 2, 0, { M, 0 },  0, { M, 0 } },
215    { 2, 1, { M, 0 },  0, { M-1, 0 } },
216    { 2, 1, { 123, 0 }, 0, { 122, 0 } },
217
218    { 2, 1, { 0, 0 },  1, { M, M } },
219    { 2, M, { 0, 0 },  1, { 1, M } },
220
221    { 3, 0, { 0,   0, 0 },  0, { 0,   0, 0 } },
222    { 3, 0, { 123, 0, 0 },  0, { 123, 0, 0 } },
223
224    { 3, 1, { 0, 0, 0 },  1, { M, M, M } },
225    { 3, M, { 0, 0, 0 },  1, { 1, M, M } },
226
227    { 4, 1, { 0, 0, 0, 0 },  1, { M, M, M, M } },
228    { 4, M, { 0, 0, 0, 0 },  1, { 1, M, M, M } },
229
230    { 4, 1, { 0, 0, 1,   42 },  0, { M, M, 0,   42 } },
231    { 4, M, { 0, 0, 123, 24 },  0, { 1, M, 122, 24 } },
232  };
233
234  mp_limb_t  got[ASIZE];
235  mp_limb_t  got_c;
236  /* mpn_sec_sub_1_itch(n) <= n */
237  mp_limb_t  scratch[ASIZE];
238  int        i;
239
240  for (i = 0; i < numberof (data); i++)
241    {
242      SETUP ();
243      got_c = mpn_sub_1 (got, data[i].src, data[i].size, data[i].n);
244      VERIFY ("check_sub_1 (separate)");
245
246      SETUP_INPLACE ();
247      got_c = mpn_sub_1 (got, got, data[i].size, data[i].n);
248      VERIFY ("check_sub_1 (in-place)");
249
250      SETUP ();
251      scratch [mpn_sec_sub_1_itch(data[i].size)] = MAGIC;
252      got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size, data[i].n, scratch);
253      got_c ^= scratch [mpn_sec_sub_1_itch(data[i].size)] ^ MAGIC;
254      VERIFY ("check_sec_sub_1 (separate)");
255
256      SETUP_INPLACE ();
257      got_c = mpn_sec_sub_1 (got, got, data[i].size, data[i].n, scratch);
258      VERIFY ("check_sec_sub_1 (in-place)");
259
260      if (data[i].n == 1)
261        {
262          SETUP ();
263          got_c = mpn_sub_1 (got, data[i].src, data[i].size, CNST_LIMB(1));
264          VERIFY ("check_sub_1 (separate, const 1)");
265
266          SETUP_INPLACE ();
267          got_c = mpn_sub_1 (got, got, data[i].size, CNST_LIMB(1));
268          VERIFY ("check_sub_1 (in-place, const 1)");
269
270          SETUP ();
271          got_c = mpn_sec_sub_1 (got, data[i].src, data[i].size,
272				 CNST_LIMB(1), scratch);
273          VERIFY ("check_sec_sub_1 (separate, const 1)");
274
275          SETUP_INPLACE ();
276          got_c = mpn_sec_sub_1 (got, got, data[i].size,
277				 CNST_LIMB(1), scratch);
278          VERIFY ("check_sec_sub_1 (in-place, const 1)");
279        }
280
281      /* Same again on functions, not inlines. */
282      SETUP ();
283      got_c = (*fudge(mpn_sub_1)) (got, data[i].src, data[i].size, data[i].n);
284      VERIFY ("check_sub_1 (function, separate)");
285
286      SETUP_INPLACE ();
287      got_c = (*fudge(mpn_sub_1)) (got, got, data[i].size, data[i].n);
288      VERIFY ("check_sub_1 (function, in-place)");
289    }
290}
291
292/* Try to prevent the optimizer inlining. */
293mpn_aors_1_t
294fudge (mpn_aors_1_t f)
295{
296  return f;
297}
298
299int
300main (void)
301{
302  tests_start ();
303  mp_trace_base = -16;
304
305  check_add_1 ();
306  check_sub_1 ();
307
308  tests_end ();
309  exit (0);
310}
311