1 | /* Printing operations with very long integers. |
2 | Copyright (C) 2012-2023 Free Software Foundation, Inc. |
3 | Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it |
8 | under the terms of the GNU General Public License as published by the |
9 | Free Software Foundation; either version 3, or (at your option) any |
10 | later version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT |
13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "pretty-print.h" |
25 | |
26 | /* |
27 | * public printing routines. |
28 | */ |
29 | |
30 | #define BLOCKS_NEEDED(PREC) \ |
31 | (((PREC) + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT) |
32 | |
33 | void |
34 | print_dec (const wide_int_ref &wi, char *buf, signop sgn) |
35 | { |
36 | if (sgn == SIGNED) |
37 | print_decs (wi, buf); |
38 | else |
39 | print_decu (wi, buf); |
40 | } |
41 | |
42 | void |
43 | print_dec (const wide_int_ref &wi, FILE *file, signop sgn) |
44 | { |
45 | if (sgn == SIGNED) |
46 | print_decs (wi, file); |
47 | else |
48 | print_decu (wi, file); |
49 | } |
50 | |
51 | |
52 | /* Try to print the signed self in decimal to BUF. */ |
53 | |
54 | void |
55 | print_decs (const wide_int_ref &wi, char *buf) |
56 | { |
57 | if (wi.get_precision () <= HOST_BITS_PER_WIDE_INT || wi.get_len () == 1) |
58 | { |
59 | if (wi::neg_p (x: wi)) |
60 | sprintf (s: buf, format: "-" HOST_WIDE_INT_PRINT_UNSIGNED, |
61 | -(unsigned HOST_WIDE_INT) wi.to_shwi ()); |
62 | else |
63 | sprintf (s: buf, HOST_WIDE_INT_PRINT_DEC, wi.to_shwi ()); |
64 | } |
65 | else if (wi::neg_p (x: wi)) |
66 | { |
67 | widest2_int w = widest2_int::from (x: wi, sgn: SIGNED); |
68 | *buf = '-'; |
69 | print_decu (wi: -w, buf: buf + 1); |
70 | } |
71 | else |
72 | print_decu (wi, buf); |
73 | } |
74 | |
75 | /* Try to print the signed self in decimal to FILE. */ |
76 | |
77 | void |
78 | print_decs (const wide_int_ref &wi, FILE *file) |
79 | { |
80 | char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p = buf; |
81 | unsigned len; |
82 | if (print_decs_buf_size (wi, len: &len)) |
83 | p = XALLOCAVEC (char, len); |
84 | print_decs (wi, buf: p); |
85 | fputs (s: p, stream: file); |
86 | } |
87 | |
88 | /* Try to print the unsigned self in decimal to BUF. */ |
89 | |
90 | void |
91 | print_decu (const wide_int_ref &wi, char *buf) |
92 | { |
93 | if ((wi.get_precision () <= HOST_BITS_PER_WIDE_INT) |
94 | || (wi.get_len () == 1 && !wi::neg_p (x: wi))) |
95 | sprintf (s: buf, HOST_WIDE_INT_PRINT_UNSIGNED, wi.to_uhwi ()); |
96 | else |
97 | { |
98 | widest2_int w = widest2_int::from (x: wi, sgn: UNSIGNED), r; |
99 | widest2_int ten19 = HOST_WIDE_INT_UC (10000000000000000000); |
100 | char buf2[20], next1[19], next2[19]; |
101 | size_t l, c = 0, i; |
102 | /* In order to avoid dividing this twice, print the 19 decimal |
103 | digit chunks in reverse order into buffer and then reorder |
104 | them in-place. */ |
105 | while (wi::gtu_p (x: w, y: ten19)) |
106 | { |
107 | w = wi::divmod_trunc (x: w, y: ten19, sgn: UNSIGNED, remainder_ptr: &r); |
108 | sprintf (s: buf + c * 19, format: "%019" PRIu64, r.to_uhwi ()); |
109 | ++c; |
110 | } |
111 | l = sprintf (s: buf2, HOST_WIDE_INT_PRINT_UNSIGNED, w.to_uhwi ()); |
112 | buf[c * 19 + l] = '\0'; |
113 | memcpy (dest: next1, src: buf, n: 19); |
114 | memcpy (dest: buf, src: buf2, n: l); |
115 | for (i = 0; i < c / 2; ++i) |
116 | { |
117 | memcpy (dest: next2, src: buf + (c - i - 1) * 19, n: 19); |
118 | memcpy (dest: buf + l + (c - i - 1) * 19, src: next1, n: 19); |
119 | memcpy (dest: next1, src: buf + (i + 1) * 19, n: 19); |
120 | memcpy (dest: buf + l + i * 19, src: next2, n: 19); |
121 | } |
122 | if (c & 1) |
123 | memcpy (dest: buf + l + i * 19, src: next1, n: 19); |
124 | } |
125 | } |
126 | |
127 | /* Try to print the signed self in decimal to FILE. */ |
128 | |
129 | void |
130 | print_decu (const wide_int_ref &wi, FILE *file) |
131 | { |
132 | char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p = buf; |
133 | unsigned len; |
134 | if (print_decu_buf_size (wi, len: &len)) |
135 | p = XALLOCAVEC (char, len); |
136 | print_decu (wi, buf: p); |
137 | fputs (s: p, stream: file); |
138 | } |
139 | |
140 | void |
141 | print_hex (const wide_int_ref &val, char *buf) |
142 | { |
143 | if (val == 0) |
144 | buf += sprintf (s: buf, format: "0x0" ); |
145 | else |
146 | { |
147 | buf += sprintf (s: buf, format: "0x" ); |
148 | int start = ROUND_DOWN (val.get_precision (), HOST_BITS_PER_WIDE_INT); |
149 | int width = val.get_precision () - start; |
150 | bool first_p = true; |
151 | for (int i = start; i >= 0; i -= HOST_BITS_PER_WIDE_INT) |
152 | { |
153 | unsigned HOST_WIDE_INT uhwi = wi::extract_uhwi (x: val, bitpos: i, width); |
154 | if (!first_p) |
155 | buf += sprintf (s: buf, HOST_WIDE_INT_PRINT_PADDED_HEX, uhwi); |
156 | else if (uhwi != 0) |
157 | { |
158 | buf += sprintf (s: buf, HOST_WIDE_INT_PRINT_HEX_PURE, uhwi); |
159 | first_p = false; |
160 | } |
161 | width = HOST_BITS_PER_WIDE_INT; |
162 | } |
163 | } |
164 | } |
165 | |
166 | /* Print one big hex number to FILE. Note that some assemblers may not |
167 | accept this for large modes. */ |
168 | void |
169 | print_hex (const wide_int_ref &wi, FILE *file) |
170 | { |
171 | char buf[WIDE_INT_PRINT_BUFFER_SIZE], *p = buf; |
172 | unsigned len; |
173 | if (print_hex_buf_size (wi, len: &len)) |
174 | p = XALLOCAVEC (char, len); |
175 | print_hex (val: wi, buf: p); |
176 | fputs (s: p, stream: file); |
177 | } |
178 | |
179 | /* Print larger precision wide_int. Not defined as inline in a header |
180 | together with pp_wide_int because XALLOCAVEC will make it uninlinable. */ |
181 | |
182 | void |
183 | pp_wide_int_large (pretty_printer *pp, const wide_int_ref &w, signop sgn) |
184 | { |
185 | unsigned int len; |
186 | print_dec_buf_size (wi: w, sgn, len: &len); |
187 | char *buf = XALLOCAVEC (char, len); |
188 | print_dec (wi: w, buf, sgn); |
189 | pp_string (pp, buf); |
190 | } |
191 | |