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