Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / gmp-utils.c
CommitLineData
b34c74ab
JB
1/* Copyright (C) 2019-2020 Free Software Foundation, Inc.
2
3 This file is part of GDB.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17
18#include "gmp-utils.h"
19
20/* See gmp-utils.h. */
21
987b6703
JB
22std::string
23gmp_string_printf (const char *fmt, ...)
b34c74ab
JB
24{
25 va_list vp;
b34c74ab
JB
26
27 va_start (vp, fmt);
987b6703 28 int size = gmp_vsnprintf (NULL, 0, fmt, vp);
b34c74ab
JB
29 va_end (vp);
30
987b6703
JB
31 std::string str (size, '\0');
32
33 /* C++11 and later guarantee std::string uses contiguous memory and
34 always includes the terminating '\0'. */
35 va_start (vp, fmt);
36 gmp_vsprintf (&str[0], fmt, vp);
37 va_end (vp);
38
39 return str;
b34c74ab
JB
40}
41
42/* See gmp-utils.h. */
43
44void
c9f0b43f 45gdb_mpz::read (gdb::array_view<const gdb_byte> buf, enum bfd_endian byte_order,
b34c74ab
JB
46 bool unsigned_p)
47{
c9f0b43f 48 mpz_import (val, 1 /* count */, -1 /* order */, buf.size () /* size */,
b34c74ab 49 byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
c9f0b43f 50 0 /* nails */, buf.data () /* op */);
b34c74ab
JB
51
52 if (!unsigned_p)
53 {
54 /* The value was imported as if it was a positive value,
55 as mpz_import does not handle signs. If the original value
56 was in fact negative, we need to adjust VAL accordingly. */
57 gdb_mpz max;
58
3c7ba803 59 mpz_ui_pow_ui (max.val, 2, buf.size () * HOST_CHAR_BIT - 1);
b34c74ab
JB
60 if (mpz_cmp (val, max.val) >= 0)
61 mpz_submul_ui (val, max.val, 2);
62 }
63}
64
65/* See gmp-utils.h. */
66
67void
c9f0b43f 68gdb_mpz::write (gdb::array_view<gdb_byte> buf, enum bfd_endian byte_order,
b34c74ab
JB
69 bool unsigned_p) const
70{
71 gdb_mpz exported_val (val);
72
73 if (mpz_cmp_ui (val, 0) < 0)
74 {
75 /* mpz_export does not handle signed values, so create a positive
76 value whose bit representation as an unsigned of the same length
77 would be the same as our negative value. */
78 gdb_mpz neg_offset;
79
3c7ba803 80 mpz_ui_pow_ui (neg_offset.val, 2, buf.size () * HOST_CHAR_BIT);
b34c74ab
JB
81 mpz_add (exported_val.val, exported_val.val, neg_offset.val);
82 }
83
84 /* Start by clearing the buffer, as mpz_export only writes as many
85 bytes as it needs (including none, if the value to export is zero. */
c9f0b43f
JB
86 memset (buf.data (), 0, buf.size ());
87 mpz_export (buf.data (), NULL /* count */, -1 /* order */,
88 buf.size () /* size */,
b34c74ab
JB
89 byte_order == BFD_ENDIAN_BIG ? 1 : -1 /* endian */,
90 0 /* nails */, exported_val.val);
91}
92
93/* See gmp-utils.h. */
94
95gdb_mpz
96gdb_mpq::get_rounded () const
97{
98 /* Work with a positive number so as to make the "floor" rounding
99 always round towards zero. */
100
101 gdb_mpq abs_val (val);
102 mpq_abs (abs_val.val, abs_val.val);
103
104 /* Convert our rational number into a quotient and remainder,
105 with "floor" rounding, which in our case means rounding
106 towards zero. */
107
108 gdb_mpz quotient, remainder;
109 mpz_fdiv_qr (quotient.val, remainder.val,
110 mpq_numref (abs_val.val), mpq_denref (abs_val.val));
111
112 /* Multiply the remainder by 2, and see if it is greater or equal
113 to abs_val's denominator. If yes, round to the next integer. */
114
115 mpz_mul_ui (remainder.val, remainder.val, 2);
116 if (mpz_cmp (remainder.val, mpq_denref (abs_val.val)) >= 0)
117 mpz_add_ui (quotient.val, quotient.val, 1);
118
119 /* Re-apply the sign if needed. */
120 if (mpq_sgn (val) < 0)
121 mpz_neg (quotient.val, quotient.val);
122
123 return quotient;
124}
125
126/* See gmp-utils.h. */
127
128void
c9f0b43f 129gdb_mpq::read_fixed_point (gdb::array_view<const gdb_byte> buf,
b34c74ab
JB
130 enum bfd_endian byte_order, bool unsigned_p,
131 const gdb_mpq &scaling_factor)
132{
133 gdb_mpz vz;
c9f0b43f 134 vz.read (buf, byte_order, unsigned_p);
b34c74ab
JB
135
136 mpq_set_z (val, vz.val);
137 mpq_mul (val, val, scaling_factor.val);
138}
139
140/* See gmp-utils.h. */
141
142void
c9f0b43f 143gdb_mpq::write_fixed_point (gdb::array_view<gdb_byte> buf,
b34c74ab
JB
144 enum bfd_endian byte_order, bool unsigned_p,
145 const gdb_mpq &scaling_factor) const
146{
147 gdb_mpq unscaled (val);
148
149 mpq_div (unscaled.val, unscaled.val, scaling_factor.val);
150
151 gdb_mpz unscaled_z = unscaled.get_rounded ();
c9f0b43f 152 unscaled_z.write (buf, byte_order, unsigned_p);
b34c74ab
JB
153}
154
155/* A wrapper around xrealloc that we can then register with GMP
156 as the "realloc" function. */
157
158static void *
159xrealloc_for_gmp (void *ptr, size_t old_size, size_t new_size)
160{
161 return xrealloc (ptr, new_size);
162}
163
164/* A wrapper around xfree that we can then register with GMP
165 as the "free" function. */
166
167static void
168xfree_for_gmp (void *ptr, size_t size)
169{
170 xfree (ptr);
171}
172
173void _initialize_gmp_utils ();
174
175void
176_initialize_gmp_utils ()
177{
178 /* Tell GMP to use GDB's memory management routines. */
179 mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp);
180}
This page took 0.038845 seconds and 4 git commands to generate.