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