1 #include "HalideRuntime.h"
2
3 extern "C" {
4
halide_string_to_string(char * dst,char * end,const char * arg)5 WEAK char *halide_string_to_string(char *dst, char *end, const char *arg) {
6 if (dst >= end) return dst;
7 while (1) {
8 if (dst == end) {
9 dst[-1] = 0;
10 return dst;
11 }
12 *dst = *arg;
13 if (*dst == 0) {
14 return dst;
15 }
16 dst++;
17 arg++;
18 }
19 }
20
halide_uint64_to_string(char * dst,char * end,uint64_t arg,int min_digits)21 WEAK char *halide_uint64_to_string(char *dst, char *end, uint64_t arg, int min_digits) {
22 // 32 is more than enough chars to contain any 64-bit int.
23 char buf[32];
24 buf[31] = 0;
25 char *digits = buf + 30;
26
27 for (int i = 0; i < min_digits || arg; i++) {
28 uint64_t top = arg / 10;
29 uint64_t bottom = arg - top * 10;
30 *digits = bottom + '0';
31 digits--;
32 arg = top;
33 }
34 digits++;
35
36 return halide_string_to_string(dst, end, digits);
37 }
38
halide_int64_to_string(char * dst,char * end,int64_t arg,int min_digits)39 WEAK char *halide_int64_to_string(char *dst, char *end, int64_t arg, int min_digits) {
40 if (arg < 0 && dst < end) {
41 *dst++ = '-';
42 arg = -arg;
43 }
44 return halide_uint64_to_string(dst, end, arg, min_digits);
45 }
46
halide_double_to_string(char * dst,char * end,double arg,int scientific)47 WEAK char *halide_double_to_string(char *dst, char *end, double arg, int scientific) {
48 uint64_t bits = 0;
49 memcpy(&bits, &arg, sizeof(double));
50
51 uint64_t one = 1;
52 uint64_t mantissa = bits & ((one << 52) - 1);
53 int biased_exponent = (bits >> 52) & ((1 << 11) - 1);
54 int negative = (bits >> 63);
55
56 // Handle special values
57 if (biased_exponent == 2047) {
58 if (mantissa) {
59 if (negative) {
60 return halide_string_to_string(dst, end, "-nan");
61 } else {
62 return halide_string_to_string(dst, end, "nan");
63 }
64 } else {
65 if (negative) {
66 return halide_string_to_string(dst, end, "-inf");
67 } else {
68 return halide_string_to_string(dst, end, "inf");
69 }
70 }
71 } else if (biased_exponent == 0 && mantissa == 0) {
72 if (scientific) {
73 if (negative) {
74 return halide_string_to_string(dst, end, "-0.000000e+00");
75 } else {
76 return halide_string_to_string(dst, end, "0.000000e+00");
77 }
78 } else {
79 if (negative) {
80 return halide_string_to_string(dst, end, "-0.000000");
81 } else {
82 return halide_string_to_string(dst, end, "0.000000");
83 }
84 }
85 }
86
87 if (negative) {
88 dst = halide_string_to_string(dst, end, "-");
89 arg = -arg;
90 }
91
92 // The desired number of decimal places.
93 const int decimal_places = 6;
94
95 // 10 ^ decimal places
96 const uint64_t scale = 1000000;
97
98 // The number of bits in the mantissa of an IEEE double.
99 const int mantissa_bits = 52;
100
101 if (scientific) {
102
103 // Compute base 10 exponent and normalize the number to within [1, 10)
104 int exponent_base_10 = 0;
105 while (arg < 1) {
106 arg *= 10;
107 exponent_base_10--;
108 }
109
110 while (arg >= 10) {
111 arg /= 10;
112 exponent_base_10++;
113 }
114
115 // Convert to fixed-point;
116 uint64_t fixed = (uint64_t)(arg * scale + 0.5);
117 uint64_t top_digit = fixed / scale;
118 uint64_t other_digits = fixed - top_digit * scale;
119
120 dst = halide_int64_to_string(dst, end, top_digit, 1);
121 dst = halide_string_to_string(dst, end, ".");
122 dst = halide_int64_to_string(dst, end, other_digits, decimal_places);
123
124 if (exponent_base_10 >= 0) {
125 dst = halide_string_to_string(dst, end, "e+");
126 } else {
127 dst = halide_string_to_string(dst, end, "e-");
128 exponent_base_10 = -exponent_base_10;
129 }
130 dst = halide_int64_to_string(dst, end, exponent_base_10, 2);
131
132 } else {
133 // Denormals flush to zero in non-scientific mode. We've
134 // already printed the sign.
135 if (biased_exponent == 0) {
136 return halide_double_to_string(dst, end, 0.0, false);
137 }
138
139 // Express it as an integer times a power of two.
140 uint64_t n = mantissa + (one << mantissa_bits);
141 int exponent = biased_exponent - 1023 - mantissa_bits;
142
143 // Break it into integer and fractional parts.
144 uint64_t integer_part = n;
145 int integer_exponent = exponent;
146
147 uint64_t fractional_part = 0;
148 if (exponent < 0) {
149 // There is a fractional component.
150
151 double f;
152 if (exponent < -mantissa_bits) {
153 // There's no integer component.
154 integer_part = 0;
155 f = n;
156 } else {
157 integer_part >>= (-exponent);
158 f = n - (integer_part << (-exponent));
159 }
160 integer_exponent = 0;
161
162 // Construct 10^decimal_places * 2^exponent exactly
163 // (recall exponent is negative).
164 union {
165 uint64_t bits;
166 double as_double;
167 } multiplier;
168 multiplier.as_double = scale;
169 multiplier.bits += (uint64_t)(exponent) << mantissa_bits;
170
171 // Use it to get the first 6 digits of the fractional part
172 // into the integer part.
173 f = f * multiplier.as_double + 0.5;
174
175 // Round-to-even, to match glibc.
176 fractional_part = (uint64_t)f;
177 if (fractional_part == f &&
178 (fractional_part & 1)) {
179 fractional_part--;
180 }
181
182 // If we rounded the fractional part up to the scale
183 // factor, we'd better reattribute it to the integer part.
184 if (fractional_part == scale) {
185 fractional_part = 0;
186 integer_part++;
187 }
188 }
189
190 // The number is now:
191 // integer_part * 2^integer_exponent + fractional_part * 2^exponent.
192
193 // Convert integer_part to decimal, then repeatedly double it.
194
195 // The largest double is 310 digits long.
196 char buf[512];
197 // Start 32 chars before the end of the scratch buffer and work
198 // backwards to allow space for carried digits.
199 char *int_part_ptr = buf + 512 - 32;
200 char *buf_end = halide_int64_to_string(int_part_ptr, buf + 512, integer_part, 1);
201 for (int i = 0; i < integer_exponent; i++) {
202 // Double each digit, with ripple carry.
203 int carry = 0;
204 for (char *p = buf_end - 1; p != int_part_ptr - 1; p--) {
205 char old_digit = *p - '0';
206 char new_digit = old_digit * 2 + carry;
207 if (new_digit > 9) {
208 new_digit -= 10;
209 carry = 1;
210 } else {
211 carry = 0;
212 }
213 *p = new_digit + '0';
214 }
215 if (carry) {
216 // There was a carry in the last digit. Add a new '1'
217 // at the start.
218 int_part_ptr--;
219 *int_part_ptr = '1';
220 }
221 }
222 dst = halide_string_to_string(dst, end, int_part_ptr);
223 dst = halide_string_to_string(dst, end, ".");
224 dst = halide_int64_to_string(dst, end, fractional_part, decimal_places);
225 }
226
227 return dst;
228 }
229
halide_pointer_to_string(char * dst,char * end,const void * arg)230 WEAK char *halide_pointer_to_string(char *dst, char *end, const void *arg) {
231 const char *hex_digits = "0123456789abcdef";
232 char buf[20] = {0};
233 char *buf_ptr = buf + 18;
234 uint64_t bits = (uint64_t)arg;
235 for (int i = 0; i < 16; i++) {
236 *buf_ptr-- = hex_digits[bits & 15];
237 bits >>= 4;
238 if (!bits) break;
239 }
240 *buf_ptr-- = 'x';
241 *buf_ptr = '0';
242 return halide_string_to_string(dst, end, buf_ptr);
243 }
244
halide_type_to_string(char * dst,char * end,const halide_type_t * t)245 WEAK char *halide_type_to_string(char *dst, char *end, const halide_type_t *t) {
246 const char *code_name = NULL;
247 switch (t->code) {
248 case halide_type_int:
249 code_name = "int";
250 break;
251 case halide_type_uint:
252 code_name = "uint";
253 break;
254 case halide_type_float:
255 code_name = "float";
256 break;
257 case halide_type_handle:
258 code_name = "handle";
259 break;
260 default:
261 code_name = "bad_type_code";
262 break;
263 }
264 dst = halide_string_to_string(dst, end, code_name);
265 dst = halide_uint64_to_string(dst, end, t->bits, 1);
266 if (t->lanes != 1) {
267 dst = halide_string_to_string(dst, end, "x");
268 dst = halide_uint64_to_string(dst, end, t->lanes, 1);
269 }
270 return dst;
271 }
272
halide_buffer_to_string(char * dst,char * end,const halide_buffer_t * buf)273 WEAK char *halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *buf) {
274 if (buf == NULL) {
275 return halide_string_to_string(dst, end, "NULL");
276 }
277 dst = halide_string_to_string(dst, end, "buffer(");
278 dst = halide_uint64_to_string(dst, end, buf->device, 1);
279 dst = halide_string_to_string(dst, end, ", ");
280 dst = halide_pointer_to_string(dst, end, buf->device_interface);
281 dst = halide_string_to_string(dst, end, ", ");
282 dst = halide_pointer_to_string(dst, end, buf->host);
283 dst = halide_string_to_string(dst, end, ", ");
284 dst = halide_uint64_to_string(dst, end, buf->flags, 1);
285 dst = halide_string_to_string(dst, end, ", ");
286 dst = halide_type_to_string(dst, end, &(buf->type));
287 for (int i = 0; i < buf->dimensions; i++) {
288 dst = halide_string_to_string(dst, end, ", {");
289 dst = halide_int64_to_string(dst, end, buf->dim[i].min, 1);
290 dst = halide_string_to_string(dst, end, ", ");
291 dst = halide_int64_to_string(dst, end, buf->dim[i].extent, 1);
292 dst = halide_string_to_string(dst, end, ", ");
293 dst = halide_int64_to_string(dst, end, buf->dim[i].stride, 1);
294 dst = halide_string_to_string(dst, end, "}");
295 }
296 dst = halide_string_to_string(dst, end, ")");
297 return dst;
298 }
299 }
300