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