support tan and cot
[fpmath-consensus.git] / impl-libc / impl-libc.c
blobc2434f43295bc7409d850f20aa0b6861f143f5fc
1 #include <errno.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include <unistd.h>
9 /* Whether we're looking at 32-bit or 64-bit floats */
10 typedef enum { P_SINGLE, P_DOUBLE } precision;
12 /* What type of arguments we expect, and what we'll give back. */
13 typedef enum {
14 /* */
15 A_UNKNOWN,
16 A__FLT__FLT,
17 A__FLT_FLT_FLT__FLT,
18 } argtype;
20 /* Types of functions we could call */
21 typedef float (*f__f32__f32)(float);
22 typedef float (*f__f32_f32_f32__f32)(float, float, float);
23 typedef double (*f__f64__f64)(double);
24 typedef double (*f__f64_f64_f64__f64)(double, double, double);
26 /* Wrapper around a function pointer */
27 typedef struct {
28 /* */
29 precision p;
30 argtype a;
32 union {
33 /* */
34 f__f32__f32 f32__f32;
35 f__f32_f32_f32__f32 f32_f32_f32__f32;
36 } f32;
38 union {
39 /* */
40 f__f64__f64 f64__f64;
41 f__f64_f64_f64__f64 f64_f64_f64__f64;
42 } f64;
44 } action;
46 void usage(void)
48 fprintf(stderr,
49 "usage: impl-libc [-s|-d] -f <function_name> -n <num_inputs>\n");
50 _exit(1);
53 float idf(float f)
55 return f;
58 double idd(double d)
60 return d;
63 void determine_function(const char *f, action *a)
65 if (!strcmp(f, "zzzzzz")) {
66 a->a = A_UNKNOWN;
67 } else if (!strcmp(f, "id")) {
68 a->a = A__FLT__FLT;
69 a->f32.f32__f32 = idf;
70 a->f64.f64__f64 = idd;
71 } else if (!strcmp(f, "ceil")) {
72 a->a = A__FLT__FLT;
73 a->f32.f32__f32 = ceilf;
74 a->f64.f64__f64 = ceil;
75 } else if (!strcmp(f, "cos")) {
76 a->a = A__FLT__FLT;
77 a->f32.f32__f32 = cosf;
78 a->f64.f64__f64 = cos;
79 } else if (!strcmp(f, "cot")) {
80 a->a = A_UNKNOWN;
81 } else if (!strcmp(f, "floor")) {
82 a->a = A__FLT__FLT;
83 a->f32.f32__f32 = floorf;
84 a->f64.f64__f64 = floor;
85 } else if (!strcmp(f, "fma")) {
86 a->a = A__FLT_FLT_FLT__FLT;
87 a->f32.f32_f32_f32__f32 = fmaf;
88 a->f64.f64_f64_f64__f64 = fma;
89 } else if (!strcmp(f, "exp")) {
90 a->a = A__FLT__FLT;
91 a->f32.f32__f32 = expf;
92 a->f64.f64__f64 = exp;
93 } else if (!strcmp(f, "expm1")) {
94 a->a = A__FLT__FLT;
95 a->f32.f32__f32 = expm1f;
96 a->f64.f64__f64 = expm1;
97 } else if (!strcmp(f, "log")) {
98 a->a = A__FLT__FLT;
99 a->f32.f32__f32 = logf;
100 a->f64.f64__f64 = log;
101 } else if (!strcmp(f, "log1p")) {
102 a->a = A__FLT__FLT;
103 a->f32.f32__f32 = log1pf;
104 a->f64.f64__f64 = log1p;
105 } else if (!strcmp(f, "powr")) {
106 /* libcs don't seem to have powr (yet?), just pow */
107 a->a = A_UNKNOWN;
108 } else if (!strcmp(f, "sin")) {
109 a->a = A__FLT__FLT;
110 a->f32.f32__f32 = sinf;
111 a->f64.f64__f64 = sin;
112 } else if (!strcmp(f, "sqrt")) {
113 a->a = A__FLT__FLT;
114 a->f32.f32__f32 = sqrtf;
115 a->f64.f64__f64 = sqrt;
116 } else if (!strcmp(f, "tan")) {
117 a->a = A__FLT__FLT;
118 a->f32.f32__f32 = tanf;
119 a->f64.f64__f64 = tan;
120 } else if (!strcmp(f, "trunc")) {
121 a->a = A__FLT__FLT;
122 a->f32.f32__f32 = truncf;
123 a->f64.f64__f64 = trunc;
124 } else {
125 fprintf(stderr, "impl-libc: unknown function \"%s\"\n", f);
126 _exit(1);
130 void read_buf(char *b, ssize_t len)
132 ssize_t r;
133 ssize_t total = 0;
135 while (total < len) {
136 r = read(0, (b + total), (len - total));
138 if (!r) {
139 /* EOF */
140 _exit(0);
141 } else if (r == -1) {
142 perror("impl-libc: read");
143 _exit(1);
144 } else {
145 total += r;
150 void write_buf(const char *b, ssize_t len)
152 ssize_t r;
153 ssize_t total = 0;
155 while (total < len) {
156 r = write(1, (b + total), (len - total));
158 if (r == -1) {
159 perror("impl-libc: write");
160 _exit(1);
161 } else {
162 total += r;
167 size_t input_width(argtype a, precision p)
169 size_t w = (p == P_SINGLE) ? 4 : 8;
171 switch (a) {
172 case A_UNKNOWN:
173 break;
174 case A__FLT__FLT:
176 return 1 * w;
177 case A__FLT_FLT_FLT__FLT:
179 return 3 * w;
182 return (size_t) -1;
185 size_t output_width(argtype a, precision p)
187 size_t w = (p == P_SINGLE) ? 4 : 8;
189 switch (a) {
190 case A_UNKNOWN:
191 break;
192 case A__FLT__FLT:
194 return 1 * w;
195 case A__FLT_FLT_FLT__FLT:
197 return 1 * w;
200 return (size_t) -1;
203 void io_loop(action a, size_t n)
205 char *in_buf = 0;
206 char *out_buf = 0;
207 size_t in_sz = input_width(a.a, a.p);
208 size_t out_sz = output_width(a.a, a.p);
210 if ((in_sz * n) / n != in_sz) {
211 fprintf(stderr, "impl-libc: input length overflow\n");
212 _exit(1);
215 if ((out_sz * n) / n != out_sz) {
216 fprintf(stderr, "impl-libc: output length overflow\n");
217 _exit(1);
220 if (!(in_buf = malloc(in_sz * n))) {
221 perror("impl-libc: malloc");
222 _exit(1);
225 if (!(out_buf = malloc(out_sz * n))) {
226 perror("impl-libc: malloc");
227 _exit(1);
230 while (1) {
231 read_buf(in_buf, in_sz * n);
233 switch (a.a) {
234 case A_UNKNOWN:
235 fprintf(stderr, "impl-libc: impossible\n");
236 _exit(1);
237 break;
238 case A__FLT__FLT:
240 switch (a.p) {
241 case P_SINGLE:
243 for (size_t j = 0; j < n; ++j) {
244 float *x = (float *) (in_buf + (in_sz *
245 j));
246 float *y = (float *) (out_buf +
247 (out_sz * j));
249 *y = a.f32.f32__f32(*x);
252 break;
253 case P_DOUBLE:
255 for (size_t j = 0; j < n; ++j) {
256 double *x = (double *) (in_buf +
257 (in_sz * j));
258 double *y = (double *) (out_buf +
259 (out_sz * j));
261 *y = a.f64.f64__f64(*x);
264 break;
267 break;
268 case A__FLT_FLT_FLT__FLT:
270 switch (a.p) {
271 case P_SINGLE:
273 for (size_t j = 0; j < n; ++j) {
274 float *x1 = (float *) (in_buf + (in_sz *
275 j));
276 float *x2 = (float *) (in_buf + (in_sz *
278 4));
279 float *x3 = (float *) (in_buf + (in_sz *
281 8));
282 float *y = (float *) (out_buf +
283 (out_sz * j));
285 *y = a.f32.f32_f32_f32__f32(*x1, *x2,
286 *x3);
289 break;
290 case P_DOUBLE:
292 for (size_t j = 0; j < n; ++j) {
293 double *x1 = (double *) (in_buf +
294 (in_sz * j));
295 double *x2 = (double *) (in_buf +
296 (in_sz * j) +
298 double *x3 = (double *) (in_buf +
299 (in_sz * j) +
300 16);
301 double *y = (double *) (out_buf +
302 (out_sz * j));
304 *y = a.f64.f64_f64_f64__f64(*x1, *x2,
305 *x3);
308 break;
311 break;
314 write_buf(out_buf, out_sz * n);
318 int main(int argc, char **argv)
320 int c = 0;
321 action a = { .p = P_SINGLE };
322 long long n = 0;
324 while ((c = getopt(argc, argv, "sdf:n:")) != -1) {
325 switch (c) {
326 case 's':
327 a.p = P_SINGLE;
328 break;
329 case 'd':
330 a.p = P_DOUBLE;
331 break;
332 case 'f':
333 determine_function(optarg, &a);
334 break;
335 case 'n':
336 errno = 0;
337 n = strtoll(optarg, 0, 0);
339 if (errno) {
340 perror("impl-libc: unparsable");
342 return 1;
345 break;
346 default:
347 usage();
348 break;
352 if (a.a == A_UNKNOWN) {
353 usage();
356 io_loop(a, n);