]> git.xonotic.org Git - xonotic/gmqcc.git/blob - intrin.c
This is supposted in C99
[xonotic/gmqcc.git] / intrin.c
1 #include <string.h>
2 #include "parser.h"
3
4 /*
5  * Provides all the "intrinsics" / "builtins" for GMQCC. These can do
6  * a few things, they can provide fall back implementations for math
7  * functions if the definitions don't exist for some given engine. Or
8  * then can determine definitions for existing builtins, and simply
9  * wrap back to them instead.  This is like a "portable" intrface that
10  * is entered when -fintrin is used (causing all existing builtins to
11  * be ignored by the compiler and instead interface through here.
12  */
13 #define intrin_ctx(I) parser_ctx((I)->parser)
14
15 static GMQCC_INLINE ast_function *intrin_value(intrin_t *intrin, ast_value **out, const char *name, qcint_t vtype) {
16     ast_value    *value = NULL;
17     ast_function *func  = NULL;
18     char          buffer[1024];
19     char          stype [1024];
20
21     util_snprintf(buffer, sizeof(buffer), "__builtin_%s", name);
22     util_snprintf(stype,  sizeof(stype),   "<%s>",        type_name[vtype]);
23
24     value                    = ast_value_new(intrin_ctx(intrin), buffer, TYPE_FUNCTION);
25     value->intrinsic         = true;
26     value->expression.next   = (ast_expression*)ast_value_new(intrin_ctx(intrin), stype, vtype);
27     func                     = ast_function_new(intrin_ctx(intrin), buffer, value);
28     value->expression.flags |= AST_FLAG_ERASEABLE;
29
30     *out = value;
31     return func;
32 }
33
34 static GMQCC_INLINE void intrin_reg(intrin_t *intrin, ast_value *const value, ast_function *const func) {
35     vec_push(intrin->parser->functions, func);
36     vec_push(intrin->parser->globals,   (ast_expression*)value);
37 }
38
39 #define QC_POW_EPSILON 0.00001f
40
41 /*
42  * since some intrinsics depend on each other there is the possibility
43  * that an intrinsic will fail to get a 'depended' function that a
44  * builtin needs, causing some dependency in the chain to have a NULL
45  * function. This will cause a segmentation fault at code generation,
46  * even though an error was raised. To contiue to allow it (instead
47  * of stopping compilation right away). We need to return from the
48  * parser, before compilation stops after all the collected errors.
49  */
50 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from);
51 static ast_expression *intrin_nullfunc(intrin_t *intrin) {
52     ast_value    *value = NULL;
53     ast_function *func  = intrin_value(intrin, &value, NULL, TYPE_VOID);
54     intrin_reg(intrin, value, func);
55     return (ast_expression*)value;
56 }
57
58 static ast_expression *intrin_isfinite(intrin_t *intrin) {
59     /*
60      * float isfinite(float x) {
61      *     return !(isnan(x) || isinf(x));
62      * }
63      */
64     ast_value    *value     = NULL;
65     ast_value    *x         = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
66     ast_function *func      = intrin_value(intrin, &value, "isfinite", TYPE_FLOAT);
67     ast_call     *callisnan = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isnan", "isfinite"));
68     ast_call     *callisinf = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "isinf", "isfinite"));
69     ast_block    *block     = ast_block_new(intrin_ctx(intrin));
70
71     /* float x; */
72     vec_push(value->expression.params, x);
73
74     /* <callisnan> = isnan(x); */
75     vec_push(callisnan->params, (ast_expression*)x);
76
77     /* <callisinf> = isinf(x); */
78     vec_push(callisinf->params, (ast_expression*)x);
79
80     /* return (!<callisnan> || <callisinf>); */
81     vec_push(block->exprs,
82         (ast_expression*)ast_return_new(
83             intrin_ctx(intrin),
84             (ast_expression*)ast_unary_new(
85                 intrin_ctx(intrin),
86                 INSTR_NOT_F,
87                 (ast_expression*)ast_binary_new(
88                     intrin_ctx(intrin),
89                     INSTR_OR,
90                     (ast_expression*)callisnan,
91                     (ast_expression*)callisinf
92                 )
93             )
94         )
95     );
96
97     vec_push(func->blocks, block);
98     intrin_reg(intrin, value, func);
99
100     return (ast_expression*)value;;
101 }
102
103 static ast_expression *intrin_isinf(intrin_t *intrin) {
104     /*
105      * float isinf(float x) {
106      *     return (x != 0.0) && (x + x == x);
107      * }
108      */
109     ast_value    *value = NULL;
110     ast_value    *x     = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
111     ast_block    *body  = ast_block_new(intrin_ctx(intrin));
112     ast_function *func  = intrin_value(intrin, &value, "isinf", TYPE_FLOAT);
113
114     vec_push(body->exprs,
115         (ast_expression*)ast_return_new(
116             intrin_ctx(intrin),
117             (ast_expression*)ast_binary_new(
118                 intrin_ctx(intrin),
119                 INSTR_AND,
120                 (ast_expression*)ast_binary_new(
121                     intrin_ctx(intrin),
122                     INSTR_NE_F,
123                     (ast_expression*)x,
124                     (ast_expression*)intrin->fold->imm_float[0]
125                 ),
126                 (ast_expression*)ast_binary_new(
127                     intrin_ctx(intrin),
128                     INSTR_EQ_F,
129                     (ast_expression*)ast_binary_new(
130                         intrin_ctx(intrin),
131                         INSTR_ADD_F,
132                         (ast_expression*)x,
133                         (ast_expression*)x
134                     ),
135                     (ast_expression*)x
136                 )
137             )
138         )
139     );
140
141     vec_push(value->expression.params, x);
142     vec_push(func->blocks, body);
143
144     intrin_reg(intrin, value, func);
145
146     return (ast_expression*)value;
147 }
148
149 static ast_expression *intrin_isnan(intrin_t *intrin) {
150     /*
151      * float isnan(float x) {
152      *   float local;
153      *   local = x;
154      *
155      *   return (x != local);
156      * }
157      */
158     ast_value    *value  = NULL;
159     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x",     TYPE_FLOAT);
160     ast_value    *local  = ast_value_new(intrin_ctx(intrin), "local", TYPE_FLOAT);
161     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
162     ast_function *func   = intrin_value(intrin, &value, "isnan", TYPE_FLOAT);
163
164     vec_push(body->locals, local);
165     vec_push(body->exprs,
166         (ast_expression*)ast_store_new(
167             intrin_ctx(intrin),
168             INSTR_STORE_F,
169             (ast_expression*)local,
170             (ast_expression*)arg1
171         )
172     );
173
174     vec_push(body->exprs,
175         (ast_expression*)ast_return_new(
176             intrin_ctx(intrin),
177             (ast_expression*)ast_binary_new(
178                 intrin_ctx(intrin),
179                 INSTR_NE_F,
180                 (ast_expression*)arg1,
181                 (ast_expression*)local
182             )
183         )
184     );
185
186     vec_push(value->expression.params, arg1);
187     vec_push(func->blocks, body);
188
189     intrin_reg(intrin, value, func);
190
191     return (ast_expression*)value;
192 }
193
194 static ast_expression *intrin_isnormal(intrin_t *intrin) {
195     /*
196      * float isnormal(float x) {
197      *     return isfinite(x);
198      * }
199      */
200     ast_value    *value         = NULL;
201     ast_call     *callisfinite  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "isfinite", "isnormal"));
202     ast_value    *x             = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
203     ast_block    *body          = ast_block_new(intrin_ctx(intrin));
204     ast_function *func          = intrin_value(intrin, &value, "isnormal", TYPE_FLOAT);
205
206     vec_push(value->expression.params, x);
207     vec_push(callisfinite->params, (ast_expression*)x);
208
209     /* return <callisfinite> */
210     vec_push(body->exprs,
211         (ast_expression*)ast_return_new(
212             intrin_ctx(intrin),
213             (ast_expression*)callisfinite
214         )
215     );
216
217     vec_push(func->blocks, body);
218     intrin_reg(intrin, value, func);
219     return (ast_expression*)value;
220 }
221
222 static ast_expression *intrin_signbit(intrin_t *intrin) {
223     /*
224      * float signbit(float x) {
225      *     return (x < 0);
226      * }
227      */
228     ast_value    *value  = NULL;
229     ast_value    *x      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
230     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
231     ast_function *func   = intrin_value(intrin, &value, "signbit", TYPE_FLOAT);
232
233     vec_push(value->expression.params, x);
234
235     /* return (x < 0); */
236     vec_push(body->exprs,
237         (ast_expression*)ast_return_new(
238             intrin_ctx(intrin),
239             (ast_expression*)ast_ternary_new(
240                 intrin_ctx(intrin),
241                 (ast_expression*)ast_binary_new(
242                     intrin_ctx(intrin),
243                     INSTR_LT,
244                     (ast_expression*)x,
245                     (ast_expression*)intrin->fold->imm_float[0]
246                 ),
247                 (ast_expression*)intrin->fold->imm_float[1],
248                 (ast_expression*)intrin->fold->imm_float[0]
249             )
250         )
251     );
252
253     vec_push(func->blocks, body);
254     intrin_reg(intrin, value, func);
255     return (ast_expression*)value;
256 }
257
258 static ast_expression *intrin_acosh(intrin_t *intrin) {
259     /*
260      * float acosh(float x) {
261      *     return log(x + sqrt((x * x) - 1));
262      * }
263      */
264     ast_value    *value    = NULL;
265     ast_value    *x        = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
266     ast_call     *calllog  = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "acosh"));
267     ast_call     *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "acosh"));
268     ast_block    *body     = ast_block_new(intrin_ctx(intrin));
269     ast_function *func     = intrin_value(intrin, &value, "acosh", TYPE_FLOAT);
270
271     vec_push(value->expression.params, x);
272
273     /* <callsqrt> = sqrt((x * x) - 1); */
274     vec_push(callsqrt->params,
275         (ast_expression*)ast_binary_new(
276             intrin_ctx(intrin),
277             INSTR_SUB_F,
278             (ast_expression*)ast_binary_new(
279                 intrin_ctx(intrin),
280                 INSTR_MUL_F,
281                 (ast_expression*)x,
282                 (ast_expression*)x
283             ),
284             (ast_expression*)intrin->fold->imm_float[1]
285         )
286     );
287
288     /* <calllog> = log(x + <callsqrt>); */
289     vec_push(calllog->params,
290         (ast_expression*)ast_binary_new(
291             intrin_ctx(intrin),
292             INSTR_ADD_F,
293             (ast_expression*)x,
294             (ast_expression*)callsqrt
295         )
296     );
297
298     /* return <calllog>; */
299     vec_push(body->exprs,
300         (ast_expression*)ast_return_new(
301             intrin_ctx(intrin),
302             (ast_expression*)calllog
303         )
304     );
305
306     vec_push(func->blocks, body);
307     intrin_reg(intrin, value, func);
308     return (ast_expression*)value;
309 }
310
311 static ast_expression *intrin_asinh(intrin_t *intrin) {
312     /*
313      * float asinh(float x) {
314      *     return log(x + sqrt((x * x) + 1));
315      * }
316      */
317     ast_value    *value    = NULL;
318     ast_value    *x        = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
319     ast_call     *calllog  = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "asinh"));
320     ast_call     *callsqrt = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "asinh"));
321     ast_block    *body     = ast_block_new(intrin_ctx(intrin));
322     ast_function *func     = intrin_value(intrin, &value, "asinh", TYPE_FLOAT);
323
324     vec_push(value->expression.params, x);
325
326     /* <callsqrt> = sqrt((x * x) + 1); */
327     vec_push(callsqrt->params,
328         (ast_expression*)ast_binary_new(
329             intrin_ctx(intrin),
330             INSTR_ADD_F,
331             (ast_expression*)ast_binary_new(
332                 intrin_ctx(intrin),
333                 INSTR_MUL_F,
334                 (ast_expression*)x,
335                 (ast_expression*)x
336             ),
337             (ast_expression*)intrin->fold->imm_float[1]
338         )
339     );
340
341     /* <calllog> = log(x + <callsqrt>); */
342     vec_push(calllog->params,
343         (ast_expression*)ast_binary_new(
344             intrin_ctx(intrin),
345             INSTR_ADD_F,
346             (ast_expression*)x,
347             (ast_expression*)callsqrt
348         )
349     );
350
351     /* return <calllog>; */
352     vec_push(body->exprs,
353         (ast_expression*)ast_return_new(
354             intrin_ctx(intrin),
355             (ast_expression*)calllog
356         )
357     );
358
359     vec_push(func->blocks, body);
360     intrin_reg(intrin, value, func);
361     return (ast_expression*)value;
362 }
363
364 static ast_expression *intrin_atanh(intrin_t *intrin) {
365     /*
366      * float atanh(float x) {
367      *     return 0.5 * log((1 + x) / (1 - x))
368      * }
369      */
370     ast_value    *value   = NULL;
371     ast_value    *x       = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
372     ast_call     *calllog = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "log", "atanh"));
373     ast_block    *body    = ast_block_new(intrin_ctx(intrin));
374     ast_function *func    = intrin_value(intrin, &value, "atanh", TYPE_FLOAT);
375
376     vec_push(value->expression.params, x);
377
378     /* <callog> = log((1 + x) / (1 - x)); */
379     vec_push(calllog->params,
380         (ast_expression*)ast_binary_new(
381             intrin_ctx(intrin),
382             INSTR_DIV_F,
383             (ast_expression*)ast_binary_new(
384                 intrin_ctx(intrin),
385                 INSTR_ADD_F,
386                 (ast_expression*)intrin->fold->imm_float[1],
387                 (ast_expression*)x
388             ),
389             (ast_expression*)ast_binary_new(
390                 intrin_ctx(intrin),
391                 INSTR_SUB_F,
392                 (ast_expression*)intrin->fold->imm_float[1],
393                 (ast_expression*)x
394             )
395         )
396     );
397
398     /* return 0.5 * <calllog>; */
399     vec_push(body->exprs,
400         (ast_expression*)ast_binary_new(
401             intrin_ctx(intrin),
402             INSTR_MUL_F,
403             (ast_expression*)fold_constgen_float(intrin->fold, 0.5, false),
404             (ast_expression*)calllog
405         )
406     );
407
408     vec_push(func->blocks, body);
409     intrin_reg(intrin, value, func);
410     return (ast_expression*)value;
411 }
412
413 static ast_expression *intrin_exp(intrin_t *intrin) {
414     /*
415      * float exp(float x) {
416      *     float sum = 1.0;
417      *     float acc = 1.0;
418      *     float i;
419      *     for (i = 1; i < 200; ++i)
420      *         sum += (acc *= x / i);
421      *
422      *     return sum;
423      * }
424      */
425     ast_value    *value = NULL;
426     ast_value    *x     = ast_value_new(intrin_ctx(intrin), "x",   TYPE_FLOAT);
427     ast_value    *sum   = ast_value_new(intrin_ctx(intrin), "sum", TYPE_FLOAT);
428     ast_value    *acc   = ast_value_new(intrin_ctx(intrin), "acc", TYPE_FLOAT);
429     ast_value    *i     = ast_value_new(intrin_ctx(intrin), "i",   TYPE_FLOAT);
430     ast_block    *body  = ast_block_new(intrin_ctx(intrin));
431     ast_function *func  = intrin_value(intrin, &value, "exp", TYPE_FLOAT);
432
433     vec_push(value->expression.params, x);
434     vec_push(body->locals, sum);
435     vec_push(body->locals, acc);
436     vec_push(body->locals, i);
437
438     /* sum = 1.0; */
439     vec_push(body->exprs,
440         (ast_expression*)ast_store_new(
441             intrin_ctx(intrin),
442             INSTR_STORE_F,
443             (ast_expression*)sum,
444             (ast_expression*)intrin->fold->imm_float[1]
445         )
446     );
447
448     /* acc = 1.0; */
449     vec_push(body->exprs,
450         (ast_expression*)ast_store_new(
451             intrin_ctx(intrin),
452             INSTR_STORE_F,
453             (ast_expression*)acc,
454             (ast_expression*)intrin->fold->imm_float[1]
455         )
456     );
457
458     /*
459      * for (i = 1; i < 200; ++i)
460      *     sum += (acc *= x / i);
461      */
462     vec_push(body->exprs,
463         (ast_expression*)ast_loop_new(
464             intrin_ctx(intrin),
465             /* i = 1; */
466             (ast_expression*)ast_store_new(
467                 intrin_ctx(intrin),
468                 INSTR_STORE_F,
469                 (ast_expression*)i,
470                 (ast_expression*)intrin->fold->imm_float[1]
471             ),
472             /* i < 200; */
473             (ast_expression*)ast_binary_new(
474                 intrin_ctx(intrin),
475                 INSTR_LT,
476                 (ast_expression*)i,
477                 (ast_expression*)fold_constgen_float(intrin->fold, 200.0f, false)
478             ),
479             false,
480             NULL,
481             false,
482             /* ++i; */
483             (ast_expression*)ast_binstore_new(
484                 intrin_ctx(intrin),
485                 INSTR_STORE_F,
486                 INSTR_ADD_F,
487                 (ast_expression*)i,
488                 (ast_expression*)intrin->fold->imm_float[1]
489             ),
490             /* sum += (acc *= (x / i)) */
491             (ast_expression*)ast_binstore_new(
492                 intrin_ctx(intrin),
493                 INSTR_STORE_F,
494                 INSTR_ADD_F,
495                 (ast_expression*)sum,
496                 (ast_expression*)ast_binstore_new(
497                     intrin_ctx(intrin),
498                     INSTR_STORE_F,
499                     INSTR_MUL_F,
500                     (ast_expression*)acc,
501                     (ast_expression*)ast_binary_new(
502                         intrin_ctx(intrin),
503                         INSTR_DIV_F,
504                         (ast_expression*)x,
505                         (ast_expression*)i
506                     )
507                 )
508             )
509         )
510     );
511
512     /* return sum; */
513     vec_push(body->exprs,
514         (ast_expression*)ast_return_new(
515             intrin_ctx(intrin),
516             (ast_expression*)sum
517         )
518     );
519
520     vec_push(func->blocks, body);
521
522     intrin_reg(intrin, value, func);
523     return (ast_expression*)value;
524 }
525
526 static ast_expression *intrin_exp2(intrin_t *intrin) {
527     /*
528      * float exp2(float x) {
529      *     return pow(2, x);
530      * }
531      */
532     ast_value    *value     = NULL;
533     ast_call     *callpow   = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", "exp2"));
534     ast_value    *arg1      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
535     ast_block    *body      = ast_block_new(intrin_ctx(intrin));
536     ast_function *func      = intrin_value(intrin, &value, "exp2", TYPE_FLOAT);
537
538     vec_push(value->expression.params, arg1);
539
540     vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
541     vec_push(callpow->params, (ast_expression*)arg1);
542
543     /* return <callpow> */
544     vec_push(body->exprs,
545         (ast_expression*)ast_return_new(
546             intrin_ctx(intrin),
547             (ast_expression*)callpow
548         )
549     );
550
551     vec_push(func->blocks, body);
552
553     intrin_reg(intrin, value, func);
554     return (ast_expression*)value;
555 }
556
557 static ast_expression *intrin_expm1(intrin_t *intrin) {
558     /*
559      * float expm1(float x) {
560      *     return exp(x) - 1;
561      * }
562      */
563     ast_value    *value    = NULL;
564     ast_call     *callexp  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "exp", "expm1"));
565     ast_value    *x        = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
566     ast_block    *body     = ast_block_new(intrin_ctx(intrin));
567     ast_function *func     = intrin_value(intrin, &value, "expm1", TYPE_FLOAT);
568
569     vec_push(value->expression.params, x);
570
571     /* <callexp> = exp(x); */
572     vec_push(callexp->params, (ast_expression*)x);
573
574     /* return <callexp> - 1; */
575     vec_push(body->exprs,
576         (ast_expression*)ast_return_new(
577             intrin_ctx(intrin),
578             (ast_expression*)ast_binary_new(
579                 intrin_ctx(intrin),
580                 INSTR_SUB_F,
581                 (ast_expression*)callexp,
582                 (ast_expression*)intrin->fold->imm_float[1]
583             )
584         )
585     );
586
587     vec_push(func->blocks, body);
588     intrin_reg(intrin, value, func);
589     return (ast_expression*)value;
590 }
591
592 static ast_expression *intrin_pow(intrin_t *intrin) {
593     /*
594      *
595      * float pow(float base, float exp) {
596      *     float result;
597      *     float low;
598      *     float high;
599      *     float mid;
600      *     float square;
601      *     float accumulate;
602      *
603      *     if (exp == 0.0)
604      *         return 1;
605      *     if (exp == 1.0)
606      *         return base;
607      *     if (exp < 0)
608      *         return 1.0 / pow(base, -exp);
609      *     if (exp >= 1) {
610      *         result = pow(base, exp / 2);
611      *         return result * result;
612      *     }
613      *
614      *     low        = 0.0f;
615      *     high       = 1.0f;
616      *     square     = sqrt(base);
617      *     accumulate = square;
618      *     mid        = high / 2.0f
619      *
620      *     while (fabs(mid - exp) > QC_POW_EPSILON) {
621      *         square = sqrt(square);
622      *         if (mid < exp) {
623      *             low         = mid;
624      *             accumulate *= square;
625      *         } else {
626      *             high        = mid;
627      *             accumulate *= (1.0f / square);
628      *         }
629      *         mid = (low + high) / 2;
630      *     }
631      *     return accumulate;
632      * }
633      */
634     ast_value    *value = NULL;
635     ast_function *func = intrin_value(intrin, &value, "pow", TYPE_FLOAT);
636
637     /* prepare some calls for later */
638     ast_call *callpow1  = ast_call_new(intrin_ctx(intrin), (ast_expression*)value);                  /* for pow(base, -exp)    */
639     ast_call *callpow2  = ast_call_new(intrin_ctx(intrin), (ast_expression*)value);                  /* for pow(vase, exp / 2) */
640     ast_call *callsqrt1 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(base)         */
641     ast_call *callsqrt2 = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "sqrt", "pow")); /* for sqrt(square)       */
642     ast_call *callfabs  = ast_call_new(intrin_ctx(intrin), intrin_func_self(intrin, "fabs", "pow")); /* for fabs(mid - exp)    */
643
644     /* prepare some blocks for later */
645     ast_block *expgt1       = ast_block_new(intrin_ctx(intrin));
646     ast_block *midltexp     = ast_block_new(intrin_ctx(intrin));
647     ast_block *midltexpelse = ast_block_new(intrin_ctx(intrin));
648     ast_block *whileblock   = ast_block_new(intrin_ctx(intrin));
649
650     /* float pow(float base, float exp) */
651     ast_value    *base = ast_value_new(intrin_ctx(intrin), "base", TYPE_FLOAT);
652     ast_value    *exp  = ast_value_new(intrin_ctx(intrin), "exp",  TYPE_FLOAT);
653     /* { */
654     ast_block    *body = ast_block_new(intrin_ctx(intrin));
655
656     /*
657      * float result;
658      * float low;
659      * float high;
660      * float square;
661      * float accumulate;
662      * float mid;
663      */
664     ast_value *result     = ast_value_new(intrin_ctx(intrin), "result",     TYPE_FLOAT);
665     ast_value *low        = ast_value_new(intrin_ctx(intrin), "low",        TYPE_FLOAT);
666     ast_value *high       = ast_value_new(intrin_ctx(intrin), "high",       TYPE_FLOAT);
667     ast_value *square     = ast_value_new(intrin_ctx(intrin), "square",     TYPE_FLOAT);
668     ast_value *accumulate = ast_value_new(intrin_ctx(intrin), "accumulate", TYPE_FLOAT);
669     ast_value *mid        = ast_value_new(intrin_ctx(intrin), "mid",        TYPE_FLOAT);
670     vec_push(body->locals, result);
671     vec_push(body->locals, low);
672     vec_push(body->locals, high);
673     vec_push(body->locals, square);
674     vec_push(body->locals, accumulate);
675     vec_push(body->locals, mid);
676
677     vec_push(value->expression.params, base);
678     vec_push(value->expression.params, exp);
679
680     /*
681      * if (exp == 0.0)
682      *     return 1;
683      */
684     vec_push(body->exprs,
685         (ast_expression*)ast_ifthen_new(
686             intrin_ctx(intrin),
687             (ast_expression*)ast_binary_new(
688                 intrin_ctx(intrin),
689                 INSTR_EQ_F,
690                 (ast_expression*)exp,
691                 (ast_expression*)intrin->fold->imm_float[0]
692             ),
693             (ast_expression*)ast_return_new(
694                 intrin_ctx(intrin),
695                 (ast_expression*)intrin->fold->imm_float[1]
696             ),
697             NULL
698         )
699     );
700
701     /*
702      * if (exp == 1.0)
703      *     return base;
704      */
705     vec_push(body->exprs,
706         (ast_expression*)ast_ifthen_new(
707             intrin_ctx(intrin),
708             (ast_expression*)ast_binary_new(
709                 intrin_ctx(intrin),
710                 INSTR_EQ_F,
711                 (ast_expression*)exp,
712                 (ast_expression*)intrin->fold->imm_float[1]
713             ),
714             (ast_expression*)ast_return_new(
715                 intrin_ctx(intrin),
716                 (ast_expression*)base
717             ),
718             NULL
719         )
720     );
721
722     /* <callpow1> = pow(base, -exp) */
723     vec_push(callpow1->params, (ast_expression*)base);
724     vec_push(callpow1->params,
725         (ast_expression*)ast_unary_new(
726             intrin_ctx(intrin),
727             VINSTR_NEG_F,
728             (ast_expression*)exp
729         )
730     );
731
732     /*
733      * if (exp < 0)
734      *     return 1.0 / <callpow1>;
735      */
736     vec_push(body->exprs,
737         (ast_expression*)ast_ifthen_new(
738             intrin_ctx(intrin),
739             (ast_expression*)ast_binary_new(
740                 intrin_ctx(intrin),
741                 INSTR_LT,
742                 (ast_expression*)exp,
743                 (ast_expression*)intrin->fold->imm_float[0]
744             ),
745             (ast_expression*)ast_return_new(
746                 intrin_ctx(intrin),
747                 (ast_expression*)ast_binary_new(
748                     intrin_ctx(intrin),
749                     INSTR_DIV_F,
750                     (ast_expression*)intrin->fold->imm_float[1],
751                     (ast_expression*)callpow1
752                 )
753             ),
754             NULL
755         )
756     );
757
758     /* <callpow2> = pow(base, exp / 2) */
759     vec_push(callpow2->params, (ast_expression*)base);
760     vec_push(callpow2->params,
761         (ast_expression*)ast_binary_new(
762             intrin_ctx(intrin),
763             INSTR_DIV_F,
764             (ast_expression*)exp,
765             (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
766         )
767     );
768
769     /*
770      * <expgt1> = {
771      *     result = <callpow2>;
772      *     return result * result;
773      * }
774      */
775     vec_push(expgt1->exprs,
776         (ast_expression*)ast_store_new(
777             intrin_ctx(intrin),
778             INSTR_STORE_F,
779             (ast_expression*)result,
780             (ast_expression*)callpow2
781         )
782     );
783     vec_push(expgt1->exprs,
784         (ast_expression*)ast_return_new(
785             intrin_ctx(intrin),
786             (ast_expression*)ast_binary_new(
787                 intrin_ctx(intrin),
788                 INSTR_MUL_F,
789                 (ast_expression*)result,
790                 (ast_expression*)result
791             )
792         )
793     );
794
795     /*
796      * if (exp >= 1) {
797      *     <expgt1>
798      * }
799      */
800     vec_push(body->exprs,
801         (ast_expression*)ast_ifthen_new(
802             intrin_ctx(intrin),
803             (ast_expression*)ast_binary_new(
804                 intrin_ctx(intrin),
805                 INSTR_GE,
806                 (ast_expression*)exp,
807                 (ast_expression*)intrin->fold->imm_float[1]
808             ),
809             (ast_expression*)expgt1,
810             NULL
811         )
812     );
813
814     /*
815      * <callsqrt1> = sqrt(base)
816      */
817     vec_push(callsqrt1->params, (ast_expression*)base);
818
819     /*
820      * low        = 0.0f;
821      * high       = 1.0f;
822      * square     = sqrt(base);
823      * accumulate = square;
824      * mid        = high / 2.0f;
825      */
826     vec_push(body->exprs,
827         (ast_expression*)ast_store_new(intrin_ctx(intrin),
828             INSTR_STORE_F,
829             (ast_expression*)low,
830             (ast_expression*)intrin->fold->imm_float[0]
831         )
832     );
833     vec_push(body->exprs,
834         (ast_expression*)ast_store_new(
835             intrin_ctx(intrin),
836             INSTR_STORE_F,
837             (ast_expression*)high,
838             (ast_expression*)intrin->fold->imm_float[1]
839         )
840     );
841
842     vec_push(body->exprs,
843         (ast_expression*)ast_store_new(
844             intrin_ctx(intrin),
845             INSTR_STORE_F,
846             (ast_expression*)square,
847             (ast_expression*)callsqrt1
848         )
849     );
850
851     vec_push(body->exprs,
852         (ast_expression*)ast_store_new(
853             intrin_ctx(intrin),
854             INSTR_STORE_F,
855             (ast_expression*)accumulate,
856             (ast_expression*)square
857         )
858     );
859     vec_push(body->exprs,
860         (ast_expression*)ast_store_new(
861             intrin_ctx(intrin),
862             INSTR_STORE_F,
863             (ast_expression*)mid,
864             (ast_expression*)ast_binary_new(
865                 intrin_ctx(intrin),
866                 INSTR_DIV_F,
867                 (ast_expression*)high,
868                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
869             )
870         )
871     );
872
873     /*
874      * <midltexp> = {
875      *     low         = mid;
876      *     accumulate *= square;
877      * }
878      */
879     vec_push(midltexp->exprs,
880         (ast_expression*)ast_store_new(
881             intrin_ctx(intrin),
882             INSTR_STORE_F,
883             (ast_expression*)low,
884             (ast_expression*)mid
885         )
886     );
887     vec_push(midltexp->exprs,
888         (ast_expression*)ast_binstore_new(
889             intrin_ctx(intrin),
890             INSTR_STORE_F,
891             INSTR_MUL_F,
892             (ast_expression*)accumulate,
893             (ast_expression*)square
894         )
895     );
896
897     /*
898      * <midltexpelse> = {
899      *     high        = mid;
900      *     accumulate *= (1.0 / square);
901      * }
902      */
903     vec_push(midltexpelse->exprs,
904         (ast_expression*)ast_store_new(
905             intrin_ctx(intrin),
906             INSTR_STORE_F,
907             (ast_expression*)high,
908             (ast_expression*)mid
909         )
910     );
911     vec_push(midltexpelse->exprs,
912         (ast_expression*)ast_binstore_new(
913             intrin_ctx(intrin),
914             INSTR_STORE_F,
915             INSTR_MUL_F,
916             (ast_expression*)accumulate,
917             (ast_expression*)ast_binary_new(
918                 intrin_ctx(intrin),
919                 INSTR_DIV_F,
920                 (ast_expression*)intrin->fold->imm_float[1],
921                 (ast_expression*)square
922             )
923         )
924     );
925
926     /*
927      * <callsqrt2> = sqrt(square)
928      */
929     vec_push(callsqrt2->params, (ast_expression*)square);
930
931     /*
932      * <whileblock> = {
933      *     square = <callsqrt2>;
934      *     if (mid < exp)
935      *          <midltexp>;
936      *     else
937      *          <midltexpelse>;
938      *
939      *     mid = (low + high) / 2;
940      * }
941      */
942     vec_push(whileblock->exprs,
943         (ast_expression*)ast_store_new(
944             intrin_ctx(intrin),
945             INSTR_STORE_F,
946             (ast_expression*)square,
947             (ast_expression*)callsqrt2
948         )
949     );
950     vec_push(whileblock->exprs,
951         (ast_expression*)ast_ifthen_new(
952             intrin_ctx(intrin),
953             (ast_expression*)ast_binary_new(
954                 intrin_ctx(intrin),
955                 INSTR_LT,
956                 (ast_expression*)mid,
957                 (ast_expression*)exp
958             ),
959             (ast_expression*)midltexp,
960             (ast_expression*)midltexpelse
961         )
962     );
963     vec_push(whileblock->exprs,
964         (ast_expression*)ast_store_new(
965             intrin_ctx(intrin),
966             INSTR_STORE_F,
967             (ast_expression*)mid,
968             (ast_expression*)ast_binary_new(
969                 intrin_ctx(intrin),
970                 INSTR_DIV_F,
971                 (ast_expression*)ast_binary_new(
972                     intrin_ctx(intrin),
973                     INSTR_ADD_F,
974                     (ast_expression*)low,
975                     (ast_expression*)high
976                 ),
977                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
978             )
979         )
980     );
981
982     /*
983      * <callabs> = fabs(mid - exp)
984      */
985     vec_push(callfabs->params,
986         (ast_expression*)ast_binary_new(
987             intrin_ctx(intrin),
988             INSTR_SUB_F,
989             (ast_expression*)mid,
990             (ast_expression*)exp
991         )
992     );
993
994     /*
995      * while (<callfabs>  > epsilon)
996      *     <whileblock>
997      */
998     vec_push(body->exprs,
999         (ast_expression*)ast_loop_new(
1000             intrin_ctx(intrin),
1001             /* init */
1002             NULL,
1003             /* pre condition */
1004             (ast_expression*)ast_binary_new(
1005                 intrin_ctx(intrin),
1006                 INSTR_GT,
1007                 (ast_expression*)callfabs,
1008                 (ast_expression*)fold_constgen_float(intrin->fold, QC_POW_EPSILON, false)
1009             ),
1010             /* pre not */
1011             false,
1012             /* post condition */
1013             NULL,
1014             /* post not */
1015             false,
1016             /* increment expression */
1017             NULL,
1018             /* code block */
1019             (ast_expression*)whileblock
1020         )
1021     );
1022
1023     /* return accumulate */
1024     vec_push(body->exprs,
1025         (ast_expression*)ast_return_new(
1026             intrin_ctx(intrin),
1027             (ast_expression*)accumulate
1028         )
1029     );
1030
1031     /* } */
1032     vec_push(func->blocks, body);
1033
1034     intrin_reg(intrin, value, func);
1035     return (ast_expression*)value;
1036 }
1037
1038 static ast_expression *intrin_mod(intrin_t *intrin) {
1039     /*
1040      * float mod(float a, float b) {
1041      *     float div = a / b;
1042      *     float sign = (div < 0.0f) ? -1 : 1;
1043      *     return a - b * sign * floor(sign * div);
1044      * }
1045      */
1046     ast_value    *value = NULL;
1047     ast_call     *call  = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", "mod"));
1048     ast_value    *a     = ast_value_new(intrin_ctx(intrin), "a",    TYPE_FLOAT);
1049     ast_value    *b     = ast_value_new(intrin_ctx(intrin), "b",    TYPE_FLOAT);
1050     ast_value    *div   = ast_value_new(intrin_ctx(intrin), "div",  TYPE_FLOAT);
1051     ast_value    *sign  = ast_value_new(intrin_ctx(intrin), "sign", TYPE_FLOAT);
1052     ast_block    *body  = ast_block_new(intrin_ctx(intrin));
1053     ast_function *func  = intrin_value(intrin, &value, "mod", TYPE_FLOAT);
1054
1055     vec_push(value->expression.params, a);
1056     vec_push(value->expression.params, b);
1057
1058     vec_push(body->locals, div);
1059     vec_push(body->locals, sign);
1060
1061     /* div = a / b; */
1062     vec_push(body->exprs,
1063         (ast_expression*)ast_store_new(
1064             intrin_ctx(intrin),
1065             INSTR_STORE_F,
1066             (ast_expression*)div,
1067             (ast_expression*)ast_binary_new(
1068                 intrin_ctx(intrin),
1069                 INSTR_DIV_F,
1070                 (ast_expression*)a,
1071                 (ast_expression*)b
1072             )
1073         )
1074     );
1075
1076     /* sign = (div < 0.0f) ? -1 : 1; */
1077     vec_push(body->exprs,
1078         (ast_expression*)ast_store_new(
1079             intrin_ctx(intrin),
1080             INSTR_STORE_F,
1081             (ast_expression*)sign,
1082             (ast_expression*)ast_ternary_new(
1083                 intrin_ctx(intrin),
1084                 (ast_expression*)ast_binary_new(
1085                     intrin_ctx(intrin),
1086                     INSTR_LT,
1087                     (ast_expression*)div,
1088                     (ast_expression*)intrin->fold->imm_float[0]
1089                 ),
1090                 (ast_expression*)intrin->fold->imm_float[2],
1091                 (ast_expression*)intrin->fold->imm_float[1]
1092             )
1093         )
1094     );
1095
1096     /* floor(sign * div) */
1097     vec_push(call->params,
1098         (ast_expression*)ast_binary_new(
1099             intrin_ctx(intrin),
1100             INSTR_MUL_F,
1101             (ast_expression*)sign,
1102             (ast_expression*)div
1103         )
1104     );
1105
1106     /* return a - b * sign * <call> */
1107     vec_push(body->exprs,
1108         (ast_expression*)ast_return_new(
1109             intrin_ctx(intrin),
1110             (ast_expression*)ast_binary_new(
1111                 intrin_ctx(intrin),
1112                 INSTR_SUB_F,
1113                 (ast_expression*)a,
1114                 (ast_expression*)ast_binary_new(
1115                     intrin_ctx(intrin),
1116                     INSTR_MUL_F,
1117                     (ast_expression*)b,
1118                     (ast_expression*)ast_binary_new(
1119                         intrin_ctx(intrin),
1120                         INSTR_MUL_F,
1121                         (ast_expression*)sign,
1122                         (ast_expression*)call
1123                     )
1124                 )
1125             )
1126         )
1127     );
1128
1129     vec_push(func->blocks, body);
1130     intrin_reg(intrin, value, func);
1131
1132     return (ast_expression*)value;
1133 }
1134
1135 static ast_expression *intrin_fabs(intrin_t *intrin) {
1136     /*
1137      * float fabs(float x) {
1138      *     return x < 0 ? -x : x;
1139      * }
1140      */
1141     ast_value    *value  = NULL;
1142     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1143     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1144     ast_function *func   = intrin_value(intrin, &value, "fabs", TYPE_FLOAT);
1145
1146     vec_push(body->exprs,
1147         (ast_expression*)ast_return_new(
1148             intrin_ctx(intrin),
1149             (ast_expression*)ast_ternary_new(
1150                 intrin_ctx(intrin),
1151                 (ast_expression*)ast_binary_new(
1152                     intrin_ctx(intrin),
1153                     INSTR_LE,
1154                     (ast_expression*)arg1,
1155                     (ast_expression*)intrin->fold->imm_float[0]
1156                 ),
1157                 (ast_expression*)ast_unary_new(
1158                     intrin_ctx(intrin),
1159                     VINSTR_NEG_F,
1160                     (ast_expression*)arg1
1161                 ),
1162                 (ast_expression*)arg1
1163             )
1164         )
1165     );
1166
1167     vec_push(value->expression.params, arg1);
1168     vec_push(func->blocks, body);
1169
1170     intrin_reg(intrin, value, func);
1171
1172     return (ast_expression*)value;
1173 }
1174
1175 static ast_expression *intrin_epsilon(intrin_t *intrin) {
1176     /*
1177      * float epsilon(void) {
1178      *     float eps = 1.0f;
1179      *     do { eps /= 2.0f; } while ((1.0f + (eps / 2.0f)) != 1.0f);
1180      *     return eps;
1181      * }
1182      */
1183     ast_value    *value  = NULL;
1184     ast_value    *eps    = ast_value_new(intrin_ctx(intrin), "eps", TYPE_FLOAT);
1185     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1186     ast_function *func   = intrin_value(intrin, &value, "epsilon", TYPE_FLOAT);
1187
1188     vec_push(body->locals, eps);
1189
1190     /* eps = 1.0f; */
1191     vec_push(body->exprs,
1192         (ast_expression*)ast_store_new(
1193             intrin_ctx(intrin),
1194             INSTR_STORE_F,
1195             (ast_expression*)eps,
1196             (ast_expression*)intrin->fold->imm_float[0]
1197         )
1198     );
1199
1200     vec_push(body->exprs,
1201         (ast_expression*)ast_loop_new(
1202             intrin_ctx(intrin),
1203             NULL,
1204             NULL,
1205             false,
1206             (ast_expression*)ast_binary_new(
1207                 intrin_ctx(intrin),
1208                 INSTR_NE_F,
1209                 (ast_expression*)ast_binary_new(
1210                     intrin_ctx(intrin),
1211                     INSTR_ADD_F,
1212                     (ast_expression*)intrin->fold->imm_float[1],
1213                     (ast_expression*)ast_binary_new(
1214                         intrin_ctx(intrin),
1215                         INSTR_MUL_F,
1216                         (ast_expression*)eps,
1217                         (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1218                     )
1219                 ),
1220                 (ast_expression*)intrin->fold->imm_float[1]
1221             ),
1222             false,
1223             NULL,
1224             (ast_expression*)ast_binstore_new(
1225                 intrin_ctx(intrin),
1226                 INSTR_STORE_F,
1227                 INSTR_DIV_F,
1228                 (ast_expression*)eps,
1229                 (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1230             )
1231         )
1232     );
1233
1234     /* return eps; */
1235     vec_push(body->exprs,
1236         (ast_expression*)ast_return_new(
1237             intrin_ctx(intrin),
1238             (ast_expression*)eps
1239         )
1240     );
1241
1242     vec_push(func->blocks, body);
1243     intrin_reg(intrin, value, func);
1244
1245     return (ast_expression*)value;
1246 }
1247
1248 static ast_expression *intrin_nan(intrin_t *intrin) {
1249     /*
1250      * float nan(void) {
1251      *     float x = 0.0f;
1252      *     return x / x;
1253      * }
1254      */
1255     ast_value    *value  = NULL;
1256     ast_value    *x      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1257     ast_function *func   = intrin_value(intrin, &value, "nan", TYPE_FLOAT);
1258     ast_block    *block  = ast_block_new(intrin_ctx(intrin));
1259
1260     vec_push(block->locals, x);
1261
1262     vec_push(block->exprs,
1263         (ast_expression*)ast_store_new(
1264             intrin_ctx(intrin),
1265             INSTR_STORE_F,
1266             (ast_expression*)x,
1267             (ast_expression*)intrin->fold->imm_float[0]
1268         )
1269     );
1270
1271     vec_push(block->exprs,
1272         (ast_expression*)ast_return_new(
1273             intrin_ctx(intrin),
1274             (ast_expression*)ast_binary_new(
1275                 intrin_ctx(intrin),
1276                 INSTR_DIV_F,
1277                 (ast_expression*)x,
1278                 (ast_expression*)x
1279             )
1280         )
1281     );
1282
1283     vec_push(func->blocks, block);
1284     intrin_reg(intrin, value, func);
1285
1286     return (ast_expression*)value;
1287 }
1288
1289 static ast_expression *intrin_inf(intrin_t *intrin) {
1290     /*
1291      * float inf(void) {
1292      *     float x = 1.0f;
1293      *     float y = 0.0f;
1294      *     return x / y;
1295      * }
1296      */
1297     ast_value    *value  = NULL;
1298     ast_value    *x      = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1299     ast_value    *y      = ast_value_new(intrin_ctx(intrin), "y", TYPE_FLOAT);
1300     ast_function *func   = intrin_value(intrin, &value, "inf", TYPE_FLOAT);
1301     ast_block    *block  = ast_block_new(intrin_ctx(intrin));
1302     size_t        i;
1303
1304     vec_push(block->locals, x);
1305     vec_push(block->locals, y);
1306
1307     /* to keep code size down */
1308     for (i = 0; i <= 1; i++) {
1309         vec_push(block->exprs,
1310             (ast_expression*)ast_store_new(
1311                 intrin_ctx(intrin),
1312                 INSTR_STORE_F,
1313                 (ast_expression*)((i == 0) ? x : y),
1314                 (ast_expression*)intrin->fold->imm_float[i]
1315             )
1316         );
1317     }
1318
1319     vec_push(block->exprs,
1320         (ast_expression*)ast_return_new(
1321             intrin_ctx(intrin),
1322             (ast_expression*)ast_binary_new(
1323                 intrin_ctx(intrin),
1324                 INSTR_DIV_F,
1325                 (ast_expression*)x,
1326                 (ast_expression*)y
1327             )
1328         )
1329     );
1330
1331     vec_push(func->blocks, block);
1332     intrin_reg(intrin, value, func);
1333
1334     return (ast_expression*)value;
1335 }
1336
1337 static ast_expression *intrin_ln(intrin_t *intrin) {
1338     /*
1339      * float log(float power, float base) {
1340      *   float whole;
1341      *   float nth
1342      *   float sign = 1.0f;
1343      *   float eps  = epsilon();
1344      *
1345      *   if (power <= 1.0f || bbase <= 1.0) {
1346      *       if (power <= 0.0f || base <= 0.0f)
1347      *           return nan();
1348      *
1349      *       if (power < 1.0f) {
1350      *           power = 1.0f / power;
1351      *           sign *= -1.0f;
1352      *       }
1353      *
1354      *       if (base < 1.0f) {
1355      *           sign *= -1.0f;
1356      *           base  = 1.0f / base;
1357      *       }
1358      *   }
1359      *
1360      *   float A_i       = 1;
1361      *   float B_i       = 0;
1362      *   float A_iminus1 = 0;
1363      *   float B_iminus1 = 1;
1364      *
1365      *   for (;;) {
1366      *       whole = power;
1367      *       nth   = 0.0f;
1368      *
1369      *       while (whole >= base) {
1370      *           float base2    = base;
1371      *           float n2       = 1.0f;
1372      *           float newbase2 = base2 * base2;
1373      *
1374      *           while (whole >= newbase2) {
1375      *               base2     = newbase2;
1376      *               n2       *= 2;
1377      *               newbase2 *= newbase2;
1378      *           }
1379      *
1380      *           whole /= base2;
1381      *           nth += n2;
1382      *       }
1383      *
1384      *       float b_iplus1 = n;
1385      *       float A_iplus1 = b_iplus1 * A_i + A_iminus1;
1386      *       float B_iplus1 = b_iplus1 * B_i + B_iminus1;
1387      *
1388      *       A_iminus1 = A_i;
1389      *       B_iminus1 = B_i;
1390      *       A_i       = A_iplus1;
1391      *       B_i       = B_iplus1;
1392      *
1393      *       if (whole <= 1.0f + eps)
1394      *           break;
1395      *
1396      *       power = base;
1397      *       bower = whole;
1398      *   }
1399      *   return sign * A_i / B_i;
1400      * }
1401      */
1402
1403     ast_value    *value      = NULL;
1404     ast_value    *power      = ast_value_new(intrin_ctx(intrin), "power",     TYPE_FLOAT);
1405     ast_value    *base       = ast_value_new(intrin_ctx(intrin), "base",      TYPE_FLOAT);
1406     ast_value    *whole      = ast_value_new(intrin_ctx(intrin), "whole",     TYPE_FLOAT);
1407     ast_value    *nth        = ast_value_new(intrin_ctx(intrin), "nth",       TYPE_FLOAT);
1408     ast_value    *sign       = ast_value_new(intrin_ctx(intrin), "sign",      TYPE_FLOAT);
1409     ast_value    *A_i        = ast_value_new(intrin_ctx(intrin), "A_i",       TYPE_FLOAT);
1410     ast_value    *B_i        = ast_value_new(intrin_ctx(intrin), "B_i",       TYPE_FLOAT);
1411     ast_value    *A_iminus1  = ast_value_new(intrin_ctx(intrin), "A_iminus1", TYPE_FLOAT);
1412     ast_value    *B_iminus1  = ast_value_new(intrin_ctx(intrin), "B_iminus1", TYPE_FLOAT);
1413     ast_value    *b_iplus1   = ast_value_new(intrin_ctx(intrin), "b_iplus1",  TYPE_FLOAT);
1414     ast_value    *A_iplus1   = ast_value_new(intrin_ctx(intrin), "A_iplus1",  TYPE_FLOAT);
1415     ast_value    *B_iplus1   = ast_value_new(intrin_ctx(intrin), "B_iplus1",  TYPE_FLOAT);
1416     ast_value    *eps        = ast_value_new(intrin_ctx(intrin), "eps",       TYPE_FLOAT);
1417     ast_value    *base2      = ast_value_new(intrin_ctx(intrin), "base2",     TYPE_FLOAT);
1418     ast_value    *n2         = ast_value_new(intrin_ctx(intrin), "n2",        TYPE_FLOAT);
1419     ast_value    *newbase2   = ast_value_new(intrin_ctx(intrin), "newbase2",  TYPE_FLOAT);
1420     ast_block    *block      = ast_block_new(intrin_ctx(intrin));
1421     ast_block    *plt1orblt1 = ast_block_new(intrin_ctx(intrin)); /* (power <= 1.0f || base <= 1.0f) */
1422     ast_block    *plt1       = ast_block_new(intrin_ctx(intrin)); /* (power < 1.0f) */
1423     ast_block    *blt1       = ast_block_new(intrin_ctx(intrin)); /* (base  < 1.0f) */
1424     ast_block    *forloop    = ast_block_new(intrin_ctx(intrin)); /* for(;;) */
1425     ast_block    *whileloop  = ast_block_new(intrin_ctx(intrin)); /* while (whole >= base) */
1426     ast_block    *nestwhile  = ast_block_new(intrin_ctx(intrin)); /* while (whole >= newbase2) */
1427     ast_function *func       = intrin_value(intrin, &value, "ln", TYPE_FLOAT);
1428     size_t        i;
1429
1430     vec_push(value->expression.params, power);
1431     vec_push(value->expression.params, base);
1432
1433     vec_push(block->locals, whole);
1434     vec_push(block->locals, nth);
1435     vec_push(block->locals, sign);
1436     vec_push(block->locals, eps);
1437     vec_push(block->locals, A_i);
1438     vec_push(block->locals, B_i);
1439     vec_push(block->locals, A_iminus1);
1440     vec_push(block->locals, B_iminus1);
1441
1442     /* sign = 1.0f; */
1443     vec_push(block->exprs,
1444         (ast_expression*)ast_store_new(
1445             intrin_ctx(intrin),
1446             INSTR_STORE_F,
1447             (ast_expression*)sign,
1448             (ast_expression*)intrin->fold->imm_float[1]
1449         )
1450     );
1451
1452     /* eps = __builtin_epsilon(); */
1453     vec_push(block->exprs,
1454         (ast_expression*)ast_store_new(
1455             intrin_ctx(intrin),
1456             INSTR_STORE_F,
1457             (ast_expression*)eps,
1458             (ast_expression*)ast_call_new(
1459                 intrin_ctx(intrin),
1460                 intrin_func_self(intrin, "__builtin_epsilon", "ln")
1461             )
1462         )
1463     );
1464
1465     /*
1466      * A_i       = 1;
1467      * B_i       = 0;
1468      * A_iminus1 = 0;
1469      * B_iminus1 = 1;
1470      */
1471     for (i = 0; i <= 1; i++) {
1472         int j;
1473         for (j = 1; j >= 0; j--) {
1474             vec_push(block->exprs,
1475                 (ast_expression*)ast_store_new(
1476                     intrin_ctx(intrin),
1477                     INSTR_STORE_F,
1478                     (ast_expression*)((j) ? ((i) ? B_iminus1 : A_i)
1479                                           : ((i) ? A_iminus1 : B_i)),
1480                     (ast_expression*)intrin->fold->imm_float[j]
1481                 )
1482             );
1483         }
1484     }
1485
1486     /*
1487      * <plt1> = {
1488      *     power = 1.0f / power;
1489      *     sign *= -1.0f;
1490      * }
1491      * <blt1> = {
1492      *     base  = 1.0f / base;
1493      *     sign *= -1.0f;
1494      * }
1495      */
1496     for (i = 0; i <= 1; i++) {
1497         vec_push(((i) ? blt1 : plt1)->exprs,
1498             (ast_expression*)ast_store_new(
1499                 intrin_ctx(intrin),
1500                 INSTR_STORE_F,
1501                 (ast_expression*)((i) ? base : power),
1502                 (ast_expression*)ast_binary_new(
1503                     intrin_ctx(intrin),
1504                     INSTR_DIV_F,
1505                     (ast_expression*)intrin->fold->imm_float[1],
1506                     (ast_expression*)((i) ? base : power)
1507                 )
1508             )
1509         );
1510         vec_push(plt1->exprs,
1511             (ast_expression*)ast_binstore_new(
1512                 intrin_ctx(intrin),
1513                 INSTR_STORE_F,
1514                 INSTR_MUL_F,
1515                 (ast_expression*)sign,
1516                 (ast_expression*)intrin->fold->imm_float[2]
1517             )
1518         );
1519     }
1520
1521     /*
1522      * <plt1orblt1> = {
1523      *     if (power <= 0.0 || base <= 0.0f)
1524      *         return __builtin_nan();
1525      *     if (power < 1.0f)
1526      *         <plt1>
1527      *     if (base < 1.0f)
1528      *         <blt1>
1529      * }
1530      */
1531     vec_push(plt1orblt1->exprs,
1532         (ast_expression*)ast_ifthen_new(
1533             intrin_ctx(intrin),
1534             (ast_expression*)ast_binary_new(
1535                 intrin_ctx(intrin),
1536                 INSTR_OR,
1537                 (ast_expression*)ast_binary_new(
1538                     intrin_ctx(intrin),
1539                     INSTR_LE,
1540                     (ast_expression*)power,
1541                     (ast_expression*)intrin->fold->imm_float[0]
1542                 ),
1543                 (ast_expression*)ast_binary_new(
1544                     intrin_ctx(intrin),
1545                     INSTR_LE,
1546                     (ast_expression*)base,
1547                     (ast_expression*)intrin->fold->imm_float[0]
1548                 )
1549             ),
1550             (ast_expression*)ast_return_new(
1551                 intrin_ctx(intrin),
1552                 (ast_expression*)ast_call_new(
1553                     intrin_ctx(intrin),
1554                     intrin_func_self(intrin, "__builtin_nan", "ln")
1555                 )
1556             ),
1557             NULL
1558         )
1559     );
1560
1561     for (i = 0; i <= 1; i++) {
1562         vec_push(plt1orblt1->exprs,
1563             (ast_expression*)ast_ifthen_new(
1564                 intrin_ctx(intrin),
1565                 (ast_expression*)ast_binary_new(
1566                     intrin_ctx(intrin),
1567                     INSTR_LT,
1568                     (ast_expression*)((i) ? base : power),
1569                     (ast_expression*)intrin->fold->imm_float[1]
1570                 ),
1571                 (ast_expression*)((i) ? blt1 : plt1),
1572                 NULL
1573             )
1574         );
1575     }
1576
1577     vec_push(block->exprs, (ast_expression*)plt1orblt1);
1578
1579
1580     /* whole = power; */
1581     vec_push(forloop->exprs,
1582         (ast_expression*)ast_store_new(
1583             intrin_ctx(intrin),
1584             INSTR_STORE_F,
1585             (ast_expression*)whole,
1586             (ast_expression*)power
1587         )
1588     );
1589
1590     /* nth = 0.0f; */
1591     vec_push(forloop->exprs,
1592         (ast_expression*)ast_store_new(
1593             intrin_ctx(intrin),
1594             INSTR_STORE_F,
1595             (ast_expression*)nth,
1596             (ast_expression*)intrin->fold->imm_float[0]
1597         )
1598     );
1599
1600     /* base2 = base; */
1601     vec_push(whileloop->exprs,
1602         (ast_expression*)ast_store_new(
1603             intrin_ctx(intrin),
1604             INSTR_STORE_F,
1605             (ast_expression*)base2,
1606             (ast_expression*)base
1607         )
1608     );
1609
1610     /* n2 = 1.0f; */
1611     vec_push(whileloop->exprs,
1612         (ast_expression*)ast_store_new(
1613             intrin_ctx(intrin),
1614             INSTR_STORE_F,
1615             (ast_expression*)n2,
1616             (ast_expression*)intrin->fold->imm_float[1]
1617         )
1618     );
1619
1620     /* newbase2 = base2 * base2; */
1621     vec_push(whileloop->exprs,
1622         (ast_expression*)ast_store_new(
1623             intrin_ctx(intrin),
1624             INSTR_STORE_F,
1625             (ast_expression*)newbase2,
1626             (ast_expression*)ast_binary_new(
1627                 intrin_ctx(intrin),
1628                 INSTR_MUL_F,
1629                 (ast_expression*)base2,
1630                 (ast_expression*)base2
1631             )
1632         )
1633     );
1634
1635     /* while loop locals */
1636     vec_push(whileloop->locals, base2);
1637     vec_push(whileloop->locals, n2);
1638     vec_push(whileloop->locals, newbase2);
1639
1640     /* base2 = newbase2; */
1641     vec_push(nestwhile->exprs,
1642         (ast_expression*)ast_store_new(
1643             intrin_ctx(intrin),
1644             INSTR_STORE_F,
1645             (ast_expression*)base2,
1646             (ast_expression*)newbase2
1647         )
1648     );
1649
1650     /* n2 *= 2; */
1651     vec_push(nestwhile->exprs,
1652         (ast_expression*)ast_binstore_new(
1653             intrin_ctx(intrin),
1654             INSTR_STORE_F,
1655             INSTR_MUL_F,
1656             (ast_expression*)n2,
1657             (ast_expression*)intrin->fold->imm_float[3] /* 2.0f */
1658         )
1659     );
1660
1661     /* newbase2 *= newbase2; */
1662     vec_push(nestwhile->exprs,
1663         (ast_expression*)ast_binstore_new(
1664             intrin_ctx(intrin),
1665             INSTR_STORE_F,
1666             INSTR_MUL_F,
1667             (ast_expression*)newbase2,
1668             (ast_expression*)newbase2
1669         )
1670     );
1671
1672     /* while (whole >= newbase2) */
1673     vec_push(whileloop->exprs,
1674         (ast_expression*)ast_loop_new(
1675             intrin_ctx(intrin),
1676             NULL,
1677             (ast_expression*)ast_binary_new(
1678                 intrin_ctx(intrin),
1679                 INSTR_GE,
1680                 (ast_expression*)whole,
1681                 (ast_expression*)newbase2
1682             ),
1683             false,
1684             NULL,
1685             false,
1686             NULL,
1687             (ast_expression*)nestwhile
1688         )
1689     );
1690
1691     /* whole /= base2; */
1692     vec_push(whileloop->exprs,
1693         (ast_expression*)ast_binstore_new(
1694             intrin_ctx(intrin),
1695             INSTR_STORE_F,
1696             INSTR_DIV_F,
1697             (ast_expression*)whole,
1698             (ast_expression*)base2
1699         )
1700     );
1701
1702     /* nth += n2; */
1703     vec_push(whileloop->exprs,
1704         (ast_expression*)ast_binstore_new(
1705             intrin_ctx(intrin),
1706             INSTR_STORE_F,
1707             INSTR_ADD_F,
1708             (ast_expression*)nth,
1709             (ast_expression*)n2
1710         )
1711     );
1712
1713     /* while (whole >= base) */
1714     vec_push(forloop->exprs,
1715         (ast_expression*)ast_loop_new(
1716             intrin_ctx(intrin),
1717             NULL,
1718             (ast_expression*)ast_binary_new(
1719                 intrin_ctx(intrin),
1720                 INSTR_GE,
1721                 (ast_expression*)whole,
1722                 (ast_expression*)base
1723             ),
1724             false,
1725             NULL,
1726             false,
1727             NULL,
1728             (ast_expression*)whileloop
1729         )
1730     );
1731
1732     vec_push(forloop->locals, b_iplus1);
1733     vec_push(forloop->locals, A_iplus1);
1734     vec_push(forloop->locals, B_iplus1);
1735
1736     /* b_iplus1 = nth; */
1737     vec_push(forloop->exprs,
1738         (ast_expression*)ast_store_new(
1739             intrin_ctx(intrin),
1740             INSTR_STORE_F,
1741             (ast_expression*)b_iplus1,
1742             (ast_expression*)nth
1743         )
1744     );
1745
1746     /*
1747      * A_iplus1 = b_iplus1 * A_i + A_iminus1;
1748      * B_iplus1 = b_iplus1 * B_i + B_iminus1;
1749      */
1750     for (i = 0; i <= 1; i++) {
1751         vec_push(forloop->exprs,
1752             (ast_expression*)ast_store_new(
1753                 intrin_ctx(intrin),
1754                 INSTR_STORE_F,
1755                 (ast_expression*)((i) ? B_iplus1 : A_iplus1),
1756                 (ast_expression*)ast_binary_new(
1757                     intrin_ctx(intrin),
1758                     INSTR_ADD_F,
1759                     (ast_expression*)ast_binary_new(
1760                         intrin_ctx(intrin),
1761                         INSTR_MUL_F,
1762                         (ast_expression*)b_iplus1,
1763                         (ast_expression*) ((i) ? B_i : A_i)
1764                     ),
1765                     (ast_expression*)((i) ? B_iminus1 : A_iminus1)
1766                 )
1767             )
1768         );
1769     }
1770
1771     /*
1772      * A_iminus1 = A_i;
1773      * B_iminus1 = B_i;
1774      */
1775     for (i = 0; i <= 1; i++) {
1776         vec_push(forloop->exprs,
1777             (ast_expression*)ast_store_new(
1778                 intrin_ctx(intrin),
1779                 INSTR_STORE_F,
1780                 (ast_expression*)((i) ? B_iminus1 : A_iminus1),
1781                 (ast_expression*)((i) ? B_i       : A_i)
1782             )
1783         );
1784     }
1785
1786     /*
1787      * A_i = A_iplus1;
1788      * B_i = B_iplus1;
1789      */
1790     for (i = 0; i <= 1; i++) {
1791         vec_push(forloop->exprs,
1792             (ast_expression*)ast_store_new(
1793                 intrin_ctx(intrin),
1794                 INSTR_STORE_F,
1795                 (ast_expression*)((i) ? B_i      : A_i),
1796                 (ast_expression*)((i) ? B_iplus1 : A_iplus1)
1797             )
1798         );
1799     }
1800
1801     /*
1802      * if (whole <= 1.0f + eps)
1803      *     break;
1804      */
1805     vec_push(forloop->exprs,
1806         (ast_expression*)ast_ifthen_new(
1807             intrin_ctx(intrin),
1808             (ast_expression*)ast_binary_new(
1809                 intrin_ctx(intrin),
1810                 INSTR_LE,
1811                 (ast_expression*)whole,
1812                 (ast_expression*)ast_binary_new(
1813                     intrin_ctx(intrin),
1814                     INSTR_ADD_F,
1815                     (ast_expression*)intrin->fold->imm_float[1],
1816                     (ast_expression*)eps
1817                 )
1818             ),
1819             (ast_expression*)ast_breakcont_new(
1820                 intrin_ctx(intrin),
1821                 false,
1822                 0
1823             ),
1824             NULL
1825         )
1826     );
1827
1828     /*
1829      * power = base;
1830      * base  = whole;
1831      */
1832     for (i = 0; i <= 1; i++) {
1833         vec_push(forloop->exprs,
1834             (ast_expression*)ast_store_new(
1835                 intrin_ctx(intrin),
1836                 INSTR_STORE_F,
1837                 (ast_expression*)((i) ? base  : power),
1838                 (ast_expression*)((i) ? whole : base)
1839             )
1840         );
1841     }
1842
1843     /* add the for loop block */
1844     vec_push(block->exprs,
1845         (ast_expression*)ast_loop_new(
1846             intrin_ctx(intrin),
1847             NULL,
1848             /* for(; 1; ) ?? (can this be NULL too?) */
1849             (ast_expression*)intrin->fold->imm_float[1],
1850             false,
1851             NULL,
1852             false,
1853             NULL,
1854             (ast_expression*)forloop
1855         )
1856     );
1857
1858     /* return sign * A_i / B_il */
1859     vec_push(block->exprs,
1860         (ast_expression*)ast_return_new(
1861             intrin_ctx(intrin),
1862             (ast_expression*)ast_binary_new(
1863                 intrin_ctx(intrin),
1864                 INSTR_MUL_F,
1865                 (ast_expression*)sign,
1866                 (ast_expression*)ast_binary_new(
1867                     intrin_ctx(intrin),
1868                     INSTR_DIV_F,
1869                     (ast_expression*)A_i,
1870                     (ast_expression*)B_i
1871                 )
1872             )
1873         )
1874     );
1875
1876     vec_push(func->blocks, block);
1877     intrin_reg(intrin, value, func);
1878
1879     return (ast_expression*)value;
1880 }
1881
1882 static ast_expression *intrin_log_variant(intrin_t *intrin, const char *name, float base) {
1883     ast_value    *value  = NULL;
1884     ast_call     *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", name));
1885     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT);
1886     ast_block    *body   = ast_block_new(intrin_ctx(intrin));
1887     ast_function *func   = intrin_value(intrin, &value, name, TYPE_FLOAT);
1888
1889     vec_push(value->expression.params, arg1);
1890
1891     vec_push(callln->params, (ast_expression*)arg1);
1892     vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, base, false));
1893
1894     vec_push(body->exprs,
1895         (ast_expression*)ast_return_new(
1896             intrin_ctx(intrin),
1897             (ast_expression*)callln
1898         )
1899     );
1900
1901     vec_push(func->blocks, body);
1902     intrin_reg(intrin, value, func);
1903     return (ast_expression*)value;
1904 }
1905
1906 static ast_expression *intrin_log(intrin_t *intrin) {
1907     return intrin_log_variant(intrin, "log", 2.7182818284590452354);
1908 }
1909 static ast_expression *intrin_log10(intrin_t *intrin) {
1910     return intrin_log_variant(intrin, "log10", 10);
1911 }
1912 static ast_expression *intrin_log2(intrin_t *intrin) {
1913     return intrin_log_variant(intrin, "log2", 2);
1914 }
1915 static ast_expression *intrin_logb(intrin_t *intrin) {
1916     /* FLT_RADIX == 2 for now */
1917     return intrin_log_variant(intrin, "log2", 2);
1918 }
1919
1920 static ast_expression *intrin_shift_variant(intrin_t *intrin, const char *name, size_t instr) {
1921     /*
1922      * float [shift] (float a, float b) {
1923      *   return floor(a [instr] pow(2, b));
1924      */
1925     ast_value    *value     = NULL;
1926     ast_call     *callpow   = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "pow", name));
1927     ast_call     *callfloor = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "floor", name));
1928     ast_value    *a         = ast_value_new(intrin_ctx(intrin), "a", TYPE_FLOAT);
1929     ast_value    *b         = ast_value_new(intrin_ctx(intrin), "b", TYPE_FLOAT);
1930     ast_block    *body      = ast_block_new(intrin_ctx(intrin));
1931     ast_function *func      = intrin_value(intrin, &value, name, TYPE_FLOAT);
1932
1933     vec_push(value->expression.params, a);
1934     vec_push(value->expression.params, b);
1935
1936     /* <callpow> = pow(2, b) */
1937     vec_push(callpow->params, (ast_expression*)intrin->fold->imm_float[3]);
1938     vec_push(callpow->params, (ast_expression*)b);
1939
1940     /* <callfloor> = floor(a [instr] <callpow>) */
1941     vec_push(
1942         callfloor->params,
1943         (ast_expression*)ast_binary_new(
1944             intrin_ctx(intrin),
1945             instr,
1946             (ast_expression*)a,
1947             (ast_expression*)callpow
1948         )
1949     );
1950
1951     /* return <callfloor> */
1952     vec_push(body->exprs,
1953         (ast_expression*)ast_return_new(
1954             intrin_ctx(intrin),
1955             (ast_expression*)callfloor
1956         )
1957     );
1958
1959     vec_push(func->blocks, body);
1960     intrin_reg(intrin, value, func);
1961     return (ast_expression*)value;
1962 }
1963
1964 static ast_expression *intrin_lshift(intrin_t *intrin) {
1965     return intrin_shift_variant(intrin, "lshift", INSTR_MUL_F);
1966 }
1967
1968 static ast_expression *intrin_rshift(intrin_t *intrin) {
1969     return intrin_shift_variant(intrin, "rshift", INSTR_DIV_F);
1970 }
1971
1972 /*
1973  * TODO: make static (and handle ast_type_string) here for the builtin
1974  * instead of in SYA parse close.
1975  */
1976 ast_expression *intrin_debug_typestring(intrin_t *intrin) {
1977     (void)intrin;
1978     return (ast_expression*)0x1;
1979 }
1980
1981 static const intrin_func_t intrinsics[] = {
1982     {&intrin_isfinite,         "__builtin_isfinite",         "isfinite", 1},
1983     {&intrin_isinf,            "__builtin_isinf",            "isinf",    1},
1984     {&intrin_isnan,            "__builtin_isnan",            "isnan",    1},
1985     {&intrin_isnormal,         "__builtin_isnormal",         "isnormal", 1},
1986     {&intrin_signbit,          "__builtin_signbit",          "signbit",  1},
1987     {&intrin_acosh,            "__builtin_acosh",            "acosh",    1},
1988     {&intrin_asinh,            "__builtin_asinh",            "asinh",    1},
1989     {&intrin_atanh,            "__builtin_atanh",            "atanh",    1},
1990     {&intrin_exp,              "__builtin_exp",              "exp",      1},
1991     {&intrin_exp2,             "__builtin_exp2",             "exp2",     1},
1992     {&intrin_expm1,            "__builtin_expm1",            "expm1",    1},
1993     {&intrin_mod,              "__builtin_mod",              "mod",      2},
1994     {&intrin_pow,              "__builtin_pow",              "pow",      2},
1995     {&intrin_fabs,             "__builtin_fabs",             "fabs",     1},
1996     {&intrin_log,              "__builtin_log",              "log",      1},
1997     {&intrin_log10,            "__builtin_log10",            "log10",    1},
1998     {&intrin_log2,             "__builtin_log2",             "log2",     1},
1999     {&intrin_logb,             "__builtin_logb",             "logb",     1},
2000     {&intrin_lshift,           "__builtin_lshift",           "",         2},
2001     {&intrin_rshift,           "__builtin_rshift",           "",         2},
2002     {&intrin_epsilon,          "__builtin_epsilon",          "",         0},
2003     {&intrin_nan,              "__builtin_nan",              "",         0},
2004     {&intrin_inf,              "__builtin_inf",              "",         0},
2005     {&intrin_ln,               "__builtin_ln",               "",         2},
2006     {&intrin_debug_typestring, "__builtin_debug_typestring", "",         0},
2007     {&intrin_nullfunc,         "#nullfunc",                  "",         0}
2008 };
2009
2010 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
2011     va_list ap;
2012     va_start(ap, fmt);
2013     vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
2014     va_end(ap);
2015 }
2016
2017 /* exposed */
2018 intrin_t *intrin_init(parser_t *parser) {
2019     intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
2020     size_t    i;
2021
2022     intrin->parser     = parser;
2023     intrin->fold       = parser->fold;
2024     intrin->intrinsics = NULL;
2025     intrin->generated  = NULL;
2026
2027     vec_append(intrin->intrinsics, GMQCC_ARRAY_COUNT(intrinsics), intrinsics);
2028
2029     /* populate with null pointers for tracking generation */
2030     for (i = 0; i < GMQCC_ARRAY_COUNT(intrinsics); i++)
2031         vec_push(intrin->generated, NULL);
2032
2033     return intrin;
2034 }
2035
2036 void intrin_cleanup(intrin_t *intrin) {
2037     vec_free(intrin->intrinsics);
2038     vec_free(intrin->generated);
2039     mem_d(intrin);
2040 }
2041
2042 ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
2043     size_t i;
2044     if (!value || !value->name)
2045         return NULL;
2046     for (i = 0; i < vec_size(intrin->intrinsics); i++)
2047         if (!strcmp(value->name, intrin->intrinsics[i].name))
2048             return (vec_size(exprs) != intrin->intrinsics[i].args)
2049                         ? NULL
2050                         : fold_intrin(intrin->fold, value->name + 10, exprs);
2051     return NULL;
2052 }
2053
2054 static GMQCC_INLINE ast_expression *intrin_func_try(intrin_t *intrin, size_t offset, const char *compare) {
2055     size_t i;
2056     for (i = 0; i < vec_size(intrin->intrinsics); i++) {
2057         if (strcmp(*(char **)((char *)&intrin->intrinsics[i] + offset), compare))
2058             continue;
2059         if (intrin->generated[i])
2060             return intrin->generated[i];
2061         return intrin->generated[i] = intrin->intrinsics[i].intrin(intrin);
2062     }
2063     return NULL;
2064 }
2065
2066 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
2067     size_t           i;
2068     ast_expression  *find;
2069
2070     /* try current first */
2071     if ((find = parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
2072         for (i = 0; i < vec_size(intrin->parser->functions); ++i)
2073             if (((ast_value*)find)->name && !strcmp(intrin->parser->functions[i]->name, ((ast_value*)find)->name) && intrin->parser->functions[i]->builtin < 0)
2074                 return find;
2075     /* try name second */
2076     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, name),  name)))
2077         return find;
2078     /* try alias third */
2079     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
2080         return find;
2081
2082     if (from) {
2083         intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
2084         return intrin_func_self(intrin, "#nullfunc", NULL);
2085     }
2086     return NULL;
2087 }
2088
2089 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
2090     return intrin_func_self(intrin, name, NULL);
2091 }