]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - intrin.c
Reorder intrinsics table
[xonotic/gmqcc.git] / intrin.c
1 /*
2  * Copyright (C) 2012, 2013
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),
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)
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)
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 nan(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      *           whole /= base;
1393      *           nth++;
1394      *       }
1395      *
1396      *       float b_iplus1 = n;
1397      *       float A_iplus1 = b_iplus1 * A_i + A_iminus1;
1398      *       float B_iplus1 = b_iplus1 * B_i + B_iminus1;
1399      *
1400      *       A_iminus1 = A_i;
1401      *       B_iminus1 = B_i;
1402      *       A_i       = A_iplus1;
1403      *       B_i       = B_iplus1;
1404      *
1405      *       if (whole <= 1.0f + eps)
1406      *           break;
1407      *
1408      *       power = base;
1409      *       bower = whole;
1410      *   }
1411      *   return sign * A_i / B_i;
1412      * }
1413      */
1414
1415     ast_value    *value      = NULL;
1416     ast_value    *power      = ast_value_new(intrin_ctx(intrin), "power",     TYPE_FLOAT);
1417     ast_value    *base       = ast_value_new(intrin_ctx(intrin), "base",      TYPE_FLOAT);
1418     ast_value    *whole      = ast_value_new(intrin_ctx(intrin), "whole",     TYPE_FLOAT);
1419     ast_value    *nth        = ast_value_new(intrin_ctx(intrin), "nth",       TYPE_FLOAT);
1420     ast_value    *sign       = ast_value_new(intrin_ctx(intrin), "sign",      TYPE_FLOAT);
1421     ast_value    *A_i        = ast_value_new(intrin_ctx(intrin), "A_i",       TYPE_FLOAT);
1422     ast_value    *B_i        = ast_value_new(intrin_ctx(intrin), "B_i",       TYPE_FLOAT);
1423     ast_value    *A_iminus1  = ast_value_new(intrin_ctx(intrin), "A_iminus1", TYPE_FLOAT);
1424     ast_value    *B_iminus1  = ast_value_new(intrin_ctx(intrin), "B_iminus1", TYPE_FLOAT);
1425     ast_value    *b_iplus1   = ast_value_new(intrin_ctx(intrin), "b_iplus1",  TYPE_FLOAT);
1426     ast_value    *A_iplus1   = ast_value_new(intrin_ctx(intrin), "A_iplus1",  TYPE_FLOAT);
1427     ast_value    *B_iplus1   = ast_value_new(intrin_ctx(intrin), "B_iplus1",  TYPE_FLOAT);
1428     ast_value    *eps        = ast_value_new(intrin_ctx(intrin), "eps",       TYPE_FLOAT);
1429     ast_block    *block      = ast_block_new(intrin_ctx(intrin));
1430     ast_block    *plt1orblt1 = ast_block_new(intrin_ctx(intrin)); /* (power <= 1.0f || base <= 1.0f) */
1431     ast_block    *plt1       = ast_block_new(intrin_ctx(intrin)); /* (power < 1.0f) */
1432     ast_block    *blt1       = ast_block_new(intrin_ctx(intrin)); /* (base  < 1.0f) */
1433     ast_block    *forloop    = ast_block_new(intrin_ctx(intrin)); /* for(;;) */
1434     ast_block    *whileloop  = ast_block_new(intrin_ctx(intrin)); /* while (whole >= base) */
1435     ast_function *func       = intrin_value(intrin, &value, "ln", TYPE_FLOAT);
1436     size_t        i;
1437
1438     vec_push(value->expression.params, power);
1439     vec_push(value->expression.params, base);
1440
1441     vec_push(block->locals, whole);
1442     vec_push(block->locals, nth);
1443     vec_push(block->locals, sign);
1444     vec_push(block->locals, eps);
1445     vec_push(block->locals, A_i);
1446     vec_push(block->locals, B_i);
1447     vec_push(block->locals, A_iminus1);
1448     vec_push(block->locals, B_iminus1);
1449
1450     /* sign = 1.0f; */
1451     vec_push(block->exprs,
1452         (ast_expression*)ast_store_new(
1453             intrin_ctx(intrin),
1454             INSTR_STORE_F,
1455             (ast_expression*)sign,
1456             (ast_expression*)intrin->fold->imm_float[1]
1457         )
1458     );
1459
1460     /* eps = __builtin_epsilon(); */
1461     vec_push(block->exprs,
1462         (ast_expression*)ast_store_new(
1463             intrin_ctx(intrin),
1464             INSTR_STORE_F,
1465             (ast_expression*)eps,
1466             (ast_expression*)ast_call_new(
1467                 intrin_ctx(intrin),
1468                 intrin_func_self(intrin, "__builtin_epsilon", "ln")
1469             )
1470         )
1471     );
1472
1473     /*
1474      * A_i       = 1;
1475      * B_i       = 0;
1476      * A_iminus1 = 0;
1477      * B_iminus1 = 1;
1478      */
1479     for (i = 0; i <= 1; i++) {
1480         int j;
1481         for (j = 1; j >= 0; j--) {
1482             vec_push(block->exprs,
1483                 (ast_expression*)ast_store_new(
1484                     intrin_ctx(intrin),
1485                     INSTR_STORE_F,
1486                     (ast_expression*)((j) ? ((i) ? B_iminus1 : A_i)
1487                                           : ((i) ? A_iminus1 : B_i)),
1488                     (ast_expression*)intrin->fold->imm_float[j]
1489                 )
1490             );
1491         }
1492     }
1493
1494     /*
1495      * <plt1> = {
1496      *     power = 1.0f / power;
1497      *     sign *= -1.0f;
1498      * }
1499      * <blt1> = {
1500      *     base  = 1.0f / base;
1501      *     sign *= -1.0f;
1502      * }
1503      */
1504     for (i = 0; i <= 1; i++) {
1505         vec_push(((i) ? blt1 : plt1)->exprs,
1506             (ast_expression*)ast_store_new(
1507                 intrin_ctx(intrin),
1508                 INSTR_STORE_F,
1509                 (ast_expression*)((i) ? base : power),
1510                 (ast_expression*)ast_binary_new(
1511                     intrin_ctx(intrin),
1512                     INSTR_DIV_F,
1513                     (ast_expression*)intrin->fold->imm_float[1],
1514                     (ast_expression*)((i) ? base : power)
1515                 )
1516             )
1517         );
1518         vec_push(plt1->exprs,
1519             (ast_expression*)ast_binstore_new(
1520                 intrin_ctx(intrin),
1521                 INSTR_STORE_F,
1522                 INSTR_MUL_F,
1523                 (ast_expression*)sign,
1524                 (ast_expression*)intrin->fold->imm_float[2]
1525             )
1526         );
1527     }
1528
1529     /*
1530      * <plt1orblt1> = {
1531      *     if (power <= 0.0 || base <= 0.0f)
1532      *         return __builtin_nan();
1533      *     if (power < 1.0f)
1534      *         <plt1>
1535      *     if (base < 1.0f)
1536      *         <blt1>
1537      * }
1538      */
1539     vec_push(plt1orblt1->exprs,
1540         (ast_expression*)ast_ifthen_new(
1541             intrin_ctx(intrin),
1542             (ast_expression*)ast_binary_new(
1543                 intrin_ctx(intrin),
1544                 INSTR_OR,
1545                 (ast_expression*)ast_binary_new(
1546                     intrin_ctx(intrin),
1547                     INSTR_LE,
1548                     (ast_expression*)power,
1549                     (ast_expression*)intrin->fold->imm_float[0]
1550                 ),
1551                 (ast_expression*)ast_binary_new(
1552                     intrin_ctx(intrin),
1553                     INSTR_LE,
1554                     (ast_expression*)base,
1555                     (ast_expression*)intrin->fold->imm_float[0]
1556                 )
1557             ),
1558             (ast_expression*)ast_return_new(
1559                 intrin_ctx(intrin),
1560                 (ast_expression*)ast_call_new(
1561                     intrin_ctx(intrin),
1562                     intrin_func_self(intrin, "__builtin_nan", "ln")
1563                 )
1564             ),
1565             NULL
1566         )
1567     );
1568
1569     for (i = 0; i <= 1; i++) {
1570         vec_push(plt1orblt1->exprs,
1571             (ast_expression*)ast_ifthen_new(
1572                 intrin_ctx(intrin),
1573                 (ast_expression*)ast_binary_new(
1574                     intrin_ctx(intrin),
1575                     INSTR_LT,
1576                     (ast_expression*)((i) ? base : power),
1577                     (ast_expression*)intrin->fold->imm_float[1]
1578                 ),
1579                 (ast_expression*)((i) ? blt1 : plt1),
1580                 NULL
1581             )
1582         );
1583     }
1584
1585     vec_push(block->exprs, (ast_expression*)plt1orblt1);
1586
1587
1588     /* whole = power; */
1589     vec_push(forloop->exprs,
1590         (ast_expression*)ast_store_new(
1591             intrin_ctx(intrin),
1592             INSTR_STORE_F,
1593             (ast_expression*)whole,
1594             (ast_expression*)power
1595         )
1596     );
1597
1598     /* nth = 0.0f; */
1599     vec_push(forloop->exprs,
1600         (ast_expression*)ast_store_new(
1601             intrin_ctx(intrin),
1602             INSTR_STORE_F,
1603             (ast_expression*)nth,
1604             (ast_expression*)intrin->fold->imm_float[0]
1605         )
1606     );
1607
1608     /* whole /= base; */
1609     vec_push(whileloop->exprs,
1610         (ast_expression*)ast_binstore_new(
1611             intrin_ctx(intrin),
1612             INSTR_STORE_F,
1613             INSTR_DIV_F,
1614             (ast_expression*)whole,
1615             (ast_expression*)base
1616         )
1617     );
1618
1619     /* nth ++; */
1620     vec_push(whileloop->exprs,
1621         (ast_expression*)ast_binstore_new(
1622             intrin_ctx(intrin),
1623             INSTR_STORE_F,
1624             INSTR_ADD_F,
1625             (ast_expression*)nth,
1626             (ast_expression*)intrin->fold->imm_float[1]
1627         )
1628     );
1629
1630     /* while (whole >= base) */
1631     vec_push(forloop->exprs,
1632         (ast_expression*)ast_loop_new(
1633             intrin_ctx(intrin),
1634             NULL,
1635             (ast_expression*)ast_binary_new(
1636                 intrin_ctx(intrin),
1637                 INSTR_GE,
1638                 (ast_expression*)whole,
1639                 (ast_expression*)base
1640             ),
1641             false,
1642             NULL,
1643             false,
1644             NULL,
1645             (ast_expression*)whileloop
1646         )
1647     );
1648
1649     vec_push(forloop->locals, b_iplus1);
1650     vec_push(forloop->locals, A_iplus1);
1651     vec_push(forloop->locals, B_iplus1);
1652
1653     /* b_iplus1 = nth; */
1654     vec_push(forloop->exprs,
1655         (ast_expression*)ast_store_new(
1656             intrin_ctx(intrin),
1657             INSTR_STORE_F,
1658             (ast_expression*)b_iplus1,
1659             (ast_expression*)nth
1660         )
1661     );
1662
1663     /*
1664      * A_iplus1 = b_iplus1 * A_i + A_iminus1;
1665      * B_iplus1 = b_iplus1 * B_i + B_iminus1;
1666      */
1667     for (i = 0; i <= 1; i++) {
1668         vec_push(forloop->exprs,
1669             (ast_expression*)ast_store_new(
1670                 intrin_ctx(intrin),
1671                 INSTR_STORE_F,
1672                 (ast_expression*)((i) ? B_iplus1 : A_iplus1),
1673                 (ast_expression*)ast_binary_new(
1674                     intrin_ctx(intrin),
1675                     INSTR_ADD_F,
1676                     (ast_expression*)ast_binary_new(
1677                         intrin_ctx(intrin),
1678                         INSTR_MUL_F,
1679                         (ast_expression*)b_iplus1,
1680                         (ast_expression*) ((i) ? B_i : A_i)
1681                     ),
1682                     (ast_expression*)((i) ? B_iminus1 : A_iminus1)
1683                 )
1684             )
1685         );
1686     }
1687
1688     /*
1689      * A_iminus1 = A_i;
1690      * B_iminus1 = B_i;
1691      */
1692     for (i = 0; i <= 1; i++) {
1693         vec_push(forloop->exprs,
1694             (ast_expression*)ast_store_new(
1695                 intrin_ctx(intrin),
1696                 INSTR_STORE_F,
1697                 (ast_expression*)((i) ? B_iminus1 : A_iminus1),
1698                 (ast_expression*)((i) ? B_i       : A_i)
1699             )
1700         );
1701     }
1702
1703     /*
1704      * A_i = A_iplus1;
1705      * B_i = B_iplus1;
1706      */
1707     for (i = 0; i <= 1; i++) {
1708         vec_push(forloop->exprs,
1709             (ast_expression*)ast_store_new(
1710                 intrin_ctx(intrin),
1711                 INSTR_STORE_F,
1712                 (ast_expression*)((i) ? B_i      : A_i),
1713                 (ast_expression*)((i) ? B_iplus1 : A_iplus1)
1714             )
1715         );
1716     }
1717
1718     /*
1719      * if (whole <= 1.0f + eps)
1720      *     break;
1721      */
1722     vec_push(forloop->exprs,
1723         (ast_expression*)ast_ifthen_new(
1724             intrin_ctx(intrin),
1725             (ast_expression*)ast_binary_new(
1726                 intrin_ctx(intrin),
1727                 INSTR_LE,
1728                 (ast_expression*)whole,
1729                 (ast_expression*)ast_binary_new(
1730                     intrin_ctx(intrin),
1731                     INSTR_ADD_F,
1732                     (ast_expression*)intrin->fold->imm_float[1],
1733                     (ast_expression*)eps
1734                 )
1735             ),
1736             (ast_expression*)ast_breakcont_new(
1737                 intrin_ctx(intrin),
1738                 false,
1739                 0
1740             ),
1741             NULL
1742         )
1743     );
1744
1745     /*
1746      * power = base;
1747      * base  = whole;
1748      */
1749     for (i = 0; i <= 1; i++) {
1750         vec_push(forloop->exprs,
1751             (ast_expression*)ast_store_new(
1752                 intrin_ctx(intrin),
1753                 INSTR_STORE_F,
1754                 (ast_expression*)((i) ? base  : power),
1755                 (ast_expression*)((i) ? whole : base)
1756             )
1757         );
1758     }
1759
1760     /* add the for loop block */
1761     vec_push(block->exprs,
1762         (ast_expression*)ast_loop_new(
1763             intrin_ctx(intrin),
1764             NULL,
1765             /* for(; 1; ) ?? (can this be NULL too?) */
1766             (ast_expression*)intrin->fold->imm_float[1],
1767             false,
1768             NULL,
1769             false,
1770             NULL,
1771             (ast_expression*)forloop
1772         )
1773     );
1774
1775     /* return sign * A_i / B_il */
1776     vec_push(block->exprs,
1777         (ast_expression*)ast_return_new(
1778             intrin_ctx(intrin),
1779             (ast_expression*)ast_binary_new(
1780                 intrin_ctx(intrin),
1781                 INSTR_MUL_F,
1782                 (ast_expression*)sign,
1783                 (ast_expression*)ast_binary_new(
1784                     intrin_ctx(intrin),
1785                     INSTR_DIV_F,
1786                     (ast_expression*)A_i,
1787                     (ast_expression*)B_i
1788                 )
1789             )
1790         )
1791     );
1792
1793     vec_push(func->blocks, block);
1794     intrin_reg(intrin, value, func);
1795
1796     return (ast_expression*)value;
1797 }
1798
1799 #define LOG_VARIANT(NAME, BASE) \
1800 static ast_expression *intrin_##NAME(intrin_t *intrin) { \
1801     ast_value    *value  = NULL; \
1802     ast_call     *callln = ast_call_new (intrin_ctx(intrin), intrin_func_self(intrin, "__builtin_ln", #NAME)); \
1803     ast_value    *arg1   = ast_value_new(intrin_ctx(intrin), "x", TYPE_FLOAT); \
1804     ast_block    *body   = ast_block_new(intrin_ctx(intrin)); \
1805     ast_function *func   = intrin_value(intrin, &value, #NAME, TYPE_FLOAT); \
1806     vec_push(value->expression.params, arg1); \
1807     vec_push(callln->params, (ast_expression*)arg1); \
1808     vec_push(callln->params, (ast_expression*)fold_constgen_float(intrin->fold, BASE)); \
1809     vec_push(body->exprs, \
1810         (ast_expression*)ast_return_new( \
1811             intrin_ctx(intrin), \
1812             (ast_expression*)callln \
1813         ) \
1814     ); \
1815     vec_push(func->blocks, body); \
1816     intrin_reg(intrin, value, func); \
1817     return (ast_expression*)value; \
1818 }
1819 LOG_VARIANT(log, 2.7182818284590452354)
1820 LOG_VARIANT(log10, 10)
1821 LOG_VARIANT(log2, 2)
1822 LOG_VARIANT(logb, 2) /* FLT_RADIX == 2 for now */
1823 #undef LOG_VARIANT
1824
1825 /*
1826  * TODO: make static (and handle ast_type_string) here for the builtin
1827  * instead of in SYA parse close.
1828  */
1829 ast_expression *intrin_debug_typestring(intrin_t *intrin) {
1830     (void)intrin;
1831     return (ast_expression*)0x1;
1832 }
1833
1834 static const intrin_func_t intrinsics[] = {
1835     {&intrin_isfinite,         "__builtin_isfinite",         "isfinite", 1},
1836     {&intrin_isinf,            "__builtin_isinf",            "isinf",    1},
1837     {&intrin_isnan,            "__builtin_isnan",            "isnan",    1},
1838     {&intrin_isnormal,         "__builtin_isnormal",         "isnormal", 1},
1839     {&intrin_signbit,          "__builtin_signbit",          "signbit",  1},
1840     {&intrin_acosh,            "__builtin_acosh",            "acosh",    1},
1841     {&intrin_asinh,            "__builtin_asinh",            "asinh",    1},
1842     {&intrin_atanh,            "__builtin_atanh",            "atanh",    1},
1843     {&intrin_exp,              "__builtin_exp",              "exp",      1},
1844     {&intrin_exp2,             "__builtin_exp2",             "exp2",     1},
1845     {&intrin_expm1,            "__builtin_expm1",            "expm1",    1},
1846     {&intrin_mod,              "__builtin_mod",              "mod",      2},
1847     {&intrin_pow,              "__builtin_pow",              "pow",      2},
1848     {&intrin_fabs,             "__builtin_fabs",             "fabs",     1},
1849     {&intrin_log,              "__builtin_log",              "log",      1},
1850     {&intrin_log10,            "__builtin_log10",            "log10",    1},
1851     {&intrin_log2,             "__builtin_log2",             "log2",     1},
1852     {&intrin_logb,             "__builtin_logb",             "logb",     1},
1853     {&intrin_epsilon,          "__builtin_epsilon",          "",         0},
1854     {&intrin_nan,              "__builtin_nan",              "",         0},
1855     {&intrin_inf,              "__builtin_inf",              "",         0},
1856     {&intrin_ln,               "__builtin_ln",               "",         2},
1857     {&intrin_debug_typestring, "__builtin_debug_typestring", "",         0},
1858     {&intrin_nullfunc,         "#nullfunc",                  "",         0}
1859 };
1860
1861 static void intrin_error(intrin_t *intrin, const char *fmt, ...) {
1862     va_list ap;
1863     va_start(ap, fmt);
1864     vcompile_error(intrin->parser->lex->tok.ctx, fmt, ap);
1865     va_end(ap);
1866 }
1867
1868 /* exposed */
1869 intrin_t *intrin_init(parser_t *parser) {
1870     intrin_t *intrin = (intrin_t*)mem_a(sizeof(intrin_t));
1871     size_t    i;
1872
1873     intrin->parser     = parser;
1874     intrin->fold       = parser->fold;
1875     intrin->intrinsics = NULL;
1876     intrin->generated  = NULL;
1877
1878     vec_append(intrin->intrinsics, GMQCC_ARRAY_COUNT(intrinsics), intrinsics);
1879
1880     /* populate with null pointers for tracking generation */
1881     for (i = 0; i < GMQCC_ARRAY_COUNT(intrinsics); i++)
1882         vec_push(intrin->generated, NULL);
1883
1884     return intrin;
1885 }
1886
1887 void intrin_cleanup(intrin_t *intrin) {
1888     vec_free(intrin->intrinsics);
1889     vec_free(intrin->generated);
1890     mem_d(intrin);
1891 }
1892
1893 ast_expression *intrin_fold(intrin_t *intrin, ast_value *value, ast_expression **exprs) {
1894     size_t i;
1895     if (!value || !value->name)
1896         return NULL;
1897     for (i = 0; i < vec_size(intrin->intrinsics); i++)
1898         if (!strcmp(value->name, intrin->intrinsics[i].name))
1899             return (vec_size(exprs) != intrin->intrinsics[i].args)
1900                         ? NULL
1901                         : fold_intrin(intrin->fold, value->name + 10, exprs);
1902     return NULL;
1903 }
1904
1905 static GMQCC_INLINE ast_expression *intrin_func_try(intrin_t *intrin, size_t offset, const char *compare) {
1906     size_t i;
1907     for (i = 0; i < vec_size(intrin->intrinsics); i++) {
1908         if (strcmp(*(char **)((char *)&intrin->intrinsics[i] + offset), compare))
1909             continue;
1910         if (intrin->generated[i])
1911             return intrin->generated[i];
1912         return intrin->generated[i] = intrin->intrinsics[i].intrin(intrin);
1913     }
1914     return NULL;
1915 }
1916
1917 static ast_expression *intrin_func_self(intrin_t *intrin, const char *name, const char *from) {
1918     size_t           i;
1919     ast_expression  *find;
1920
1921     /* try current first */
1922     if ((find = parser_find_global(intrin->parser, name)) && ((ast_value*)find)->expression.vtype == TYPE_FUNCTION)
1923         for (i = 0; i < vec_size(intrin->parser->functions); ++i)
1924             if (((ast_value*)find)->name && !strcmp(intrin->parser->functions[i]->name, ((ast_value*)find)->name) && intrin->parser->functions[i]->builtin < 0)
1925                 return find;
1926     /* try name second */
1927     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, name),  name)))
1928         return find;
1929     /* try alias third */
1930     if ((find = intrin_func_try(intrin, offsetof(intrin_func_t, alias), name)))
1931         return find;
1932
1933     if (from) {
1934         intrin_error(intrin, "need function `%s', compiler depends on it for `__builtin_%s'", name, from);
1935         return intrin_func_self(intrin, "#nullfunc", NULL);
1936     }
1937     return NULL;
1938 }
1939
1940 ast_expression *intrin_func(intrin_t *intrin, const char *name) {
1941     return intrin_func_self(intrin, name, NULL);
1942 }