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